1

Apparently the answer to my question "Can I restrict nose coverage output to directory (rather than package)?" is no, but I can pass a --coverage-package=PACKAGE option to nose with the package name of each .py file in the directory.

So for example, if the directory contains:

foo.py
bar.py
baz.py

...then I would need to use the command:

nosetests --with-coverage --coverage-package=foo --coverage-package=bar --coverage-package=baz

So my question is, can someone write some shell script code (preferably sh or bash) to take all the filenames in the current directory with a .py extension and generate the above command-line (with the .py extensions removed)? My bash skills are quite limited. (I'm tempted to just do it in Python.)

Community
  • 1
  • 1
Daryl Spitzer
  • 143,156
  • 76
  • 154
  • 173

3 Answers3

13
nosetests --with-coverage $(for f in *.py; do echo --cover-package="${f%.*}"; done)

The trick is here is using parameter substitution to remove the file extension.

${f%.*}
Ayman Hourieh
  • 132,184
  • 23
  • 144
  • 116
  • This solution will fail for all .py files that contain spaces or glob metacharacters. And while it's obviously uncommon for python script filenames to contain such, there's no point in keeping a broken solution alive when you can just as easily do it right (see my answer to the question). – lhunath May 14 '09 at 10:33
  • As for why it fails, any unquoted expansions undergo bash word splitting and bash pathname expansion. As such, foo="A * in the sky.mp3"; rm -f $foo will have disastrous results. Because it's often unpredictable how disastrous the results of this bad practice will be, it's best to just **always** properly quote the separate arguments to your commands. In this case, each --cover-package is a separate argument and should be individually quoted. – lhunath May 14 '09 at 10:35
  • Thanks for the explanation. Quoting "${f%.*}" seems to protect against the problem you are describing. I edited my answer. I tested by creating files called 1.py, 2.py and "3 * 4.pl", and then running rm $(for f in *.pl; do echo "$f"; done). The command deletes the last file only. I prefer to fix my solution as I find a for loop much more readable. – Ayman Hourieh May 14 '09 at 19:21
3

And if you care to do it correct (which means, don't allow wordsplitting to cut your filenames apart or unexpected globbing to expand to random filenames), use an array:

files=(*.py)
packages=("${files[@]/%.py/}")
nosetests --with-coverage "${packages[@]/#/--coverage-package=}"
lhunath
  • 120,288
  • 16
  • 68
  • 77
2
nosetests --with-coverage `ls *.py|sed -e 's/^/--cover-package=' -e 's/\.py$//'`
Daryl Spitzer
  • 143,156
  • 76
  • 154
  • 173
chaos
  • 122,029
  • 33
  • 303
  • 309