Parametrized module import

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jacek Generowicz

    Parametrized module import

    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?

  • Oliver Fromme

    #2
    Re: Parametrized module import

    Jacek Generowicz <jacek.generowi cz@cern.ch> wrote:[color=blue]
    > 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?[/color]

    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_m ode = 0 # default

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

    #--- File main_program.py : ---
    import config
    config.foo_inte rface_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)

    Comment

    • Jacek Generowicz

      #3
      Re: Parametrized module import

      Oliver Fromme <olli@haluter.f romme.com> writes:
      [color=blue]
      > 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.[/color]

      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.

      Comment

      • Oliver Fromme

        #4
        Re: Parametrized module import

        Heather Coppersmith <me@privacy.net > wrote:[color=blue]
        > Jacek Generowicz <jacek.generowi cz@cern.ch> wrote:[color=green]
        > > Oliver Fromme <olli@haluter.f romme.com> writes:[color=darkred]
        > > > 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.[/color]
        > >
        > > 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.[/color]
        >
        > Upon import, a module's "top level" code is executed, so try a
        > variation on this theme at the top level of your module:[/color]

        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_m ode = None
        def set_foo_interfa ce_mode (mode):
        if foo_interface_m ode is None:
        foo_interface_m ode = mode
        else:
        raise "foo_interface_ mode may only be set once"

        #--- File your_module.py: ---
        import config
        if config.foo_inte rface_mode is None:
        raise "foo_interface_ mode has not been set"
        elif config.foo_inte rface_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)

        Comment

        • Jacek Generowicz

          #5
          Re: Parametrized module import

          Heather Coppersmith <me@privacy.net > writes:
          [color=blue]
          > Upon import, a module's "top level" code is executed,[/color]

          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 ...
          [color=blue]
          > 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_configuratio n_module
          > configure_mysel f( )
          > i_am_configured = True[/color]

          .... 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.

          Comment

          • Jacek Generowicz

            #6
            Re: Parametrized module import

            Oliver Fromme <olli@haluter.f romme.com> writes:
            [color=blue]
            > 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_m ode = None
            > def set_foo_interfa ce_mode (mode):
            > if foo_interface_m ode is None:
            > foo_interface_m ode = mode
            > else:
            > raise "foo_interface_ mode may only be set once"[/color]

            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 "Configurin g ..."
            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.

            Comment

            • george young

              #7
              Re: Parametrized module import

              On 08 Jul 2004 09:43:31 +0200
              Jacek Generowicz <jacek.generowi cz@cern.ch> threw this fish to the penguins:
              [color=blue]
              > 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?[/color]

              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)

              Comment

              • Jacek Generowicz

                #8
                Re: Parametrized module import

                george young <gry@ll.mit.edu > writes:
                [color=blue]
                > You might look at the way pygtk does it. I haven't peeked inside,[/color]

                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"

                ...
                [color=blue]
                > 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[/color]

                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.

                Comment

                • anton muhin

                  #9
                  Re: Parametrized module import

                  Jacek Generowicz wrote:[color=blue]
                  > 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?
                  >[/color]

                  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.doSome thing()

                  Of course, this solution might not fit your needs.

                  regards,
                  anton.

                  Comment

                  • Jacek Generowicz

                    #10
                    Re: Parametrized module import

                    anton muhin <antonmuhin@ram bler.ru> writes:
                    [color=blue]
                    > Of course, this solution might not fit your needs.[/color]

                    In this case, I am afraid that it does not.

                    Comment

                    • Heather Coppersmith

                      #11
                      Re: Parametrized module import

                      On 08 Jul 2004 14:22:25 +0200,
                      Jacek Generowicz <jacek.generowi cz@cern.ch> wrote:
                      [color=blue]
                      > Heather Coppersmith <me@privacy.net > writes:[color=green]
                      >> Upon import, a module's "top level" code is executed,[/color][/color]
                      [color=blue]
                      > 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 ...[/color]
                      [color=blue][color=green]
                      >> 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_configuratio n_module
                      >> configure_mysel f( )
                      >> i_am_configured = True[/color][/color]
                      [color=blue]
                      > ... so the first branch will _never_ get executed.[/color]
                      [color=blue]
                      > 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.[/color]

                      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

                      Comment

                      • John Lenton

                        #12
                        Re: Parametrized module import

                        On 08 Jul 2004 16:28:21 +0200, Jacek Generowicz
                        <jacek.generowi cz@cern.ch> wrote:[color=blue]
                        >
                        > 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.[/color]

                        How ugly is this:

                        import sys

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

                        def config(name):
                        name = str(name)
                        if name not in __mapping:
                        raise RuntimeExceptio n, "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()[i] = lambda *a, **kw: __mapping[i][__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 (jlenton@gmail. com) -- Random fortune:
                        bash: fortune: command not found

                        Comment

                        • John Lenton

                          #13
                          Re: Parametrized module import

                          On Thu, 8 Jul 2004 13:25:25 -0300, John Lenton <jlenton@gmail. com> wrote:[color=blue]
                          > raise RuntimeExceptio n, "unknown flavor " + name[/color]

                          that should've been RuntimeError, and flavour.

                          --
                          John Lenton (jlenton@gmail. com) -- Random fortune:
                          bash: fortune: command not found

                          Comment

                          • Oliver Fromme

                            #14
                            Re: Parametrized module import

                            Jacek Generowicz <jacek.generowi cz@cern.ch> wrote:[color=blue]
                            > 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.[/color]

                            I see.
                            [color=blue]
                            > 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.[/color]

                            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_m ode = 0 # default
                            def set_foo_interfa ce_mode (mode):
                            foo_interface_m ode = 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_inte rface_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)

                            Comment

                            • John Lenton

                              #15
                              Re: Parametrized module import

                              On 08 Jul 2004 16:28:21 +0200, Jacek Generowicz
                              <jacek.generowi cz@cern.ch> wrote:[color=blue]
                              >
                              > 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.[/color]

                              How ugly is this:

                              import sys

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

                              def config(name):
                              name = str(name)
                              if name not in __mapping:
                              raise RuntimeExceptio n, "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()[i] = lambda *a, **kw: __mapping[i][__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 (jlenton@gmail. com) -- Random fortune:
                              bash: fortune: command not found

                              Comment

                              Working...