I would like to run all my django tests using mercurial's precommit hook. Whenever a test fails the commit will be aborted.
The goal is to block build-breaking commits as often as possible.
edit: Ended up using the external script route. Here is the reletant portion of my hgrc:
[hooks]
precommit = python ./pinax/projects/lgr/manage.py test lgr_photos --verbosity=0 --noinput
commit = hg push
Here is my progress on the hook function:
from os.path import join, dirname
import sys
from django.core.management import call_command
def hook(ui, repo, **kwargs):
project_path = join( dirname(repo.path), 'pinax', 'projects')
sys.path.insert(0, project_path)
from lgr.manage import *
output = call_command('test', verbosity=0, interactive=False)
#ui.warn(output)
What am I doing wrong here?
PS - It's giving a HUGE error traceback, which is included in it's entirety below
jim@ubuntu:~/workspace/lgr$ hg ci -m 'testing hooks'
No username found, using '[email protected]' instead
error: precommit hook raised an exception: '_demandmod' object is not iterable
** unknown exception encountered, details follow
** report bug details to http://mercurial.selenic.com/bts/
** or [email protected]
** Mercurial Distributed SCM (version 1.3.1)
** Extensions loaded:
Traceback (most recent call last):
File "/usr/bin/hg", line 27, in <module>
mercurial.dispatch.run()
File "/usr/lib/pymodules/python2.6/mercurial/dispatch.py", line 16, in run
sys.exit(dispatch(sys.argv[1:]))
File "/usr/lib/pymodules/python2.6/mercurial/dispatch.py", line 27, in dispatch
return _runcatch(u, args)
File "/usr/lib/pymodules/python2.6/mercurial/dispatch.py", line 43, in _runcatch
return _dispatch(ui, args)
File "/usr/lib/pymodules/python2.6/mercurial/dispatch.py", line 449, in _dispatch
return runcommand(lui, repo, cmd, fullargs, ui, options, d)
File "/usr/lib/pymodules/python2.6/mercurial/dispatch.py", line 317, in runcommand
ret = _runcommand(ui, options, cmd, d)
File "/usr/lib/pymodules/python2.6/mercurial/dispatch.py", line 501, in _runcommand
return checkargs()
File "/usr/lib/pymodules/python2.6/mercurial/dispatch.py", line 454, in checkargs
return cmdfunc()
File "/usr/lib/pymodules/python2.6/mercurial/dispatch.py", line 448, in <lambda>
d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
File "/usr/lib/pymodules/python2.6/mercurial/util.py", line 402, in check
return func(*args, **kwargs)
File "/usr/lib/pymodules/python2.6/mercurial/commands.py", line 667, in commit
node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
File "/usr/lib/pymodules/python2.6/mercurial/cmdutil.py", line 1213, in commit
return commitfunc(ui, repo, message, match(repo, pats, opts), opts)
File "/usr/lib/pymodules/python2.6/mercurial/commands.py", line 665, in commitfunc
editor=e, extra=extra)
File "/usr/lib/pymodules/python2.6/mercurial/localrepo.py", line 886, in commit
ret = self.commitctx(cctx, True)
File "/usr/lib/pymodules/python2.6/mercurial/localrepo.py", line 915, in commitctx
self.hook("precommit", throw=True, parent1=xp1, parent2=xp2)
File "/usr/lib/pymodules/python2.6/mercurial/localrepo.py", line 139, in hook
return hook.hook(self.ui, self, name, throw, **args)
File "/usr/lib/pymodules/python2.6/mercurial/hook.py", line 119, in hook
r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
File "/usr/lib/pymodules/python2.6/mercurial/hook.py", line 52, in _pythonhook
r = obj(ui=ui, repo=repo, hooktype=name, **args)
here is the important part:
File "/home/jim/run_lgr_tests.py", line 11, in hook
output = call_command('test', verbosity=0, interactive=False)
and the rest:
File "/usr/local/lib/python2.6/dist-packages/django/core/management/__init__.py", line 166, in call_command
return klass.execute(*args, **defaults)
File "/usr/local/lib/python2.6/dist-packages/django/core/management/base.py", line 213, in execute
translation.activate('en-us')
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/__init__.py", line 73, in activate
return real_activate(language)
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/__init__.py", line 43, in delayed_loader
return g['real_%s' % caller](*args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/trans_real.py", line 205, in activate
_active[currentThread()] = translation(language)
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/trans_real.py", line 194, in translation
default_translation = _fetch(settings.LANGUAGE_CODE)
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/trans_real.py", line 180, in _fetch
app = import_module(appname)
File "/usr/local/lib/python2.6/dist-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
File "/usr/lib/pymodules/python2.6/mercurial/demandimport.py", line 84, in _demandimport
return _origimport(name, globals, locals, fromlist)
File "/home/jim/workspace/lgr/pinax/projects/lgr/apps/lgr_hacks.py", line 5, in <module>
User.email = models.EmailField(_('email address'), blank=True, max_length=200)
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/__init__.py", line 62, in ugettext
return real_ugettext(message)
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/trans_real.py", line 286, in ugettext
return do_translate(message, 'ugettext')
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/trans_real.py", line 276, in do_translate
_default = translation(settings.LANGUAGE_CODE)
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/trans_real.py", line 194, in translation
default_translation = _fetch(settings.LANGUAGE_CODE)
File "/usr/local/lib/python2.6/dist-packages/django/utils/translation/trans_real.py", line 180, in _fetch
app = import_module(appname)
File "/usr/local/lib/python2.6/dist-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
File "/usr/lib/pymodules/python2.6/mercurial/demandimport.py", line 84, in _demandimport
return _origimport(name, globals, locals, fromlist)
File "/home/jim/workspace/lgr/pinax/apps/external_apps/djangodblog/__init__.py", line 1, in <module>
import djangodblog.admin
File "/usr/lib/pymodules/python2.6/mercurial/demandimport.py", line 91, in _demandimport
return _origimport(name, globals, locals, fromlist)
File "/home/jim/workspace/lgr/pinax/apps/external_apps/djangodblog/admin.py", line 14, in <module>
admin.site.register(ErrorBatch, ErrorBatchAdmin)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/admin/sites.py", line 90, in register
validate(admin_class, model)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/admin/validation.py", line 22, in validate
models.get_apps()
File "/usr/local/lib/python2.6/dist-packages/django/db/models/loading.py", line 100, in get_apps
self._populate()
File "/usr/local/lib/python2.6/dist-packages/django/db/models/loading.py", line 58, in _populate
self.load_app(app_name, True)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/loading.py", line 74, in load_app
models = import_module('.models', app_name)
File "/usr/local/lib/python2.6/dist-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
File "/usr/lib/pymodules/python2.6/mercurial/demandimport.py", line 84, in _demandimport
return _origimport(name, globals, locals, fromlist)
File "/home/jim/workspace/lgr/pinax/projects/lgr/apps/account/models.py", line 7, in <module>
from timezones.fields import TimeZoneField
File "/usr/lib/pymodules/python2.6/mercurial/demandimport.py", line 103, in _demandimport
mod = _origimport(name, globals, locals)
File "/home/jim/workspace/lgr/pinax/apps/external_apps/timezones/fields.py", line 12, in <module>
default_tz = pytz.timezone(getattr(settings, "TIME_ZONE", "UTC"))
File "/usr/lib/pymodules/python2.6/mercurial/demandimport.py", line 75, in __getattribute__
self._load()
File "/usr/lib/pymodules/python2.6/mercurial/demandimport.py", line 47, in _load
mod = _origimport(head, globals, locals)
File "/home/jim/workspace/lgr/pinax/libs/external_libs/pytz-2008b/pytz/__init__.py", line 29, in <module>
from pkg_resources import resource_stream
File "/usr/lib/pymodules/python2.6/mercurial/demandimport.py", line 103, in _demandimport
mod = _origimport(name, globals, locals)
File "/usr/lib/python2.6/dist-packages/pkg_resources.py", line 2562, in <module>
working_set.require(__requires__)
File "/usr/lib/python2.6/dist-packages/pkg_resources.py", line 626, in require
needed = self.resolve(parse_requirements(requirements))
File "/usr/lib/python2.6/dist-packages/pkg_resources.py", line 505, in resolve
requirements = list(requirements)[::-1] # set up the stack
File "/usr/lib/python2.6/dist-packages/pkg_resources.py", line 2380, in parse_requirements
for line in lines:
File "/usr/lib/python2.6/dist-packages/pkg_resources.py", line 1814, in yield_lines
for s in yield_lines(ss):
File "/usr/lib/python2.6/dist-packages/pkg_resources.py", line 1813, in yield_lines
for ss in strs:
TypeError: '_demandmod' object is not iterable
If you want to run a test case class which has the path <module_name>/tests/test_views.py , you can run the command python manage.py test <module_name>. tests. test_views.
If you want to manually run all pre-commit hooks on a repository, run pre-commit run --all-files . To run individual hooks use pre-commit run <hook_id> . The first time pre-commit runs on a file it will automatically download, install, and run the hook.
The preferred way to write tests in Django is using the unittest module built-in to the Python standard library. This is covered in detail in the Writing and running tests document. You can also use any other Python test framework; Django provides an API and tools for that kind of integration.
The pre-commit hook is run first, before you even type in a commit message. It's used to inspect the snapshot that's about to be committed, to see if you've forgotten something, to make sure tests run, or to examine whatever you need to inspect in the code.
It looks like Mercurial's way of importing modules is clashing with Django's somehow.
Before trying to dive in and sort that out, is there any reason to not just run the tests with the normal command?
[hooks]
precommit.runtests = python manage.py test
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With