1 | """ |
---|
2 | nosetests setuptools command |
---|
3 | ---------------------------- |
---|
4 | |
---|
5 | The easiest way to run tests with nose is to use the `nosetests` setuptools |
---|
6 | command:: |
---|
7 | |
---|
8 | python setup.py nosetests |
---|
9 | |
---|
10 | This command has one *major* benefit over the standard `test` command: *all |
---|
11 | nose plugins are supported*. |
---|
12 | |
---|
13 | To configure the `nosetests` command, add a [nosetests] section to your |
---|
14 | setup.cfg. The [nosetests] section can contain any command line arguments that |
---|
15 | nosetests supports. The differences between issuing an option on the command |
---|
16 | line and adding it to setup.cfg are: |
---|
17 | |
---|
18 | * In setup.cfg, the -- prefix must be excluded |
---|
19 | * In setup.cfg, command line flags that take no arguments must be given an |
---|
20 | argument flag (1, T or TRUE for active, 0, F or FALSE for inactive) |
---|
21 | |
---|
22 | Here's an example [nosetests] setup.cfg section:: |
---|
23 | |
---|
24 | [nosetests] |
---|
25 | verbosity=1 |
---|
26 | detailed-errors=1 |
---|
27 | with-coverage=1 |
---|
28 | cover-package=nose |
---|
29 | debug=nose.loader |
---|
30 | pdb=1 |
---|
31 | pdb-failures=1 |
---|
32 | |
---|
33 | If you commonly run nosetests with a large number of options, using |
---|
34 | the nosetests setuptools command and configuring with setup.cfg can |
---|
35 | make running your tests much less tedious. (Note that the same options |
---|
36 | and format supported in setup.cfg are supported in all other config |
---|
37 | files, and the nosetests script will also load config files.) |
---|
38 | |
---|
39 | Another reason to run tests with the command is that the command will |
---|
40 | install packages listed in your `tests_require`, as well as doing a |
---|
41 | complete build of your package before running tests. For packages with |
---|
42 | dependencies or that build C extensions, using the setuptools command |
---|
43 | can be more convenient than building by hand and running the nosetests |
---|
44 | script. |
---|
45 | |
---|
46 | Bootstrapping |
---|
47 | ------------- |
---|
48 | |
---|
49 | If you are distributing your project and want users to be able to run tests |
---|
50 | without having to install nose themselves, add nose to the setup_requires |
---|
51 | section of your setup():: |
---|
52 | |
---|
53 | setup( |
---|
54 | # ... |
---|
55 | setup_requires=['nose>=0.11'] |
---|
56 | ) |
---|
57 | |
---|
58 | This will direct setuptools to download and activate nose during the setup |
---|
59 | process, making the ``nosetests`` command available. |
---|
60 | |
---|
61 | """ |
---|
62 | try: |
---|
63 | from setuptools import Command |
---|
64 | except ImportError: |
---|
65 | Command = nosetests = None |
---|
66 | else: |
---|
67 | from nose.config import Config, option_blacklist, user_config_files, \ |
---|
68 | flag, _bool |
---|
69 | from nose.core import TestProgram |
---|
70 | from nose.plugins import DefaultPluginManager |
---|
71 | |
---|
72 | |
---|
73 | def get_user_options(parser): |
---|
74 | """convert a optparse option list into a distutils option tuple list""" |
---|
75 | opt_list = [] |
---|
76 | for opt in parser.option_list: |
---|
77 | if opt._long_opts[0][2:] in option_blacklist: |
---|
78 | continue |
---|
79 | long_name = opt._long_opts[0][2:] |
---|
80 | if opt.action not in ('store_true', 'store_false'): |
---|
81 | long_name = long_name + "=" |
---|
82 | short_name = None |
---|
83 | if opt._short_opts: |
---|
84 | short_name = opt._short_opts[0][1:] |
---|
85 | opt_list.append((long_name, short_name, opt.help or "")) |
---|
86 | return opt_list |
---|
87 | |
---|
88 | |
---|
89 | class nosetests(Command): |
---|
90 | description = "Run unit tests using nosetests" |
---|
91 | __config = Config(files=user_config_files(), |
---|
92 | plugins=DefaultPluginManager()) |
---|
93 | __parser = __config.getParser() |
---|
94 | user_options = get_user_options(__parser) |
---|
95 | |
---|
96 | def initialize_options(self): |
---|
97 | """create the member variables, but change hyphens to |
---|
98 | underscores |
---|
99 | """ |
---|
100 | |
---|
101 | self.option_to_cmds = {} |
---|
102 | for opt in self.__parser.option_list: |
---|
103 | cmd_name = opt._long_opts[0][2:] |
---|
104 | option_name = cmd_name.replace('-', '_') |
---|
105 | self.option_to_cmds[option_name] = cmd_name |
---|
106 | setattr(self, option_name, None) |
---|
107 | self.attr = None |
---|
108 | |
---|
109 | def finalize_options(self): |
---|
110 | """nothing to do here""" |
---|
111 | pass |
---|
112 | |
---|
113 | def run(self): |
---|
114 | """ensure tests are capable of being run, then |
---|
115 | run nose.main with a reconstructed argument list""" |
---|
116 | self.run_command('egg_info') |
---|
117 | |
---|
118 | # Build extensions in-place |
---|
119 | self.reinitialize_command('build_ext', inplace=1) |
---|
120 | self.run_command('build_ext') |
---|
121 | |
---|
122 | if self.distribution.install_requires: |
---|
123 | self.distribution.fetch_build_eggs( |
---|
124 | self.distribution.install_requires) |
---|
125 | if self.distribution.tests_require: |
---|
126 | self.distribution.fetch_build_eggs( |
---|
127 | self.distribution.tests_require) |
---|
128 | |
---|
129 | argv = ['nosetests'] |
---|
130 | for (option_name, cmd_name) in self.option_to_cmds.items(): |
---|
131 | if option_name in option_blacklist: |
---|
132 | continue |
---|
133 | value = getattr(self, option_name) |
---|
134 | if value is not None: |
---|
135 | argv.extend( |
---|
136 | self.cfgToArg(option_name.replace('_', '-'), value)) |
---|
137 | TestProgram(argv=argv, config=self.__config) |
---|
138 | |
---|
139 | def cfgToArg(self, optname, value): |
---|
140 | argv = [] |
---|
141 | if flag(value): |
---|
142 | if _bool(value): |
---|
143 | argv.append('--' + optname) |
---|
144 | else: |
---|
145 | argv.extend(['--' + optname, value]) |
---|
146 | return argv |
---|