Parametrized module import

Discussion in 'Python' started by Jacek Generowicz, Jul 8, 2004.

  1. I have a module whose behaviour needs to be configurable. The module
    needs to decide, the first time it is imported, beteween alternative
    interfaces it presents.

    Currently, I set some environment variables which select the desired
    behaviour, and the module inspects those variables to determine the
    mode in which it should set itself up. I would prefer a pure Python
    solution, rather than one which depends on external state.

    Can you recommend any approaches, or warn against the pitfalls of some
    approaches?
     
    Jacek Generowicz, Jul 8, 2004
    #1
    1. Advertising

  2. Jacek Generowicz <> wrote:
    > I have a module whose behaviour needs to be configurable. The module
    > needs to decide, the first time it is imported, beteween alternative
    > interfaces it presents.
    >
    > Currently, I set some environment variables which select the desired
    > behaviour, and the module inspects those variables to determine the
    > mode in which it should set itself up. I would prefer a pure Python
    > solution, rather than one which depends on external state.
    >
    > Can you recommend any approaches, or warn against the pitfalls of some
    > approaches?


    You could create another module called "config" or "cfg"
    which contains some global variables. You import it into
    your configurable module as well as into your main program.
    Then you can configure the module's behaviour via those
    global variables before importing the module.

    Something like this:

    #--- File config.py: ---
    foo_interface_mode = 0 # default

    #--- File your_module.py: ---
    import config
    if config.foo_interface_mode == 0:
    ... this interface
    else:
    ... that interface

    #--- File main_program.py: ---
    import config
    config.foo_interface_mode = 1
    import your_module

    Best regards
    Oliver

    --
    Oliver Fromme, Konrad-Celtis-Str. 72, 81369 Munich, Germany

    ``All that we see or seem is just a dream within a dream.''
    (E. A. Poe)
     
    Oliver Fromme, Jul 8, 2004
    #2
    1. Advertising

  3. Oliver Fromme <> writes:

    > You could create another module called "config" or "cfg"
    > which contains some global variables. You import it into
    > your configurable module as well as into your main program.
    > Then you can configure the module's behaviour via those
    > global variables before importing the module.


    Yes, my initial crappy prototype idea was to add configuration
    information to the sys module, but this variation is much neater
    .... in fact, after the first 2 minutes of thinking about it, it looks
    perfect :)

    However, one thing which keeps bothering me about the whole business,
    is the possibilty of importing the module (with your chosen
    configuration) after it has already been imported, without you knowing
    it, with a different configuration. Ideally there should be some
    warning about the fact that the configuration you specified is being
    ignored as a result of the module already being imported ... and I
    don't see how to achieve this.
     
    Jacek Generowicz, Jul 8, 2004
    #3
  4. On 08 Jul 2004 12:58:51 +0200,
    Jacek Generowicz <> wrote:

    > Oliver Fromme <> writes:


    >> You could create another module called "config" or "cfg" which
    >> contains some global variables. You import it into your
    >> configurable module as well as into your main program. Then
    >> you can configure the module's behaviour via those global
    >> variables before importing the module.


    > Yes, my initial crappy prototype idea was to add configuration
    > information to the sys module, but this variation is much neater
    > ... in fact, after the first 2 minutes of thinking about it, it
    > looks perfect :)


    > However, one thing which keeps bothering me about the whole
    > business, is the possibilty of importing the module (with your
    > chosen configuration) after it has already been imported,
    > without you knowing it, with a different configuration. Ideally
    > there should be some warning about the fact that the
    > configuration you specified is being ignored as a result of the
    > module already being imported ... and I don't see how to achieve
    > this.


    Upon import, a module's "top level" code is executed, so try a
    variation on this theme at the top level of your module:

    i_am_configured = False

    if i_am_configured:
    print 'i am already configured'
    else:
    import my_configuration_module
    configure_myself( )
    i_am_configured = True

    HTH,
    Heather

    --
    Heather Coppersmith
    That's not right; that's not even wrong. -- Wolfgang Pauli
     
    Heather Coppersmith, Jul 8, 2004
    #4
  5. Heather Coppersmith <> writes:

    > Upon import, a module's "top level" code is executed,


    Yes, but only on the _first_ import. On subsequent imports the system
    notices that the module has already imported, and doesn't execute
    anything in the module, it just binds a name to the already imported
    module ...

    > so try a variation on this theme at the top level of your module:
    >
    > i_am_configured = False
    >
    > if i_am_configured:
    > print 'i am already configured'
    > else:
    > import my_configuration_module
    > configure_myself( )
    > i_am_configured = True


    .... so the first branch will _never_ get executed.

    My question is exactly about this problem: nothing gets executed on
    the second import, so there's nowhere for me to put the "already
    configured" message.
     
    Jacek Generowicz, Jul 8, 2004
    #5
  6. Heather Coppersmith <> wrote:
    > Jacek Generowicz <> wrote:
    > > Oliver Fromme <> writes:
    > > > You could create another module called "config" or "cfg" which
    > > > contains some global variables. You import it into your
    > > > configurable module as well as into your main program. Then
    > > > you can configure the module's behaviour via those global
    > > > variables before importing the module.

    > >
    > > Yes, my initial crappy prototype idea was to add configuration
    > > information to the sys module, but this variation is much neater
    > > ... in fact, after the first 2 minutes of thinking about it, it
    > > looks perfect :)
    > >
    > > However, one thing which keeps bothering me about the whole
    > > business, is the possibilty of importing the module (with your
    > > chosen configuration) after it has already been imported,
    > > without you knowing it, with a different configuration. Ideally
    > > there should be some warning about the fact that the
    > > configuration you specified is being ignored as a result of the
    > > module already being imported ... and I don't see how to achieve
    > > this.

    >
    > Upon import, a module's "top level" code is executed, so try a
    > variation on this theme at the top level of your module:


    It's only executed when the module is imported for the
    _first_ time, so that wouldn't work.

    However, the problem can be solved by not modifying a
    global variable in the "config" module directly, but by
    using a function which allows only one call.

    #--- File config.py: ---
    foo_interface_mode = None
    def set_foo_interface_mode (mode):
    if foo_interface_mode is None:
    foo_interface_mode = mode
    else:
    raise "foo_interface_mode may only be set once"

    #--- File your_module.py: ---
    import config
    if config.foo_interface_mode is None:
    raise "foo_interface_mode has not been set"
    elif config.foo_interface_mode == 0:
    ... this interface
    else:
    ... that interface

    #--- File main_program.py: ---
    import config
    config.set_foo_interface_mode (1)
    import your_module

    Of course, you could use assert instead of raise, or just
    print a warning and go on. Whatever you prefer.

    Best regards
    Oliver

    --
    Oliver Fromme, Konrad-Celtis-Str. 72, 81369 Munich, Germany

    ``All that we see or seem is just a dream within a dream.''
    (E. A. Poe)
     
    Oliver Fromme, Jul 8, 2004
    #6
  7. Oliver Fromme <> writes:

    > However, the problem can be solved by not modifying a
    > global variable in the "config" module directly, but by
    > using a function which allows only one call.
    >
    > #--- File config.py: ---
    > foo_interface_mode = None
    > def set_foo_interface_mode (mode):
    > if foo_interface_mode is None:
    > foo_interface_mode = mode
    > else:
    > raise "foo_interface_mode may only be set once"


    But there must be a default configuration, so you can't check for
    None. I typically deal with these situations by using functions which
    replace themselves when called:

    def configure():
    print "Configuring ..."
    global configure
    def configure():
    print "Sorry, already configured."

    But this doesn't quite solve the problem I'm trying to solve, which is
    to warn, at the time the import statement is executed, that the
    configuration which is in place is not being respected.

    There's nothing wrong with the user changing the mode twenty times
    before the first import. I guess the imported module could block
    further configuration changes, and the warning can come when you try
    to change the configuration _after_ the first import.
     
    Jacek Generowicz, Jul 8, 2004
    #7
  8. Jacek Generowicz

    george young Guest

    On 08 Jul 2004 09:43:31 +0200
    Jacek Generowicz <> threw this fish to the penguins:

    > I have a module whose behaviour needs to be configurable. The module
    > needs to decide, the first time it is imported, beteween alternative
    > interfaces it presents.
    >
    > Currently, I set some environment variables which select the desired
    > behaviour, and the module inspects those variables to determine the
    > mode in which it should set itself up. I would prefer a pure Python
    > solution, rather than one which depends on external state.
    >
    > Can you recommend any approaches, or warn against the pitfalls of some
    > approaches?


    You might look at the way pygtk does it. I haven't peeked inside, but the
    api is:

    import pygtk
    pygtk.require('2.0') # or '1.2' or some other version
    import gtk # uses state set by require() to load the appropriate version

    The pygtk.py file looks quite reusable with hardly any change...

    See: http://www.pygtk.org


    -- George
    --
    "Are the gods not just?" "Oh no, child.
    What would become of us if they were?" (CSL)
     
    george young, Jul 8, 2004
    #8
  9. george young <> writes:

    > You might look at the way pygtk does it. I haven't peeked inside,


    Here is the relevant part ...

    def require(version):
    global _pygtk_required_version

    if _pygtk_required_version != None:
    assert _pygtk_required_version == version, \
    "a different version of gtk was already required"
    return

    assert not sys.modules.has_key('gtk'), \
    "pygtk.require() must be called before importing gtk"

    ...

    > but the api is:
    >
    > import pygtk
    > pygtk.require('2.0') # or '1.2' or some other version
    > import gtk # uses state set by require() to load the appropriate version


    Yup ... but now I'm being put under pressure to make the API thus:

    import foo
    foo.config....

    which doesn't thrill me at all, for a plethora of implementation
    detail related reasons which are not interesting here.

    Thanks for the poniter, anyway.
     
    Jacek Generowicz, Jul 8, 2004
    #9
  10. Jacek Generowicz

    anton muhin Guest

    Jacek Generowicz wrote:
    > I have a module whose behaviour needs to be configurable. The module
    > needs to decide, the first time it is imported, beteween alternative
    > interfaces it presents.
    >
    > Currently, I set some environment variables which select the desired
    > behaviour, and the module inspects those variables to determine the
    > mode in which it should set itself up. I would prefer a pure Python
    > solution, rather than one which depends on external state.
    >
    > Can you recommend any approaches, or warn against the pitfalls of some
    > approaches?
    >


    Following `explicit is better than implicit` I'd prefer to have a huge
    interface class or object that would be instantiated with parameters.
    Something like this:

    from myModule import myModule

    myModule.tweak(<blah>)

    ....

    myModule.doSomething()

    Of course, this solution might not fit your needs.

    regards,
    anton.
     
    anton muhin, Jul 8, 2004
    #10
  11. anton muhin <> writes:

    > Of course, this solution might not fit your needs.


    In this case, I am afraid that it does not.
     
    Jacek Generowicz, Jul 8, 2004
    #11
  12. On 08 Jul 2004 14:22:25 +0200,
    Jacek Generowicz <> wrote:

    > Heather Coppersmith <> writes:
    >> Upon import, a module's "top level" code is executed,


    > Yes, but only on the _first_ import. On subsequent imports the system
    > notices that the module has already imported, and doesn't execute
    > anything in the module, it just binds a name to the already imported
    > module ...


    >> so try a variation on this theme at the top level of your module:
    >>
    >> i_am_configured = False
    >>
    >> if i_am_configured:
    >> print 'i am already configured'
    >> else:
    >> import my_configuration_module
    >> configure_myself( )
    >> i_am_configured = True


    > ... so the first branch will _never_ get executed.


    > My question is exactly about this problem: nothing gets executed on
    > the second import, so there's nowhere for me to put the "already
    > configured" message.


    Oops--yes, you are correct. I apologize. My quickie tests were
    apparently less than sufficient. [slaps self on wrist, and then
    on forehead]

    Regards,
    Heather

    --
    Heather Coppersmith
    That's not right; that's not even wrong. -- Wolfgang Pauli
     
    Heather Coppersmith, Jul 8, 2004
    #12
  13. Jacek Generowicz

    John Lenton Guest

    On 08 Jul 2004 16:28:21 +0200, Jacek Generowicz
    <> wrote:
    >
    > Yup ... but now I'm being put under pressure to make the API thus:
    >
    > import foo
    > foo.config....
    >
    > which doesn't thrill me at all, for a plethora of implementation
    > detail related reasons which are not interesting here.
    >
    > Thanks for the poniter, anyway.


    How ugly is this:

    import sys

    def __config():
    return sys._getframe(2).f_globals.get('__magic_config', None)

    def config(name):
    name = str(name)
    if name not in __mapping:
    raise RuntimeException, "unknown flavor " + name
    sys._getframe(1).f_globals['__magic_config'] = name

    def __default_bar(*a, **kw):
    print "I am the default"

    def __white_bar(*a, **kw):
    print "I am white"

    def __black_bar(*a, **kw):
    print "I am black"

    __mapping = {'bar': {None: __default_bar,
    'white': __white_bar,
    'black': __black_bar},
    }

    for i in __mapping:
    globals() = lambda *a, **kw: __mapping[__config()](*a, **kw)

    I'd say about 6 in a fuglyness scale, but it might do what you want.
    I'm sure there's an easyer way of putting things into the current
    namespace, but this works.

    --
    John Lenton () -- Random fortune:
    bash: fortune: command not found
     
    John Lenton, Jul 8, 2004
    #13
  14. Jacek Generowicz

    John Lenton Guest

    On 08 Jul 2004 16:28:21 +0200, Jacek Generowicz
    <> wrote:
    >
    > Yup ... but now I'm being put under pressure to make the API thus:
    >
    > import foo
    > foo.config....
    >
    > which doesn't thrill me at all, for a plethora of implementation
    > detail related reasons which are not interesting here.
    >
    > Thanks for the poniter, anyway.


    How ugly is this:

    import sys

    def __config():
    return sys._getframe(2).f_globals.get('__magic_config', None)

    def config(name):
    name = str(name)
    if name not in __mapping:
    raise RuntimeException, "unknown flavor " + name
    sys._getframe(1).f_globals['__magic_config'] = name

    def __default_bar(*a, **kw):
    print "I am the default"

    def __white_bar(*a, **kw):
    print "I am white"

    def __black_bar(*a, **kw):
    print "I am black"

    __mapping = {'bar': {None: __default_bar,
    'white': __white_bar,
    'black': __black_bar},
    }

    for i in __mapping:
    globals() = lambda *a, **kw: __mapping[__config()](*a, **kw)

    I'd say about 6 in a fuglyness scale, but it might do what you want.
    I'm sure there's an easyer way of putting things into the current
    namespace, but this works.

    --
    John Lenton () -- Random fortune:
    bash: fortune: command not found
     
    John Lenton, Jul 8, 2004
    #14
  15. Jacek Generowicz

    John Lenton Guest

    On Thu, 8 Jul 2004 13:25:25 -0300, John Lenton <> wrote:
    > raise RuntimeException, "unknown flavor " + name


    that should've been RuntimeError, and flavour.

    --
    John Lenton () -- Random fortune:
    bash: fortune: command not found
     
    John Lenton, Jul 8, 2004
    #15
  16. Jacek Generowicz <> wrote:
    > But this doesn't quite solve the problem I'm trying to solve, which is
    > to warn, at the time the import statement is executed, that the
    > configuration which is in place is not being respected.


    I see.

    > There's nothing wrong with the user changing the mode twenty times
    > before the first import. I guess the imported module could block
    > further configuration changes, and the warning can come when you try
    > to change the configuration _after_ the first import.


    In that case, why don't you let the imported module change
    the definition of the function in the "config" module?
    That's exactly the place after which modifications should
    be disallowed, if I understand you correctly.

    Third try.

    #--- File config.py: ---
    foo_interface_mode = 0 # default
    def set_foo_interface_mode (mode):
    foo_interface_mode = mode

    #--- File your_module.py: ---
    import config

    def config_warn():
    print "foo_interface_mode may only be set once!"

    config.set_foo_interface_mode = config_warn

    if config.foo_interface_mode == 0:
    ... this interface
    else:
    ... that interface

    #--- File main_program.py: ---
    import config
    config.set_foo_interface_mode (1)
    import your_module

    Best regards
    Oliver

    --
    Oliver Fromme, Konrad-Celtis-Str. 72, 81369 Munich, Germany

    ``All that we see or seem is just a dream within a dream.''
    (E. A. Poe)
     
    Oliver Fromme, Jul 8, 2004
    #16
  17. Oliver Fromme <> writes:

    > > I guess the imported module could block further configuration
    > > changes, and the warning can come when you try to change the
    > > configuration _after_ the first import.


    > #--- File config.py: ---
    > foo_interface_mode = 0 # default
    > def set_foo_interface_mode (mode):
    > foo_interface_mode = mode
    >
    > #--- File your_module.py: ---
    > import config
    >
    > def config_warn():
    > print "foo_interface_mode may only be set once!"
    >
    > config.set_foo_interface_mode = config_warn


    Yup, that's exactly the sort of thing I was suggesting.
     
    Jacek Generowicz, Jul 9, 2004
    #17
  18. Jacek Generowicz

    David Fraser Guest

    Jacek Generowicz wrote:
    > I have a module whose behaviour needs to be configurable. The module
    > needs to decide, the first time it is imported, beteween alternative
    > interfaces it presents.
    >
    > Currently, I set some environment variables which select the desired
    > behaviour, and the module inspects those variables to determine the
    > mode in which it should set itself up. I would prefer a pure Python
    > solution, rather than one which depends on external state.
    >
    > Can you recommend any approaches, or warn against the pitfalls of some
    > approaches?
    >

    What I would recommend is class-ifying the code inside the module. Then
    you can create a fresh object each time you want a different
    configuration, and you don't have to worry about the relationship
    between import and configure.
    This may make your module more flexible as well

    David
     
    David Fraser, Jul 9, 2004
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page