Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

First working version with notifications

  • Loading branch information...
commit f82fb697fde9c95a381901443d99ebaf75803245 1 parent e805ada
martinrusev authored

Showing 26 changed files with 259 additions and 201 deletions. Show diff stats Hide diff stats

  1. +28 0 LICENSE.txt
  2. +1 0  MANIFEST.in
  3. 0  README
  4. +65 0 README.rst
  5. +3 0  __init__.py
  6. 0  {exampleapp → autotest}/__init__.py
  7. 0  {exampleapp → }/autotest/__init__.pyc
  8. 0  {exampleapp/autotest → autotest/management}/__init__.py
  9. 0  {exampleapp → }/autotest/management/__init__.pyc
  10. 0  {exampleapp/autotest/management → autotest/management/commands}/__init__.py
  11. 0  {exampleapp → }/autotest/management/commands/__init__.pyc
  12. +67 0 autotest/management/commands/autotest.py
  13. BIN  autotest/management/commands/autotest.pyc
  14. +39 0 autotest/management/commands/autotestrunner.py
  15. BIN  autotest/management/commands/autotestrunner.pyc
  16. +13 0 autotest/notifications.py
  17. +14 0 autotest/testrunner.py
  18. BIN  exampleapp/__init__.pyc
  19. 0  exampleapp/autotest/management/commands/__init__.py
  20. +0 63 exampleapp/autotest/management/commands/autotest.py
  21. BIN  exampleapp/autotest/management/commands/autotest.pyc
  22. +0 14 exampleapp/manage.py
  23. +0 107 exampleapp/settings.py
  24. BIN  exampleapp/settings.pyc
  25. +0 17 exampleapp/urls.py
  26. +29 0 setup.py
28 LICENSE.txt
... ... @@ -0,0 +1,28 @@
  1 +Copyright (c) 2011, Martin Rusev
  2 +All rights reserved.
  3 +
  4 +Redistribution and use in source and binary forms, with or without
  5 +modification, are permitted provided that the following conditions are
  6 +met:
  7 +
  8 + * Redistributions of source code must retain the above copyright
  9 + notice, this list of conditions and the following disclaimer.
  10 + * Redistributions in binary form must reproduce the above
  11 + copyright notice, this list of conditions and the following
  12 + disclaimer in the documentation and/or other materials provided
  13 + with the distribution.
  14 + * Neither the name of the author nor the names of other
  15 + contributors may be used to endorse or promote products derived
  16 + from this software without specific prior written permission.
  17 +
  18 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1  MANIFEST.in
... ... @@ -0,0 +1 @@
  1 +include README.rst LICENSE.txt
0  README
No changes.
65 README.rst
Source Rendered
... ... @@ -0,0 +1,65 @@
  1 +=================
  2 +django-autotest
  3 +=================
  4 +
  5 +Django autotest is a custom command for your applications
  6 +that runs the test suite when you save a test file and displays
  7 +a desktop notification with the results.
  8 +
  9 +===============
  10 + Installation
  11 +===============
  12 +
  13 +
  14 +1. Install the package with ``pip install django_autotest`` or alternatively you can
  15 +download the tarball and run ``python setup.py install``
  16 +
  17 +2. Add ``autotest`` to your INSTALLED_APPS list in settings.py
  18 +
  19 +
  20 +::
  21 +
  22 + INSTALLED_APPS = ('autotest')
  23 +
  24 +
  25 +
  26 +3. Add a PROJECT_ROOT variable to ``settings.py`` with the absolute path to your Django application.
  27 +
  28 +::
  29 +
  30 + from os.path import abspath, dirname
  31 +
  32 + PROJECT_ROOT = abspath(dirname(__file__))
  33 +
  34 + # or if you have already defined that for another purposes ( templates for example )
  35 + PROJECT_ROOT = MY_PROJECT_ROOT_DIRECTORY
  36 +
  37 +
  38 +=========
  39 + Usage
  40 +=========
  41 +
  42 +
  43 +
  44 +
  45 +==================
  46 + Additional notes
  47 +==================
  48 +
  49 +
  50 +
  51 +===============
  52 + Requirements
  53 +===============
  54 +
  55 +
  56 +Django 1.2+
  57 +
  58 +watchdog
  59 +
  60 +For the notifications:
  61 +
  62 +libnotify ( Linux )
  63 +Growl ( Windows and Mac )
  64 +
  65 +
3  __init__.py
... ... @@ -0,0 +1,3 @@
  1 +from os.path import abspath, dirname
  2 +
  3 +AUTOTEST_PATH = abspath(dirname(__file__))
0  exampleapp/__init__.py → autotest/__init__.py
File renamed without changes
0  exampleapp/autotest/__init__.pyc → autotest/__init__.pyc
File renamed without changes
0  exampleapp/autotest/__init__.py → autotest/management/__init__.py
File renamed without changes
0  exampleapp/autotest/management/__init__.pyc → autotest/management/__init__.pyc
File renamed without changes
0  exampleapp/autotest/management/__init__.py → autotest/management/commands/__init__.py
File renamed without changes
0  exampleapp/autotest/management/commands/__init__.pyc → autotest/management/commands/__init__.pyc
File renamed without changes
67 autotest/management/commands/autotest.py
... ... @@ -0,0 +1,67 @@
  1 +import time
  2 +from watchdog.observers import Observer
  3 +from watchdog.events import PatternMatchingEventHandler
  4 +from django.core.management.base import BaseCommand
  5 +from os import path, chdir
  6 +from django.conf import settings
  7 +from subprocess import Popen, PIPE, call
  8 +from autotest import AUTOTEST_PATH
  9 +
  10 +
  11 +class AutotestEventHandler(PatternMatchingEventHandler):
  12 +
  13 +
  14 + def run_test_suite(self):
  15 +
  16 +
  17 + chdir(settings.PROJECT_ROOT)
  18 + result = Popen(['./manage.py', 'autotestrunner'], stdout=PIPE, stderr=PIPE, close_fds=True).communicate()
  19 +
  20 + title = ''
  21 + content = ''
  22 + for line in result:
  23 + split_lines = line.split('\n')
  24 + for l in split_lines:
  25 + if l.startswith('Ran'):
  26 + title = l
  27 + if l.startswith('OK') or l.startswith('FAIL'):
  28 + content = l
  29 +
  30 + call(['/usr/bin/python',
  31 + '{0}notifications.py'.format(AUTOTEST_PATH),
  32 + '--title={0}'.format(title),
  33 + '--content={0}'.format(content)]
  34 + )
  35 +
  36 +
  37 + def on_modified(self, event):
  38 + path_to_file, filename = path.split(event.src_path)
  39 + print filename
  40 + self.run_test_suite()
  41 +
  42 +
  43 +class Command(BaseCommand):
  44 + option_list = BaseCommand.option_list + (
  45 + )
  46 + help = 'Runs the test suite when a tests file is saved'
  47 + args = '[appname ...]'
  48 +
  49 + requires_model_validation = False
  50 +
  51 + def handle(self, *args, **options):
  52 + self.event_handler = AutotestEventHandler(patterns=['*.py'],ignore_directories=True)
  53 + self.run()
  54 +
  55 + def run(self):
  56 + app_path = settings.PROJECT_ROOT
  57 +
  58 + observer = Observer()
  59 + observer.schedule(self.event_handler, app_path, recursive=True)
  60 + observer.start()
  61 + try:
  62 + while True:
  63 + time.sleep(1)
  64 + except KeyboardInterrupt:
  65 + observer.stop()
  66 + observer.join()
  67 +
BIN  autotest/management/commands/autotest.pyc
Binary file not shown
39 autotest/management/commands/autotestrunner.py
... ... @@ -0,0 +1,39 @@
  1 +from django.core.management.base import BaseCommand
  2 +from django.conf import settings
  3 +
  4 +
  5 +def get_runner(settings):
  6 + test_path = settings.AUTOTEST_RUNNER.split('.')
  7 + # Allow for Python 2.5 relative paths
  8 + if len(test_path) > 1:
  9 + test_module_name = '.'.join(test_path[:-1])
  10 + else:
  11 + test_module_name = '.'
  12 + test_module = __import__(test_module_name, {}, {}, test_path[-1])
  13 + test_runner = getattr(test_module, test_path[-1])
  14 +
  15 + return test_runner
  16 +
  17 +
  18 +class Command(BaseCommand):
  19 + option_list = BaseCommand.option_list + ()
  20 + help = 'Internal command for the autotest app'
  21 + args = '[appname ...]'
  22 +
  23 + requires_model_validation = False
  24 +
  25 + def handle(self, *test_labels, **options):
  26 +
  27 + TestRunner = get_runner(settings)
  28 +
  29 + if hasattr(TestRunner, 'func_name'):
  30 + import warnings
  31 + warnings.warn(
  32 + 'Function-based test runners are deprecated. Test runners should be classes with a run_tests() method.',
  33 + DeprecationWarning
  34 + )
  35 + failures = TestRunner(verbosity=1, interactive=True)
  36 + else:
  37 + test_runner = TestRunner(verbosity=1, interactive=True, failfast=True)
  38 + failures = test_runner.run_tests(test_labels)
  39 +
BIN  autotest/management/commands/autotestrunner.pyc
Binary file not shown
13 autotest/notifications.py
... ... @@ -0,0 +1,13 @@
  1 +import sys
  2 +import pynotify
  3 +import getopt
  4 +
  5 +if __name__ == '__main__':
  6 +
  7 + args = sys.argv[1:]
  8 + optlist,args = getopt.getopt(args, "tc:d", ['title=', 'content='])
  9 +
  10 + title = optlist[0][1]
  11 + content = optlist[1][1]
  12 + n = pynotify.Notification(title, content)
  13 + n.show()
14 autotest/testrunner.py
... ... @@ -0,0 +1,14 @@
  1 +from django.conf import settings
  2 +from django.test.simple import DjangoTestSuiteRunner
  3 +from django.test.utils import setup_test_environment, teardown_test_environment
  4 +
  5 +
  6 +class AutotestSuiteRunner(DjangoTestSuiteRunner):
  7 +
  8 +
  9 + def setup_test_environment(self, **kwargs):
  10 + setup_test_environment()
  11 + settings.DEBUG = False
  12 +
  13 + def teardown_test_environment(self, **kwargs):
  14 + teardown_test_environment()
BIN  exampleapp/__init__.pyc
Binary file not shown
0  exampleapp/autotest/management/commands/__init__.py
No changes.
63 exampleapp/autotest/management/commands/autotest.py
... ... @@ -1,63 +0,0 @@
1   -import time
2   -from watchdog.observers import Observer
3   -from watchdog.events import PatternMatchingEventHandler
4   -from django.core.management.base import BaseCommand
5   -from os import path
6   -from django.conf import settings
7   -
8   -
9   -class AutotestEventHandler(PatternMatchingEventHandler):
10   - def on_any_event(self, event):
11   - print event.src_path
12   -
13   - path_to_file, filename = path.split(event.src_path)
14   -
15   - print path.split(event.src_path)
16   -
17   -class Command(BaseCommand):
18   - option_list = BaseCommand.option_list + (
19   - )
20   - help = ''
21   - args = '[appname ...]'
22   -
23   - requires_model_validation = False
24   -
25   - def handle(self, *args, **options):
26   - self.event_handler = AutotestEventHandler(patterns=['*.py'], ignore_directories=True)
27   - self.run(*args, **options)
28   -
29   - def run(self, *args, **options):
30   - app_path = settings.PROJECT_ROOT
31   -
32   - observer = Observer()
33   - observer.schedule(self.event_handler, app_path, recursive=True)
34   - observer.start()
35   - try:
36   - while True:
37   - time.sleep(1)
38   - except KeyboardInterrupt:
39   - observer.stop()
40   - observer.join()
41   -
42   - def inner_run(self, *args, **options):
43   - from django.test.utils import get_runner
44   -
45   - self.stdout.write("Validating models...\n\n")
46   -
47   - verbosity = int(options.get('verbosity', 1))
48   - interactive = options.get('interactive', True)
49   - failfast = options.get('failfast', False)
50   - TestRunner = get_runner(settings)
51   -
52   - if hasattr(TestRunner, 'func_name'):
53   - import warnings
54   - warnings.warn(
55   - 'Function-based test runners are deprecated. Test runners should be classes with a run_tests() method.',
56   - DeprecationWarning
57   - )
58   - failures = TestRunner(args, verbosity=verbosity, interactive=interactive)
59   - else:
60   - test_runner = TestRunner(verbosity=verbosity, interactive=interactive, failfast=failfast)
61   - failures = test_runner.run_tests(args)
62   -
63   - print failures
BIN  exampleapp/autotest/management/commands/autotest.pyc
Binary file not shown
14 exampleapp/manage.py
... ... @@ -1,14 +0,0 @@
1   -#!/usr/bin/env python
2   -from django.core.management import execute_manager
3   -import imp
4   -try:
5   - imp.find_module('settings') # Assumed to be in the same directory.
6   -except ImportError:
7   - import sys
8   - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
9   - sys.exit(1)
10   -
11   -import settings
12   -
13   -if __name__ == "__main__":
14   - execute_manager(settings)
107 exampleapp/settings.py
... ... @@ -1,107 +0,0 @@
1   -from os.path import abspath, dirname
2   -
3   -DEBUG = True
4   -TEMPLATE_DEBUG = DEBUG
5   -
6   -ADMINS = (
7   - # ('Your Name', 'your_email@example.com'),
8   -)
9   -
10   -MANAGERS = ADMINS
11   -
12   -DATABASES = {
13   - 'default': {
14   - 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
15   - 'NAME': 'autotest.db', # Or path to database file if using sqlite3.
16   - 'USER': '', # Not used with sqlite3.
17   - 'PASSWORD': '', # Not used with sqlite3.
18   - 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
19   - 'PORT': '', # Set to empty string for default. Not used with sqlite3.
20   - }
21   -}
22   -
23   -TIME_ZONE = 'America/Chicago'
24   -
25   -LANGUAGE_CODE = 'en-us'
26   -
27   -SITE_ID = 1
28   -
29   -USE_I18N = True
30   -
31   -USE_L10N = True
32   -
33   -MEDIA_ROOT = ''
34   -
35   -MEDIA_URL = ''
36   -
37   -STATIC_ROOT = ''
38   -
39   -STATIC_URL = '/static/'
40   -
41   -ADMIN_MEDIA_PREFIX = '/static/admin/'
42   -
43   -# Additional locations of static files
44   -STATICFILES_DIRS = (
45   -)
46   -
47   -STATICFILES_FINDERS = (
48   - 'django.contrib.staticfiles.finders.FileSystemFinder',
49   - 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
50   -# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
51   -)
52   -
53   -# Make this unique, and don't share it with anybody.
54   -SECRET_KEY = 'w&mj%j1+=deov$vd3#$=2@hry&niq+5r9-xf&%wcqpdkzaqane'
55   -
56   -# List of callables that know how to import templates from various sources.
57   -TEMPLATE_LOADERS = (
58   - 'django.template.loaders.filesystem.Loader',
59   - 'django.template.loaders.app_directories.Loader',
60   -# 'django.template.loaders.eggs.Loader',
61   -)
62   -
63   -MIDDLEWARE_CLASSES = (
64   - 'django.middleware.common.CommonMiddleware',
65   - 'django.contrib.sessions.middleware.SessionMiddleware',
66   - 'django.middleware.csrf.CsrfViewMiddleware',
67   - 'django.contrib.auth.middleware.AuthenticationMiddleware',
68   - 'django.contrib.messages.middleware.MessageMiddleware',
69   -)
70   -
71   -ROOT_URLCONF = 'exampleapp.urls'
72   -
73   -TEMPLATE_DIRS = (
74   - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
75   - # Always use forward slashes, even on Windows.
76   - # Don't forget to use absolute paths, not relative paths.
77   -)
78   -
79   -PROJECT_ROOT = abspath(dirname(__file__))
80   -
81   -INSTALLED_APPS = (
82   - 'django.contrib.auth',
83   - 'django.contrib.contenttypes',
84   - 'django.contrib.sessions',
85   - 'django.contrib.sites',
86   - 'django.contrib.messages',
87   - 'django.contrib.staticfiles',
88   - 'autotest',
89   -)
90   -
91   -LOGGING = {
92   - 'version': 1,
93   - 'disable_existing_loggers': False,
94   - 'handlers': {
95   - 'mail_admins': {
96   - 'level': 'ERROR',
97   - 'class': 'django.utils.log.AdminEmailHandler'
98   - }
99   - },
100   - 'loggers': {
101   - 'django.request': {
102   - 'handlers': ['mail_admins'],
103   - 'level': 'ERROR',
104   - 'propagate': True,
105   - },
106   - }
107   -}
BIN  exampleapp/settings.pyc
Binary file not shown
17 exampleapp/urls.py
... ... @@ -1,17 +0,0 @@
1   -from django.conf.urls.defaults import patterns, include, url
2   -
3   -# Uncomment the next two lines to enable the admin:
4   -# from django.contrib import admin
5   -# admin.autodiscover()
6   -
7   -urlpatterns = patterns('',
8   - # Examples:
9   - # url(r'^$', 'exampleapp.views.home', name='home'),
10   - # url(r'^exampleapp/', include('exampleapp.foo.urls')),
11   -
12   - # Uncomment the admin/doc line below to enable admin documentation:
13   - # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
14   -
15   - # Uncomment the next line to enable the admin:
16   - # url(r'^admin/', include(admin.site.urls)),
17   -)
29 setup.py
... ... @@ -0,0 +1,29 @@
  1 +from setuptools import setup, find_packages
  2 +import os
  3 +
  4 +def read(filename):
  5 + return open(os.path.join(os.path.dirname(__file__), filename)).read()
  6 +
  7 +version = '0.1.0'
  8 +
  9 +setup(
  10 + name='django_autotest',
  11 + version=version,
  12 + description="Django autotest is a command that automaticaly runs the test suite",
  13 + long_description=read('README.rst'),
  14 + classifiers=[
  15 + "Programming Language :: Python",
  16 + "Topic :: Software Development :: Libraries :: Python Modules",
  17 + "Framework :: Django",
  18 + "Environment :: Web Environment",
  19 + ],
  20 + keywords='django, tests, autotest,',
  21 + author='Martin Rusev',
  22 + author_email='martinrusev@live.com',
  23 + url='https://github.com/martinrusev/django-autotest',
  24 + license='BSD',
  25 + packages=find_packages(),
  26 + zip_safe=False,
  27 + install_requires=['setuptools','watchdog',],
  28 + include_package_data=True,
  29 +)

0 comments on commit f82fb69

Please sign in to comment.
Something went wrong with that request. Please try again.