diff --git a/common/ayon_common/distribution/__init__.py b/common/ayon_common/distribution/__init__.py index 66df634a2..0fd00380e 100644 --- a/common/ayon_common/distribution/__init__.py +++ b/common/ayon_common/distribution/__init__.py @@ -4,6 +4,8 @@ ) from .control import AYONDistribution from .utils import ( + get_addons_dir, + get_dependencies_dir, show_missing_permissions, show_blocked_auto_update, show_missing_bundle_information, @@ -18,6 +20,8 @@ "AYONDistribution", + "get_addons_dir", + "get_dependencies_dir", "show_missing_permissions", "show_blocked_auto_update", "show_missing_bundle_information", diff --git a/common/ayon_common/distribution/control.py b/common/ayon_common/distribution/control.py index 1a764483b..149fe0caf 100644 --- a/common/ayon_common/distribution/control.py +++ b/common/ayon_common/distribution/control.py @@ -2542,38 +2542,38 @@ def get_sys_paths(self) -> list[str]: output.append(runtime_dir) return output - def get_python_paths(self) -> list[str]: + def get_python_paths(self) -> tuple[list[str], Optional[str]]: """Get all paths to python packages that should be added to python. These paths lead to addon directories and python dependencies in dependency package. Returns: - List[str]: Paths that should be added to 'sys.path' and - 'PYTHONPATH'. + tuple[list[str], Optional[str]]: Paths that should be added + to 'sys.path' and 'PYTHONPATH'. """ - output = [] + addon_paths = [] for item in self.get_addon_dist_items(): dist_item = item["dist_item"] if dist_item.state != UpdateState.UPDATED: continue target_dirpath = dist_item.target_dirpath if target_dirpath and os.path.exists(target_dirpath): - output.append(target_dirpath) + addon_paths.append(target_dirpath) - output.extend(self._get_dev_sys_paths()) + addon_paths.extend(self._get_dev_sys_paths()) + dependencies_dir = None dependency_dist_item = self.get_dependency_dist_item() if dependency_dist_item is not None: - dependencies_dir = None target_dirpath = dependency_dist_item.target_dirpath if target_dirpath: dependencies_dir = os.path.join(target_dirpath, "dependencies") - if dependencies_dir and os.path.exists(dependencies_dir): - output.append(dependencies_dir) - return output + if not dependencies_dir or not os.path.exists(dependencies_dir): + dependencies_dir = None + return addon_paths, dependencies_dir def _get_dev_sys_paths(self) -> list[str]: output = [] diff --git a/start.py b/start.py index 9fabde3b8..d89ce8950 100644 --- a/start.py +++ b/start.py @@ -83,6 +83,7 @@ import traceback import subprocess from contextlib import contextmanager +from pathlib import Path from urllib.parse import urlencode, urlparse, parse_qs from version import __version__ @@ -377,6 +378,8 @@ def _print(message: str): from ayon_common.distribution import ( # noqa E402 AYONDistribution, BundleNotFoundError, + get_addons_dir, + get_dependencies_dir, show_missing_bundle_information, show_blocked_auto_update, show_missing_permissions, @@ -798,17 +801,44 @@ def _start_distribution(): os.environ["AYON_BUNDLE_NAME"] = project_bundle_name os.environ["AYON_STUDIO_BUNDLE_NAME"] = studio_bundle_name - # TODO probably remove paths to other addons? - python_paths = [ - path - for path in os.getenv("PYTHONPATH", "").split(os.pathsep) - if path - ] + addon_paths, dep_package_path = distribution.get_python_paths() + if dep_package_path: + sys.path.insert(0, dep_package_path) + # Remove any path leading to addons or dependecy packages directory + # - makes sure that any addon in PYTHONPATH is removed, addons from + # current bundle are added below. + # - also make sure to keep order of dependency package if there is any + # already in PYTHONPATH + addons_dir = Path(get_addons_dir()) + dependencies_dir = Path(get_dependencies_dir()) + python_paths = [] + idx = 0 + for path in os.getenv("PYTHONPATH", "").split(os.pathsep): + if not path: + continue + + p_path = Path(path) + # Ignore addons directories + if p_path.is_relative_to(addons_dir): + continue + + # Use current dependencies dir if is set otherwise skip it + if p_path.is_relative_to(dependencies_dir): + if not dep_package_path: + continue + # Unset 'dep_package_path' to not append it again when this loop + # is over + path, dep_package_path = dep_package_path, None + + python_paths.append(path) + idx += 1 + + if dep_package_path: + python_paths.append(dep_package_path) - for path in distribution.get_python_paths(): + for path in addon_paths: sys.path.insert(0, path) - if path not in python_paths: - python_paths.append(path) + python_paths.insert(0, path) for path in distribution.get_sys_paths(): sys.path.insert(0, path)