Skip to content

Python Support Copying application packages to a bundle

henrychi2 edited this page Apr 3, 2016 · 8 revisions

Copying application packages

Given a user-supplied function to an operation, the Python API finds the function's module by using the __module__ attribute. After determining the function's module, the following examples outline the steps used to determine what to copy into the Streams application bundle.

Example 1 - Importing a module inside a regular package

Regular packages contain __init__.py. The top-level package can contain only one path.

In this example, a.b.my_module is the function's module. It's top-level package is a.

Given the following structure:

/tmp/   <== In `sys.path`
  a/    <== package `a`
    __init__.py
    b/    <== subpackage `b`
      __init__.py
      my_module.py  <== contains user-supplied function "my_func"

a) Start a new python3 command-line session in /home/<user>

b) Importing a.b.my_module fails since /tmp is not in sys.path

>>> import a.b.my_module
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 'a'

c) Append to sys.path and try again

>>> import sys
>>> sys.path.append('/tmp')
>>> import a.b.my_module
>>> a.b.my_module
<module 'a.b.my_module' from '/tmp/a/b/my_module.py'>

d) Using the module's __name__ attribute, we know that the module belongs to a package because it contains a period.

>>> a.b.my_module.__name__
'a.b.my_module'

e) We need to determine the top-level directory of the package. We look at the __name__ string before the first period, which is a. This is the name of the package whose directory we need to copy.

>>> a.b.my_module.__name__.split('.')[0]
'a'

f) We need the path of the package so we can copy it to <applicationDirectory>/opt/python/packages in the bundle. We extract the information from the module's __path__ attribute.

>>> sys.modules['a'].__path__
['/tmp/a']

g) Result: Copy entire directory /tmp/a to <applicationDirectory>/opt/python/packages. This results in <applicationDirectory>/opt/python/packages/a.

Example 2- Importing modules inside a namespace package

Namespace packages do not contain __init__.py. Also, the top-level package can have multiple paths. For example,

Given the following structure:

test_common_namespace/
  package1/                 <== In `sys.path`
    common_namespace/
      module1.py
  package2/                 <== In `sys.path`
    common_namespace/
      module2.py

a) Start a Python command-line session in the same directory as test_common_namespace. Add package1 and package2 to sys.path.

>>> import sys
>>> sys.path.extend(['test_common_namespace/package1', 'test_common_namespace/package2'])

b) We can import both module1.py and module2.py under a common namespace.

>>> import common_namespace.module1
>>> import common_namespace.module2

c) Examine the names of the modules. The name of the top-level package for both is "common_namespace".

>>> common_namespace.module1.__name__
'common_namespace.module1'
>>> common_namespace.module2.__name__
'common_namespace.module2'

d) Even though the top-level package name is the same, we can see that they are two different locations by looking at the __path__.

>>> sys.modules['common_namespace'].__path__
_NamespacePath(['test_common_namespace/package1/common_namespace', 'test_common_namespace/package2/common_namespace'])

e) Result: Copy both test_common_namespace/package1/common_namespace and test_common_namespace/package2/common_namespace to <applicationDirectory>/opt/python/packages. This results in:

  • <applicationDirectory>/opt/python/packages/common_namespace/modulep1.py
  • <applicationDirectory>/opt/python/packages/common_namespace/modulep2.py