Python Packages and Importing¶
Python3 introduced more powerful module packaging. To support this, together with reducing module conflict, XPPython3 has structured imports in a simple consistent manner.
The Problem¶
First, consider the problem. Assume you have a utility module called
gis.py which perhaps does some geographic calculations, say calculating
Great Circle distance between two points, and determining the bearing from
one point to a second point.
You want to use your module in your plugin, so you simply:
import gis
Sadly, assume some other plugin developer also happened
to create a gis.py module. Perhaps it’s in a global plugin (under
Resources/plugins/PythonPlugins), or perhaps it’s with a Scenery Plugin
(under Custom Scenery/KSEA/plugins/PythonPlugins).
The problem is, once you’ve imported gis module, everyone gets that
same module. The fix is to use packages, such that “my” module differs from “your” module.
Our Solution¶
To support this, we import global plugins as part of the PythonPlugins package, so your
PI_MyPlugin.py is imported as the module PythonPlugins.PI_MyPlugin.
Plugin Type |
Example .py |
|---|---|
Global (user) |
Resources/plugins/PythonPlugins/PI_Abc.py |
Global (internal) |
Resources/plugsin/XPPython3/xp.py |
Aircraft |
Aircraft/Laminar Research/Baron B58/plugins/PythonPlugins/PI_Baron.py |
Scenery |
Custom Scenery/KSEA/plugins/PythonPlugins/PI_ground.py |
Now, gis.py can be uniquely identified as PythonPlugins.gis or KSEA.plugins.PythonPlugins.gis, etc.
To import modules with spaces in their name use:
import importlib
PI_Baron = importlib.import_module('Laminar Research.Baron B58.plugins.PythonPlugins.PI_Baron')
-or-, since you probably don’t need absolute imports, you can simply:
from . import PI_Baron
Resulting Namespace¶
Even better, so you don’t pollute the namespace, create a subpackage under Resources/plugins. Consider the following set of plugins:
<X-Plane>/
├─── Resources/
│ └─── plugins/
│ ├─── XPPython3/
│ │ └─── xp.py
│ |
│ └─── PythonPlugins/
│ ├─── PI_abc.py
│ ├─── abc/
│ │ └─── gis.py
│ │
│ ├─── PI_xyz.py
│ └─── xyz/
│ └─── gis.py
│
├─── Aircraft/Laminar/Baron/plugins/PythonPlugins/
│ ├─── PI_abc.py
│ └─── abc/
│ └─── gis.py
│
└─── Custom Scenery/KSEA/plugins/PythonPlugins/
├─── PI_abc.py
└─── abc/
└─── gis.py
First, any plugin can get access to the SDK and xp.py interface by using:
import XPLMGraphics
from XPPython3 import xp
Each plugin can get access to “their” copy of gis.py by loading a relative package:
from .abc import gis
A plugin could reference a different copy of gis.py by loading an absolute package:
# these are equivalent, and get the copy under Resources/plugins/PythonPlugins/abc:
import PythonPlugins.abc.gis as gis
from PythonPlugins.abc import gis
# this refers to a different 'gis'
from KSEA.plugins.PythonPlugins.abc import gis
Commonly, you’re not going to be referencing “other” plugin’s python files, but know that you can. More importantly, you won’t be accidentally importing someone else’s python files causing headaches for you.
If you have common files – for example you want all your Scenery plugins to use the same gis.py module, you have two
choices:
Put the same file under each Scenery plugin and use relative imports –
from . import gis– (which may be a maintenance issue if you want to update yourgis.pyfile.), orCreate a global package under
Resources/plugins/PythonPlugins, sayabcand place your file there. Then in each Scenery package:from PythonPlugins.abc import gis
… and you’ll all be using the exact same module.
To summarize¶
Import standard python modules as you always have:
import re
Import XPLM modules directly:
import XPLMGraphics
Import xp interaface (things under XPPython3) using packages:
from XPPython3 import xp
Use a sub-package for your utility scripts and import them using relative imports:
from .abc import utils
Within that sub-package (e.g., within utils.py) if you need to refer to another file in the same package use:
from . import another_file another_file.my_func() # or: from .another_file import my_func my_func()
Use a sub-package for your utility scripts, place it (the folder) under
Resources/plugins/PythonPluginsand import them using absolute imports from anywhere:from PythonPlugins.abc import utils
