1#!/usr/bin/env python
2
3import os
4import sys
5
6from django.core.management import ManagementUtility
7
8from pycharm_run_utils import import_system_module
9from teamcity import teamcity_presence_env_var
10
11inspect = import_system_module("inspect")
12
13project_directory = sys.argv.pop()
14
15#ensure project directory is given priority when looking for settings files
16sys.path.insert(0, project_directory)
17
18#import settings to prevent circular dependencies later on import django.db
19try:
20    from django.conf import settings
21    apps = settings.INSTALLED_APPS
22except:
23    pass
24
25from django.core import management
26
27try:
28  # setup environment
29  # this stuff was done earlier by setup_environ() which was removed in 1.4
30  sys.path.append(os.path.join(project_directory, os.pardir))
31  project_name = os.path.basename(project_directory)
32  __import__(project_name)
33except ImportError:
34  # project has custom structure (project directory is not importable)
35  pass
36finally:
37  sys.path.pop()
38
39manage_file = os.getenv('PYCHARM_DJANGO_MANAGE_MODULE')
40if not manage_file:
41  manage_file = 'manage'
42
43try:
44  __import__(manage_file)
45except ImportError as e:
46  print ("Failed to import" + str(manage_file) + " in ["+ ",".join(sys.path) +"] " + str(e))
47
48settings_file = os.getenv('DJANGO_SETTINGS_MODULE')
49if not settings_file:
50  settings_file = 'settings'
51
52import django
53if django.VERSION >= (1, 7):
54    if not settings.configured:
55        settings.configure()
56    django.setup()
57
58
59def _create_command():
60  """
61
62  Creates PycharmTestCommand that inherits real Command class.
63  Wrapped to method to make it is not called when module loaded but only when django fully initialized (lazy)
64
65  """
66  class PycharmTestCommand(ManagementUtility().fetch_command("test").__class__):
67    def get_runner(self):
68      TEST_RUNNER = 'django_test_runner.run_tests'
69      test_path = TEST_RUNNER.split('.')
70      # Allow for Python 2.5 relative paths
71      if len(test_path) > 1:
72        test_module_name = '.'.join(test_path[:-1])
73      else:
74        test_module_name = '.'
75      test_module = __import__(test_module_name, {}, {}, test_path[-1])
76      test_runner = getattr(test_module, test_path[-1])
77      return test_runner
78
79    def handle(self, *test_labels, **options):
80      # handle south migration in tests
81      commands = management.get_commands()
82      if hasattr(settings, "SOUTH_TESTS_MIGRATE") and not settings.SOUTH_TESTS_MIGRATE:
83        # point at the core syncdb command when creating tests
84        # tests should always be up to date with the most recent model structure
85        commands['syncdb'] = 'django.core'
86      elif 'south' in settings.INSTALLED_APPS:
87        try:
88          from south.management.commands import MigrateAndSyncCommand
89          commands['syncdb'] = MigrateAndSyncCommand()
90          from south.hacks import hacks
91          if hasattr(hacks, "patch_flush_during_test_db_creation"):
92            hacks.patch_flush_during_test_db_creation()
93        except ImportError:
94          commands['syncdb'] = 'django.core'
95
96      verbosity = int(options.get('verbosity', 1))
97      interactive = options.get('interactive', True)
98      failfast = options.get('failfast', False)
99      TestRunner = self.get_runner()
100
101      if not inspect.ismethod(TestRunner):
102        our_options = {"verbosity": int(verbosity), "interactive": interactive, "failfast": failfast}
103        options.update(our_options)
104        failures = TestRunner(test_labels, **options)
105      else:
106        test_runner = TestRunner(verbosity=verbosity, interactive=interactive, failfast=failfast)
107        failures = test_runner.run_tests(test_labels)
108
109      if failures:
110        sys.exit(bool(failures))
111
112  return PycharmTestCommand()
113
114
115class PycharmTestManagementUtility(ManagementUtility):
116  def __init__(self, argv=None):
117    ManagementUtility.__init__(self, argv)
118
119  def execute(self):
120    from django_test_runner import is_nosetest
121    if is_nosetest(settings) and "_JB_USE_OLD_RUNNERS" not in os.environ:
122      # New way to run django-nose is to install teamcity-runners plugin
123      # there is no easy way to get qname in 2.7 so string is used
124      name = "teamcity.nose_report.TeamcityReport"
125
126      # emulate TC to enable plugin
127      os.environ.update({teamcity_presence_env_var: "1"})
128
129      # NOSE_PLUGINS could be list or tuple. Adding teamcity plugin to it
130      try:
131        settings.NOSE_PLUGINS += [name]
132      except TypeError:
133        settings.NOSE_PLUGINS += (name, )
134      except AttributeError:
135        settings.NOSE_PLUGINS = [name]
136
137      # This file is required to init and monkeypatch new runners
138      # noinspection PyUnresolvedReferences
139      import _jb_runner_tools
140      super(PycharmTestManagementUtility, self).execute()
141    else:
142      _create_command().run_from_argv(self.argv)
143
144
145if __name__ == "__main__":
146
147  try:
148    custom_settings = __import__(settings_file)
149    splitted_settings = settings_file.split('.')
150    if len(splitted_settings) != 1:
151      settings_name = '.'.join(splitted_settings[:-1])
152      settings_module = __import__(settings_name, globals(), locals(), [splitted_settings[-1]])
153      custom_settings = getattr(settings_module, splitted_settings[-1])
154
155  except ImportError:
156    print ("There is no such settings file " + str(settings_file) + "\n")
157
158  try:
159    subcommand = sys.argv[1]
160  except IndexError:
161    subcommand = 'help' # Display help if no arguments were given.
162
163  if subcommand == 'test':
164    utility = PycharmTestManagementUtility(sys.argv)
165  else:
166    utility = ManagementUtility()
167
168  utility.execute()
169