On 13/08/2006, at 3:43 AM, Dan Eloff wrote:
I had some modules with circular imports and I only discovered that
this was a problem when I tried to discover why my modules were being
reimported constantly. I would suggest that this code be changed to
log an error that explicitly tells you that there's a circular import,
and what the consequences are.
# Check for a child which refers to one of its
# ancestors. Hopefully this will never occur. If
# it does we will force a reload every time to
# highlight there is a problem.
if label in ancestors:
# LOG HELPFUL ERROR HERE
return True
That looks reasonable. Should the warning message always be displayed in
the Apache error log, even if PythonDebug is Off?
Also, I still chafe every time I have to write:
sidewinder_dir = r'C:\Docume~1\Dan\MyDocu~1\PYROOT\sidewinder\\'
from mod_python import apache
session = apache.import_module(sidewinder_dir+'session.py')
config = apache.import_module(sidewinder_dir+'config.py')
Instead of:
import session
import config
One can clean it up a bit and have:
__mp_path__ += [r'C:\Docume~1\Dan\MyDocu~1\PYROOT\sidewinder\\']
from mod_python import apache
import session
import config
Or even:
from mod_python import apache
MAIN_SERVER_CONFIG = apache.main_server.get_config()
CONFIG_MODULE_PATH = MAIN_SERVER_CONFIG['sidewinder_config']
__mp_path__ += [CONFIG_MODULE_PATH]
import session
import config
The PythonOption has to be part of the main Apache configuration
though and
not part of the VirtualHost or per request configuration, but at
least the path isn't
embedded in the module.
Even so, do appreciate that it isn't really ideal. But then, I do
find it a bit strange
what you are doing in that you seem to be having a generic module
know where
to find something specific to an application it is being used by, by
virtue of what
is in module search path, rather than the application making use of
the generic
module supplying the configuration modules as arguments to functions
in generic
module that may be called by actual application.
Anyway, I have come to the conclusion that one can't avoid having an
equivalent to
the PythonPath directive but which defines directories to be searched
by the new
importer. If people use this in the wrong way and hang themselves
then that is
their problem. In general they would be okay though as long as it is
defined once
only at the root corresponding to a specific Python interpreter
instance.
What I am not sure about yet is whether the means of setting the path
should
be done with a new directive or using PythonOption. As I mentioned in
mail
just sent, one reason for using a new directive, is that if
PythonAllowOverride
is introduced, configuration in main Apache configuration could set
the module
search path and at the same time prohibit the user changing the
default. This
would be needed where for example the user was also prohibited from
defining
their own authentication handlers and there was a global one that used
mod_python handlers. The user could override the default and screw up
the operation of the globally defined authentication handlers if
those handlers
were expecting to find a module by searching that path but by user
changing
it, they could no longer be found. But then, in this situation it may
be better for
the authentication handler to load the module by an explicit path
thereby avoiding
the problem altogether.
Now by using a directive though, it would make it harder for a user
handler,
for example one that ran in the fixup phase, to dynamically modify
the search
path for modules for all response handlers executed within a certain
context.
Specifically, if the search path is set by a PythonOption, then the
fixup handler
could actually modify the inherited value of the option by modifying
the value
stored in the req.get_options() table object. If the proposed
PythonAllowOverride
directive can disallow setting of specific options using
PythonOption, then a
good middle ground might be found as one could block the options
being set
in a .htaccess file and therefore it would not interfere with a
global authentication
handler, but a fixup handler could be allowed to still set it for the
subsequent
response handler. But then, I am talking hypotheticals here and maybe
I am
just thinking too hard. Thinking up such scenarios though, is what is
required
in making good generic reusable modules or frameworks. :-)
My handler imports modules like so:
IMPORT_PATH = [config.server_options['sidewinder_dir'], config.web
['root']]
apache.import_module(mpath, path=IMPORT_PATH)
Which works great, but when those modules import something I have to
use the ugly mess above.
Is IMPORT_PATH different to or the same as:
r'C:\Docume~1\Dan\MyDocu~1\PYROOT\sidewinder\\'
Anyway, the other way of doing the above such that a search directory is
inherited, is to rather than use a module name, translate that to a
full path and
import that. The 'path' argument to apache.import_module() can then
be set
to be a path embedded as __mp_path__ in the module loaded. Ie. something
like:
GENERIC_MODULE_PATH = '/some/path/generic'
CONFIG_MODULE_PATH = '/some/path/config'
GENRIC_MODULE_FILE = os.path.join(GENERIC_MODULE_PATH, "module.py")
module = apache.import_module(GENERIC_MODULE_FILE, path=
[CONFIG_MODULE_PATH])
The path though is only inherited by the module immediately imported
though
and not further.
Originally I probably steered you away from this, because if that
generic module
is imported from multiple locations and not all consistently set the
path to the same,
whatever one got executed first would have their path be used, which
may not be
correct for all use cases. Thus, why I suggested that the generic
module itself dictate
itself any additional path by setting __mp_path__ internally to the
module when it
is being imported.
Maybe you and I could think of a better way?
We can certainly explore other options, just wary of making it too
easy to introduce
non deterministic behaviour like exists now.
I'd like if I could just add an option globally to my httpd.conf like:
PythonOption ChildrenAlwaysInheritImportPath On
This would make things a bit unpredictable again.
Or maybe add another parameter to import_module like:
apache.import_module(mpath, path=IMPORT_PATH, inherit=True)
Which is what path option does when mpath is an absolute path. It
just doesn't
keep being inherited unless module imported does the same thing.
Or?
Simpler just to allow a global search path like PythonPath that is
embedded into
modules when they are imported. It would be embedded so that its
value can't
change over time for a module that has already been imported.
Graham