diff --git a/Build.py b/Build.py index 4599642..868035c 100755 --- a/Build.py +++ b/Build.py @@ -234,6 +234,7 @@ class Analysis(Target): if pathex: for path in pathex: self.pathex.append(absnormpath(path)) + sys.pathex = pathex[:] self.hookspath = hookspath self.excludes = excludes self.scripts = TOC() diff --git a/hooks/django-import-finder.py b/hooks/django-import-finder.py new file mode 100644 index 0000000..a4865a3 --- /dev/null +++ b/hooks/django-import-finder.py @@ -0,0 +1,54 @@ +# Copyright (C) 2009, Lorenzo Berni +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import os +if not os.environ.get("DJANGO_SETTINGS_MODULE"): + os.environ["DJANGO_SETTINGS_MODULE"] = "settings" + +from django.conf import settings + +hiddenimports = list(settings.AUTHENTICATION_BACKENDS) + \ + [settings.DEFAULT_FILE_STORAGE] + \ + list(settings.FILE_UPLOAD_HANDLERS) + \ + list(settings.INSTALLED_APPS) + \ + list(settings.MIDDLEWARE_CLASSES) + \ + list(settings.TEMPLATE_CONTEXT_PROCESSORS) + \ + list(settings.TEMPLATE_LOADERS) + \ + [settings.ROOT_URLCONF] + +def find_url_callbacks(urls_module): + urlpatterns = urls_module.urlpatterns + hid_list = [urls_module.__name__] + for pattern in urlpatterns: + if isinstance(pattern, RegexURLPattern): + hid_list.append(pattern.callback.__module__) + elif isinstance(pattern, RegexURLResolver): + hid_list += find_url_callbacks(pattern.urlconf_module) + return hid_list + +from django.core.urlresolvers import RegexURLPattern, RegexURLResolver + +base_module_name = ".".join(os.environ.get("DJANGO_SETTINGS_MODULE", "settings").split(".")[:-1]) +if base_module_name: + base_module = __import__(base_module_name, {}, {}, ["urls"]) + urls = base_module.urls +else: + import urls +hiddenimports += find_url_callbacks(urls) + +print repr(sorted(set(hiddenimports))) + diff --git a/hooks/hook-django.contrib.py b/hooks/hook-django.contrib.py new file mode 100644 index 0000000..e69de29 diff --git a/hooks/hook-django.contrib.sessions.py b/hooks/hook-django.contrib.sessions.py new file mode 100644 index 0000000..2820bc8 --- /dev/null +++ b/hooks/hook-django.contrib.sessions.py @@ -0,0 +1,33 @@ +# Copyright (C) 2009, Lorenzo Berni +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import os +import glob + +def hook(mod): + global hiddenimports + + modpath = mod.__path__[0] + hiddenimports = [] + + for fn in glob.glob('%s/backends/*.py' % modpath): + fn = os.path.basename(fn) + fn = os.path.splitext(fn)[0] + hiddenimports.append('django.contrib.sessions.backends.' + fn) + + return mod + diff --git a/hooks/hook-django.core.cache.py b/hooks/hook-django.core.cache.py new file mode 100644 index 0000000..4a2d06d --- /dev/null +++ b/hooks/hook-django.core.cache.py @@ -0,0 +1,33 @@ +# Copyright (C) 2009, Lorenzo Berni +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import os +import glob + +def hook(mod): + global hiddenimports + + modpath = mod.__path__[0] + hiddenimports = [] + + for fn in glob.glob('%s/backends/*.py' % modpath): + fn = os.path.basename(fn) + fn = os.path.splitext(fn)[0] + hiddenimports.append('django.core.cache.backends.' + fn) + + return mod + diff --git a/hooks/hook-django.core.mail.py b/hooks/hook-django.core.mail.py new file mode 100644 index 0000000..d46b1a6 --- /dev/null +++ b/hooks/hook-django.core.mail.py @@ -0,0 +1,31 @@ +# Copyright (C) 2009, Lorenzo Berni +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +# django.core.mail uses part of the email package. +# Problem is: when using runserver with autoreload mode, the thread that +# checks fore changed files unwillingly trigger further imports within +# the email package because of the LazyImporter in email (used in 2.5 for +# backward compatibility). +# We then need to name those modules as hidden imports, otherwise at +# runtime the autoreload thread will complain with a traceback. +hiddenimports = [ + 'email.mime.message', + 'email.mime.image', + 'email.mime.text', + 'email.mime.multipart', + 'email.mime.audio' +] diff --git a/hooks/hook-django.core.management.py b/hooks/hook-django.core.management.py new file mode 100644 index 0000000..cc6897d --- /dev/null +++ b/hooks/hook-django.core.management.py @@ -0,0 +1,34 @@ +# Copyright (C) 2009, Lorenzo Berni +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import os +import glob + +def hook(mod): + global hiddenimports + + modpath = mod.__path__[0] + + hiddenimports = [] + + for fn in glob.glob('%s/commands/*.py' % modpath): + fn = os.path.basename(fn) + fn = os.path.splitext(fn)[0] + hiddenimports.append('django.core.management.commands.' + fn) + + return mod + diff --git a/hooks/hook-django.core.py b/hooks/hook-django.core.py new file mode 100644 index 0000000..e69de29 diff --git a/hooks/hook-django.db.backends.py b/hooks/hook-django.db.backends.py new file mode 100644 index 0000000..4e6d192 --- /dev/null +++ b/hooks/hook-django.db.backends.py @@ -0,0 +1,33 @@ +# Copyright (C) 2009, Lorenzo Berni +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import os +import glob + +def hook(mod): + global hiddenimports + + modpath = mod.__path__[0] + hiddenimports = [] + + for fn in glob.glob('%s/*' % modpath): + if os.path.isdir(fn): + fn = os.path.basename(fn) + hiddenimports.append('django.db.backends.' + fn + '.base') + + return mod + diff --git a/hooks/hook-django.db.py b/hooks/hook-django.db.py new file mode 100644 index 0000000..e69de29 diff --git a/hooks/hook-django.py b/hooks/hook-django.py new file mode 100644 index 0000000..176ef1a --- /dev/null +++ b/hooks/hook-django.py @@ -0,0 +1,48 @@ +# Copyright (C) 2009, Lorenzo Berni +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +from hookutils import django_dottedstring_imports, find_django_root + +import glob +import sys +import os + +python_path = os.environ.get("PYTHONPATH") + +if python_path: + python_path = os.pathsep.join([python_path] + sys.pathex) +else: + python_path = os.pathsep.join(sys.pathex) + +django_root_dirs = [] + +for path in python_path.split(os.pathsep): + django_root_dirs += find_django_root(path) + +if not django_root_dirs: + raise RuntimeError("No django root directory found. Please check your pathex definition in the project spec file.") +if django_root_dirs[0] in sys.pathex: + raise RuntimeError("The django root directory is defined in the pathex. You have to define the parent directory instead of the django root directory.") + +os.environ["PYTHONPATH"] = python_path + +hiddenimports = [] + +for django_root_dir in django_root_dirs: + hiddenimports += django_dottedstring_imports(django_root_dir) + + diff --git a/hooks/hookutils.py b/hooks/hookutils.py index 77c90ad..4de8931 100644 --- a/hooks/hookutils.py +++ b/hooks/hookutils.py @@ -1,5 +1,7 @@ #!/usr/bin/env python +import os + def exec_statement(stat): """Executes a Python statement in an externally spawned interpreter, and returns anything that was emitted in the standard output as a single string. @@ -53,3 +55,23 @@ def qwt_numeric_support(): return eval(exec_statement("from PyQt4 import Qwt5; print hasattr(Qwt5, 'toNumeric')")) def qwt_numarray_support(): return eval(exec_statement("from PyQt4 import Qwt5; print hasattr(Qwt5, 'toNumarray')")) + +def django_dottedstring_imports(django_root_dir): + package_name = os.path.basename(django_root_dir) + os.environ["DJANGO_SETTINGS_MODULE"] = "%s.settings" %package_name + return eval(exec_statement("execfile(r'%s')" %os.path.join(os.path.dirname(__file__), "django-import-finder.py"))) + +def find_django_root(dir): + entities = os.listdir(dir) + if "manage.py" in entities and "settings.py" in entities and "urls.py" in entities: + return dir + else: + django_root_directories = [] + for entity in entities: + path_to_analyze = os.path.join(dir, entity) + if os.path.isdir(path_to_analyze): + dir_entities = os.listdir(path_to_analyze) + if "manage.py" in dir_entities and "settings.py" in dir_entities and "urls.py" in dir_entities: + django_root_directories.append(path_to_analyze) + return django_root_directories + diff --git a/rthooks.dat b/rthooks.dat index b691b7c..f458893 100644 --- a/rthooks.dat +++ b/rthooks.dat @@ -6,4 +6,5 @@ 'PyQt4': ['support/rthooks/pyi_rth_qt4plugins.py'], 'matplotlib': ['support/rthooks/pyi_rth_mpldata.py'], 'babel': ['support/rthooks/pyi_rth_babel.py'], + 'django': ['support/rthooks/pyi_rth_django.py'], } diff --git a/support/rthooks/pyi_rth_django.py b/support/rthooks/pyi_rth_django.py new file mode 100644 index 0000000..6399dd9 --- /dev/null +++ b/support/rthooks/pyi_rth_django.py @@ -0,0 +1,54 @@ +# Copyright (C) 2009, Lorenzo Berni +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import os +import sys + +if "_MEIPASS2" in os.environ: + d = os.environ["_MEIPASS2"] +else: + d = os.path.dirname(sys.argv[0]) + +import django.core.management +import django.utils.autoreload + +def _setup_environ(settings_mod, original_settings_path=None): + project_name = settings_mod.__name__.split(".")[0] + settings_name = "settings" + if original_settings_path: + os.environ['DJANGO_SETTINGS_MODULE'] = original_settings_path + else: + os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name) + project_module = __import__(project_name, {}, {}, ['']) + return d + +def _find_commands(_): + return """cleanup compilemessages createcachetable dbshell shell runfcgi runserver startproject""".split() + +old_restart_with_reloader = django.utils.autoreload.restart_with_reloader +def _restart_with_reloader(*args): + import sys + a0 = sys.argv.pop(0) + try: + return old_restart_with_reloader(*args) + finally: + sys.argv.insert(0, a0) + + +django.core.management.setup_environ = _setup_environ +django.core.management.find_commands = _find_commands +django.utils.autoreload.restart_with_reloader = _restart_with_reloader