Archived

This forum has been archived. Please start a new discussion on GitHub.

Python and partial Ice module inclusion (Glacier2 specifically)

Hi, I recently had trouble getting some of the ice modules to fully import into python (when working with Glacier2). I post here so that maybe if someone else has this problem it will help them, or perhaps to let the developers ponder a better solution (or tell me I'm doing something incorrectly). The example is this:

Given the Slice file:
#include <Glacier2/Session.ice>
module Test
{
	interface UserConn extends Glacier2::Session
	{
	    void enter(string name);
	};
};

And the relevant bits of a server script:
#!/usr/bin/env python
import sys, Ice

Ice.loadSlice('-I/usr/share/slice test.ice')
import Test, Glacier2

#print sys.modules['Glacier2'].__dict__.keys()

class PermissionsVerifierI(Glacier2.PermissionsVerifier):
    def checkPermissions(self, userId, password, current = None):
        return (True, "")

The server fails when trying to declare the Permissions Verifier above because Ice does not import the PermissionsVerifier if you've used a slice include in your slice file. If you comment out the loadSlice (and accompanying import Test bit) Glacier2 stuff all imports correctly and it compiles. However, since the slice file has the #import <Glacier2/Session.ice> it seems that -only- the session stuff gets imported into python (comment out the print statement to see which exactly), and even though I have the explict _python_ import of Glacier2, it does not add the PermissionsVerifier to the presumably already loaded Glacier2 module.

Heh, to reword that because it was a mouthful: Ice.loadSlice(<slice file with Glacier2/Session import>) causes an incomplete Glacier2 module in python. Even an explicit python import of Glacier2 will not load it fully. (Adding a slice import of <Glacier2/PermissionsVerifier.ice> to the slice file of DOES fix it, but since PermissionVerifier is not required for the slice definitions I am making, it seems improper to include it (and it's not obvious that that's a solution to the problem).)

This seems like a bug to me, unless I am misunderstanding how this is all supposed to work. I also have no idea if this applies to other Ice modules, but I imagine it does.

In case it's necessary: this is on a Fedora Core 3 machine running python 2.3.4 and Ice 2.1.2 (binary packages).

On a related note, it would be nice if "import Ice" would either
  1. Automatically add the path to the 'Standard Ice Slices' (Glacier2, IcePack, IceBox, et al) to the default include path used by Ice.loadSlice() (so it doesn't have to be hardcoded and explicitly specified, which is asking for potential breakage when deploying across different machines)
  2. Provide an extra "Slice" package (or a better name perhaps) that would just import/declare the standard slices when imported. (so you would do: "import Ice, Slice" at the top of your file insted of just Ice).

Comments

  • Hm, in the above example, doing the python import of Glacier2 before the Ice.loadSlice() will make it work. I didn't do this in my application because the user session stuff was actually in a separate python file and included in the main application (and hence Glacier2 was being included after the loadSlice()). E.g.:
    // server.py snippet: //
    import Ice
    #import Ice, Glacier2  (this will make it work)
    Ice.loadSlice("Foo.ice")
    import Foo, User
    ...
    
    // User.py snippet //
    import Glacier2
    ...
    class Verifier(Glacier2.PermissionsVerifier):
       ...
    

    You shouldn't have to import Glacier2 in server.py if it's not being used there, so I think the correct behavior would be make sure that when you import Glacier2 it imports fully regardless of how much has already been sort of dynamically loaded via the loadSlice() mechanism(s).
  • mes
    mes California
    Welcome to the forum.

    As you've noticed, importing any portion of a Python module causes any subsequent attempts to import the whole module to be ignored. In your example, loading test.ice causes definitions to be created in the Glacier2 module; when you later attempt to execute 'import Glacier2', the interpreter thinks the module has already been imported and ignores the request.

    This situation can occur in any non-trivial application where you are mixing dynamic and static code generation. One solution is to import the top-level module for any statically-generated Slice files prior to invoking loadSlice, which ensures that all of the module's definitions are loaded. This is the solution you mentioned: importing Glacier2 prior to calling loadSlice.

    Another option is for your user.py script to load the necessary Glacier2 Slice definitions explicitly. If the Glacier2 Slice definitions were not already statically generated for you, your script would be required to do this anyway. Calling loadSlice to load PermissionsVerifier.ice would augment the existing Glacier2 definitions created by the previous call to loadSlice. However, it's not necessary to call loadSlice and retranslate the Slice definitions. Instead, it's sufficient to do this:
    // User.py snippet //
    import Glacier2_PermissionsVerifier_ice
    import Glacier2
    ...
    class Verifier(Glacier2.PermissionsVerifier):
       ...
    
    It's questionable whether we can do anything to improve this situation without introducing other issues, but we'll give it some thought.

    Take care,
    - Mark
  • Thanks for the reply. I think at the very least, a mention in the documentation about it might be warranted. Cause, boy, that was sort of annoying to track down and it just looks like a bug (even if it technically isn't). ;)

    At any rate, it's in the forums now so someone searching with a couple of keywords will have access to the info.
  • mes
    mes California
    Agreed, we'll update the manual for the next release.

    - Mark