snakeoil.demandload module

Demand load things when used.

This uses Placeholder() objects which create an actual object on first use and know how to replace themselves with that object, so there is no performance penalty after first use.

This trick is mostly transparent, but there are a few things you have to be careful with:

  • You may not bind a second name to a placeholder object. Specifically, if you demandload C{bar} in module C{foo}, you may not C{from foo import bar} in a third module. The placeholder object does not “know” it gets imported, so this does not trigger the demandload: C{bar} in the third module is the placeholder object. When that placeholder gets used it replaces itself with the actual module in C{foo} but not in the third module. Because this is normally unwanted (it introduces a small performance hit) the placeholder object will raise an exception if it detects this. But if the demandload gets triggered before the third module is imported you do not get that exception, so you have to be careful not to import or otherwise pass around the placeholder object without triggering it.

  • You may not demandload more than one level of lookups. Specifically, demandload(“os.path”) is not allowed- this would require a “os” fake object in the local scope, one which would have a “path” fake object pushed into the os object. This is effectively not much of a limitation; you can instead just lazyload ‘path’ directly via demandload(“os:path”).

  • Not all operations on the placeholder object trigger demandload. The most common problem is that C{except ExceptionClass} does not work if C{ExceptionClass} is a placeholder. C{except module.ExceptionClass} with C{module} a placeholder does work. You can normally avoid this by always demandloading the module, not something in it. Another similar case is that C{isinstance Class} or C{issubclass Class} does not work for the initial call since the proper class hasn’t replaced the placeholder until after the call. So the first call will always return False with subsequent calls working as expected. The previously mentioned workaround of demandloading the module works in this case as well.

snakeoil.demandload.demand_compile_regexp(name, *args, **kwargs)[source]

Demandloaded version of re.compile().

Extra arguments are passed unchanged to re.compile().

Parameters:

name – the name of the compiled re object in that scope.

snakeoil.demandload.demandload(*imports, **kwargs)[source]

Import modules into the caller’s global namespace when each is first used.

Other args are strings listing module names. names are handled like this:

foo            import foo
foo@bar        import foo as bar
foo:bar        from foo import bar
foo:bar,quux   from foo import bar, quux
foo.bar:quux   from foo.bar import quux
foo:baz@quux   from foo import baz as quux