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``. .. |br| raw:: html
================= ========================================================================= Plugin Type Example .py |br| Module name for importing ================= ========================================================================= Global (user) Resources/plugins/PythonPlugins/PI_Abc.py |br| PythonPlugins.PI_Abc Global (internal) Resources/plugsin/XPPython3/xp.py |br| XPPython3.xp Aircraft Aircraft/Laminar Research/Baron B58/plugins/PythonPlugins/PI_Baron.py |br| Laminar Research.Baron B58.plugins.PythonPlugins.PI_Baron Scenery Custom Scenery/KSEA/plugins/PythonPlugins/PI_ground.py |br| KSEA.plugins.PythonPlugins.PI_ground ================= ========================================================================= 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:: / ├─── 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: 1. 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 your ``gis.py`` file.), or 2. Create a global package under ``Resources/plugins/PythonPlugins``, say ``abc`` and 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/PythonPlugins`` and import them using absolute imports from anywhere:: from PythonPlugins.abc import utils