handle missing directory

This commit is contained in:
Ondrej Samohel 2020-11-23 12:16:31 +01:00 committed by Ondřej Samohel
parent 7ad9e1bd5b
commit bcf75bf37e
No known key found for this signature in database
GPG key ID: 8A29C663C672C2B7
24 changed files with 443 additions and 105 deletions

View file

@ -6,9 +6,11 @@ import re
import logging as log
import shutil
import tempfile
from typing import Union, Callable, Dict
from typing import Union, Callable, List
from zipfile import ZipFile
from pathlib import Path
import functools
from speedcopy import copyfile
from appdirs import user_data_dir
@ -17,6 +19,125 @@ from pype.lib import PypeSettingsRegistry
from .tools import load_environments
@functools.total_ordering
class PypeVersion:
"""Class for storing information about Pype version.
Attributes:
major (int): [1].2.3-variant-client
minor (int): 1.[2].3-variant-client
subversion (int): 1.2.[3]-variant-client
variant (str): 1.2.3-[variant]-client
client (str): 1.2.3-variant-[client]
path (str): path to Pype
"""
major = 0
minor = 0
subversion = 0
variant = "production"
client = None
path = None
@property
def version(self):
"""return formatted version string."""
return self._compose_version()
@version.setter
def version(self, val):
decomposed = self._decompose_version(val)
self.major = decomposed[0]
self.minor = decomposed[1]
self.subversion = decomposed[2]
self.variant = decomposed[3]
self.client = decomposed[4]
def __init__(self, major: int = None, minor: int = None,
subversion: int = None, version: str = None,
variant: str = "production", client: str = None,
path: Path = None):
self.path = path
self._version_regex = re.compile(
r"(?P<major>\d+)\.(?P<minor>\d+)\.(?P<sub>\d+)(-?((?P<variant>staging)|(?P<client>.+))(-(?P<cli>.+))?)?") # noqa: E501
if major is None or minor is None or subversion is None:
if version is None:
raise ValueError("Need version specified in some way.")
if version:
values = self._decompose_version(version)
self.major = values[0]
self.minor = values[1]
self.subversion = values[2]
self.variant = values[3]
self.client = values[4]
else:
self.major = major
self.minor = minor
self.subversion = subversion
# variant is set only if it is "staging", otherwise "production" is
# implied and no need to mention it in version string.
if variant == "staging":
self.variant = variant
self.client = client
def _compose_version(self):
version = "{}.{}.{}".format(self.major, self.minor, self.subversion)
if self.variant == "staging":
version = "{}-{}".format(version, self.variant)
if self.client:
version = "{}-{}".format(version, self.client)
return version
def _decompose_version(self, version_string: str) -> tuple:
m = re.match(self._version_regex, version_string)
if not m:
raise ValueError(
"Cannot parse version string: {}".format(version_string))
variant = None
if m.group("variant") == "staging":
variant = "staging"
client = m.group("client") or m.group("cli")
return (int(m.group("major")), int(m.group("minor")),
int(m.group("sub")), variant, client)
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
return self.version == other.version
def __str__(self):
return self.version
def __repr__(self):
return "{}, {}: {}".format(
self.__class__.__name__, self.version, self.path)
def __hash__(self):
return hash(self.version)
def __lt__(self, other):
if self.major < other.major:
return True
if self.major <= other.major and self.minor < other.minor:
return True
if self.major <= other.major and self.minor <= other.minor and self.subversion < other.subversion:
return True
if self.major == other.major and self.minor == other.minor and \
self.subversion == other.subversion and \
self.variant == "staging":
return True
return False
class BootstrapRepos:
"""Class for bootstrapping local Pype installation.
@ -55,6 +176,22 @@ class BootstrapRepos:
else:
self.live_repo_dir = Path(Path(__file__).parent / ".." / "repos")
@staticmethod
def get_version_path_from_list(version:str, version_list:list) -> Path:
"""Get path for specific version in list of Pype versions.
Args:
version (str): Version string to look for (1.2.4-staging)
version_list (list of PypeVersion): list of version to search.
Returns:
Path: Path to given version.
"""
for v in version_list:
if str(v) == version:
return v.path
@staticmethod
def get_local_version() -> str:
"""Get version of local Pype."""
@ -162,7 +299,8 @@ class BootstrapRepos:
assert repo_files != 0, f"No repositories to include in {include_dir}"
pype_inc = 0
if include_pype:
pype_files = sum(len(files) for _, _, files in os.walk('pype'))
pype_files = sum(len(files) for _, _, files in os.walk(
include_dir.parent))
repo_inc = 48.0 / float(repo_files)
pype_inc = 48.0 / float(pype_files)
else:
@ -224,7 +362,7 @@ class BootstrapRepos:
os.environ["PYTHONPATH"] = os.pathsep.join(paths)
def find_pype(
self, pype_path: Path = None) -> Union[Dict[str, Path], None]:
self, pype_path: Path = None) -> Union[List[PypeVersion], None]:
"""Get ordered dict of detected Pype version.
Resolution order for Pype is following:
@ -265,15 +403,23 @@ class BootstrapRepos:
if not dir_to_search.exists():
return None
_pype_versions = {}
_pype_versions = []
file_pattern = re.compile(r"^pype-repositories-v(?P<version>\d+\.\d+\.\d*.+?).zip$") # noqa: E501
for file in dir_to_search.iterdir():
m = re.match(
r"^pype-repositories-v(?P<version>\d+\.\d+\.\d+).zip$",
file_pattern,
file.name)
if m:
_pype_versions[m.group("version")] = file
try:
_pype_versions.append(
PypeVersion(
version=m.group("version"), path=file))
except ValueError:
# cannot parse version string
print(m)
pass
return dict(sorted(_pype_versions.items()))
return sorted(_pype_versions)
@staticmethod
def _get_pype_from_mongo(mongo_url: str) -> Union[Path, None]:
@ -336,12 +482,10 @@ class BootstrapRepos:
# either "live" Pype repository, or multiple zip files.
versions = self.find_pype(pype_path)
if versions:
latest_version = (
list(versions.keys())[-1], list(versions.values())[-1])
self._log.info(f"found Pype zips in [ {pype_path} ].")
self._log.info(f"latest version found is [ {latest_version[0]} ]")
self._log.info(f"latest version found is [ {versions[-1]} ]")
destination = self.data_dir / latest_version[1].name
destination = self.data_dir / versions[-1].path.name
# test if destination file already exist, if so lets delete it.
# we consider path on location as authoritative place.
@ -359,7 +503,7 @@ class BootstrapRepos:
destination.parent.mkdir(parents=True)
try:
copyfile(latest_version[1].as_posix(), destination.as_posix())
copyfile(versions[-1].path.as_posix(), destination.as_posix())
except OSError:
self._log.error(
"cannot copy detected version to user data directory",

63
pype.py
View file

@ -32,6 +32,9 @@ Pype depends on connection to `MongoDB`_. You can specify MongoDB connection
string via `AVALON_MONGO` set in environment or it can be set in user
settings or via **Igniter** GUI.
Todo:
Move or remove bootstrapping environments out of the code.
.. _MongoDB:
https://www.mongodb.com/
@ -40,6 +43,7 @@ import os
import re
import sys
import traceback
from pathlib import Path
from igniter.tools import load_environments
@ -79,7 +83,6 @@ def boot():
"""
print(art)
print(">>> loading environments ...")
set_environments()
# find pype versions
bootstrap = BootstrapRepos()
@ -89,7 +92,7 @@ def boot():
use_version = None
for arg in sys.argv:
m = re.search(r"--use-version=(?P<version>\d+\.\d+\.\d+)", arg)
m = re.search(r"--use-version=(?P<version>\d+\.\d+\.\d*.+?)", arg)
if m and m.group('version'):
use_version = m.group('version')
break
@ -115,28 +118,32 @@ def boot():
import igniter
igniter.run()
if use_version in pype_versions.keys():
version_path = BootstrapRepos.get_version_path_from_list(
use_version, pype_versions)
if version_path:
# use specified
bootstrap.add_paths_from_archive(pype_versions[use_version])
use_version = pype_versions[use_version]
bootstrap.add_paths_from_archive(version_path)
else:
if use_version is not None:
print(("!!! Specified version was not found, using "
"latest available"))
# use latest
bootstrap.add_paths_from_archive(list(pype_versions.values())[-1])
use_version = list(pype_versions.keys())[-1]
version_path = pype_versions[-1].path
bootstrap.add_paths_from_archive(version_path)
use_version = str(pype_versions[-1])
os.environ["PYPE_ROOT"] = pype_versions[use_version].as_posix()
os.environ["PYPE_ROOT"] = version_path.as_posix()
else:
# run through repos and add them to sys.path and PYTHONPATH
pype_root = os.path.dirname(os.path.realpath(__file__))
local_version = bootstrap.get_local_version()
if use_version and use_version != local_version:
if use_version in pype_versions.keys():
version_path = BootstrapRepos.get_version_path_from_list(
use_version, pype_versions)
if version_path:
# use specified
bootstrap.add_paths_from_archive(pype_versions[use_version])
use_version = pype_versions[use_version]
bootstrap.add_paths_from_archive(version_path)
os.environ["PYPE_ROOT"] = pype_root
repos = os.listdir(os.path.join(pype_root, "repos"))
@ -149,6 +156,18 @@ def boot():
paths += repos
os.environ["PYTHONPATH"] = os.pathsep.join(paths)
# DEPRECATED: remove when `pype-config` dissolves into Pype for good.
# .-=-----------------------=-=. ^ .=-=--------------------------=-.
os.environ["PYPE_CONFIG"] = os.path.join(
os.environ["PYPE_ROOT"], "repos", "pype-config")
os.environ["PYPE_MODULE_ROOT"] = os.environ["PYPE_ROOT"]
# ------------------------------------------------------------------
# HARDCODED:
os.environ["AVALON_DB"] = "Avalon"
os.environ["AVALON_LABEL"] = "Pype"
os.environ["AVALON_TIMEOUT"]= "1000"
# .-=-----------------------=-=. v .=-=--------------------------=-.
# delete Pype module from cache so it is used from specific version
try:
del sys.modules["pype"]
@ -159,10 +178,17 @@ def boot():
from pype import cli
from pype.lib import terminal as t
from pype.version import __version__
print(">>> loading environments ...")
set_environments()
t.echo(f"*** Pype [{__version__}] --------------------------------------")
t.echo(">>> Using Pype from [ {} ]".format(os.path.dirname(cli.__file__)))
print_info()
info = get_info()
info.insert(0, ">>> Using Pype from [ {} ]".format(
os.path.dirname(cli.__file__)))
info_length = len(max(info, key=len))
info.insert(0, f"*** Pype [{__version__}] " + "-" * info_length)
for i in info:
t.echo(i)
try:
cli.main(obj={}, prog_name="pype")
@ -173,9 +199,8 @@ def boot():
sys.exit(1)
def print_info() -> None:
def get_info() -> list:
"""Print additional information to console."""
from pype.lib import terminal as t
from pype.lib.mongo import get_default_components
from pype.lib.log import LOG_DATABASE_NAME, LOG_COLLECTION_NAME
@ -211,10 +236,12 @@ def print_info() -> None:
infos.append((" - auth source", components["auth_db"]))
maximum = max([len(i[0]) for i in infos])
formatted = []
for info in infos:
padding = (maximum - len(info[0])) + 1
t.echo("... {}:{}[ {} ]".format(info[0], " " * padding, info[1]))
print('\n')
formatted.append(
"... {}:{}[ {} ]".format(info[0], " " * padding, info[1]))
return formatted
boot()

View file

@ -48,12 +48,16 @@ from .lib import (
# Special naming case for subprocess since its a built-in method.
from .lib import _subprocess as subprocess
# for backward compatibility with Pype 2
Logger = PypeLogger
__all__ = [
"system_settings",
"project_settings",
"environments",
"PypeLogger",
"Logger",
"Anatomy",
"config",
"execute",

View file

@ -17,10 +17,15 @@ def main(ctx):
ctx.invoke(tray)
@main.command()
@click.option("-d", "--dev", is_flag=True, help="Settings in Dev mode")
def settings(dev=False):
PypeCommands().launch_settings_gui(dev)
@main.command()
@click.option("-d", "--debug",
is_flag=True, help=("Run pype tray in debug mode"))
def tray(debug):
def tray(debug=False):
"""Launch pype tray.
Default action of pype command is to launch tray widget to control basic

View file

@ -1,7 +1,25 @@
# -*- coding: utf-8 -*-
"""Pype module API."""
from .ffmpeg_utils import ffprobe_streams
from .terminal import Terminal
from .execute import execute
from .log import PypeLogger, timeit
from .mongo import (
decompose_url,
compose_url,
get_default_components
)
from .anatomy import Anatomy
from .config import (
get_datetime_data,
load_json,
collect_json_from_path,
get_presets,
get_init_presets,
update_dict
)
from .path_tools import (
version_up,
get_version_from_path,
@ -9,6 +27,7 @@ from .path_tools import (
get_paths_from_environ,
get_ffmpeg_tool_path
)
from .ffmpeg_utils import ffprobe_streams
from .plugin_tools import filter_pyblish_plugins, source_hash
from .applications import (
ApplicationLaunchFailed,
@ -30,23 +49,8 @@ from .deprecated import (
get_avalon_database,
set_io_database
)
from .terminal import Terminal
from .anatomy import Anatomy
from .config import (
get_datetime_data,
load_json,
collect_json_from_path,
get_presets,
get_init_presets,
update_dict
)
from .execute import execute
from .log import PypeLogger
from .mongo import (
decompose_url,
compose_url,
get_default_components
)
from .user_settings import IniSettingRegistry
from .user_settings import JSONSettingRegistry
@ -104,5 +108,6 @@ __all__ = [
"get_default_components",
"IniSettingRegistry",
"JSONSettingRegistry",
"PypeSettingsRegistry"
"PypeSettingsRegistry",
"timeit"
]

View file

@ -6,11 +6,7 @@ import platform
import logging
import subprocess
import acre
import avalon.lib
from ..api import Anatomy, Logger, config
from . import Anatomy, config
from .hooks import execute_hook
from .deprecated import get_avalon_database
@ -27,6 +23,9 @@ def launch_application(project_name, asset_name, task_name, app_name):
TODO(iLLiCiT): This should be split into more parts.
"""
# `get_avalon_database` is in Pype 3 replaced with using `AvalonMongoDB`
import acre
import avalon.lib
database = get_avalon_database()
project_document = database[project_name].find_one({"type": "project"})
asset_document = database[project_name].find_one({
@ -193,7 +192,7 @@ def launch_application(project_name, asset_name, task_name, app_name):
return popen
class ApplicationAction(avalon.api.Action):
class ApplicationAction:
"""Default application launcher
This is a convenience application Action that when "config" refers to a
@ -213,7 +212,7 @@ class ApplicationAction(avalon.api.Action):
@property
def log(self):
if self._log is None:
self._log = Logger().get_logger(self.__class__.__name__)
self._log = logging.getLogger(self.__class__.__name__)
return self._log
def is_compatible(self, session):

View file

@ -3,14 +3,22 @@ import json
import re
import logging
import collections
import functools
from . import config
from avalon import io, pipeline
from ..api import config
import avalon.api
log = logging.getLogger("AvalonContext")
def with_avalon(func):
@functools.wraps(func)
def wrap_avalon(*args, **kwargs):
from avalon import api, io, pipeline
return func(*args, **kwargs)
pass
@with_avalon
def is_latest(representation):
"""Return whether the representation is from latest version
@ -37,7 +45,7 @@ def is_latest(representation):
else:
return False
@with_avalon
def any_outdated():
"""Return whether the current scene has any outdated content"""
@ -65,7 +73,7 @@ def any_outdated():
checked.add(representation)
return False
@with_avalon
def get_asset(asset_name=None):
""" Returning asset document from database by its name.
@ -91,6 +99,7 @@ def get_asset(asset_name=None):
return asset_document
@with_avalon
def get_hierarchy(asset_name=None):
"""
Obtain asset hierarchy path string from mongo db
@ -138,6 +147,7 @@ def get_hierarchy(asset_name=None):
return "/".join(hierarchy_items)
@with_avalon
def get_linked_assets(asset_entity):
"""Return linked assets for `asset_entity` from DB
@ -152,6 +162,7 @@ def get_linked_assets(asset_entity):
return inputs
@with_avalon
def get_latest_version(asset_name, subset_name, dbcon=None, project_name=None):
"""Retrieve latest version from `asset_name`, and `subset_name`.
@ -257,6 +268,7 @@ class BuildWorkfile:
return containers
@with_avalon
def build_workfile(self):
"""Prepares and load containers into workfile.
@ -396,6 +408,7 @@ class BuildWorkfile:
# Return list of loaded containers
return loaded_containers
@with_avalon
def get_build_presets(self, task_name):
""" Returns presets to build workfile for task name.
@ -654,6 +667,7 @@ class BuildWorkfile:
"containers": containers
}
@with_avalon
def _load_containers(
self, repres_by_subset_id, subsets_by_id,
profiles_per_subset_id, loaders_by_name
@ -774,6 +788,7 @@ class BuildWorkfile:
return loaded_containers
@with_avalon
def _collect_last_version_repres(self, asset_entities):
"""Collect subsets, versions and representations for asset_entities.

View file

@ -253,7 +253,7 @@ def get_presets(project=None, first_run=False):
def get_init_presets(project=None):
"""Loads content of presets.
Llike :func:`get_presets()`` but also evaluate `init.json`
Like :func:`get_presets()`` but also evaluate `init.json`
pointer to default presets.
Args:

View file

@ -1,7 +1,5 @@
import os
from avalon import io
def get_avalon_database():
"""Mongo database used in avalon's io.
@ -9,6 +7,7 @@ def get_avalon_database():
* Function is not used in pype 3.0 where was replaced with usage of
AvalonMongoDB.
"""
from avalon import io
if io._database is None:
set_io_database()
return io._database
@ -20,6 +19,7 @@ def set_io_database():
* Function is not used in pype 3.0 where was replaced with usage of
AvalonMongoDB.
"""
from avalon import io
required_keys = ["AVALON_PROJECT", "AVALON_ASSET", "AVALON_SILO"]
for key in required_keys:
os.environ[key] = os.environ.get(key, "")

View file

@ -379,3 +379,22 @@ class PypeLogger:
_mongo_logging = False
return logger
def timeit(method):
""" Decorator to print how much time function took.
For debugging.
Depends on presence of 'log' object
"""
def timed(*args, **kw):
ts = time.time()
result = method(*args, **kw)
te = time.time()
if 'log_time' in kw:
name = kw.get('log_name', method.__name__.upper())
kw['log_time'][name] = int((te - ts) * 1000)
else:
log.debug('%r %2.2f ms' % (method.__name__, (te - ts) * 1000))
print('%r %2.2f ms' % (method.__name__, (te - ts) * 1000))
return result
return timed

View file

@ -4,7 +4,7 @@ import os
import inspect
import logging
from ..api import config
from . import get_presets
log = logging.getLogger(__name__)
@ -25,7 +25,7 @@ def filter_pyblish_plugins(plugins):
host = api.current_host()
presets = config.get_presets().get('plugins', {})
presets = get_presets().get('plugins', {})
# iterate over plugins
for plugin in plugins[:]:

View file

@ -1,7 +1,14 @@
import os
from . import ftrack_server
from .ftrack_server import FtrackServer, check_ftrack_url
from .lib import BaseHandler, BaseEvent, BaseAction, ServerAction
from pype.api import system_settings
os.environ["FTRACK_SERVER"] = (
system_settings()["global"]["modules"]["Ftrack"]["ftrack_server"]
)
__all__ = (
"ftrack_server",
"FtrackServer",

View file

@ -1,7 +1,7 @@
import collections
from Qt import QtCore, QtGui
from pype.api import Logger
from pypeapp.lib.log import _bootstrap_mongo_log, LOG_COLLECTION_NAME
from pype.lib.log import _bootstrap_mongo_log, LOG_COLLECTION_NAME
log = Logger().get_logger("LogModel", "LoggingModule")

View file

@ -4,9 +4,6 @@ import os
import subprocess
import sys
from pype.lib import PypeLogger as Logger
from pype.lib import execute
class PypeCommands:
"""Class implementing commands used by Pype.
@ -14,7 +11,9 @@ class PypeCommands:
Most of its methods are called by :mod:`cli` module.
"""
@staticmethod
def launch_tray(debug):
def launch_tray(debug=False):
from pype.lib import PypeLogger as Logger
from pype.lib import execute
if debug:
execute([
sys.executable,
@ -50,6 +49,16 @@ class PypeCommands:
creationflags=detached_process
)
@staticmethod
def launch_settings_gui(dev):
from pype.lib import execute
args = [sys.executable, "-m", "pype.tools.settings"]
if dev:
args.append("--develop")
return_code = execute(args)
return return_code
def launch_eventservercli(self, args):
pass

View file

@ -4,7 +4,7 @@
"PYPE_APP_ROOT": "{PYPE_SETUP_PATH}/pypeapp",
"PYPE_MODULE_ROOT": "{PYPE_SETUP_PATH}/repos/pype",
"PYPE_PROJECT_PLUGINS": "",
"STUDIO_SOFT": "{PYP_SETUP_ROOT}/soft",
"STUDIO_SOFT": "{PYPE_SETUP_ROOT}/soft",
"FFMPEG_PATH": {
"windows": "{VIRTUAL_ENV}/localized/ffmpeg_exec/windows/bin;{PYPE_SETUP_PATH}/vendor/bin/ffmpeg_exec/windows/bin",
"darwin": "{VIRTUAL_ENV}/localized/ffmpeg_exec/darwin/bin:{PYPE_SETUP_PATH}/vendor/bin/ffmpeg_exec/darwin/bin",

View file

@ -14,8 +14,6 @@
"environment": {
"__environment_keys__": {
"global": [
"PYPE_APP_ROOT",
"PYPE_MODULE_ROOT",
"FFMPEG_PATH",
"PATH",
"PYTHONPATH",
@ -24,8 +22,6 @@
"PYBLISH_GUI"
]
},
"PYPE_APP_ROOT": "{PYPE_SETUP_PATH}/pypeapp",
"PYPE_MODULE_ROOT": "{PYPE_SETUP_PATH}/repos/pype",
"FFMPEG_PATH": {
"windows": "{VIRTUAL_ENV}/localized/ffmpeg_exec/windows/bin;{PYPE_SETUP_PATH}/vendor/bin/ffmpeg_exec/windows/bin",
"darwin": "{VIRTUAL_ENV}/localized/ffmpeg_exec/darwin/bin:{PYPE_SETUP_PATH}/vendor/bin/ffmpeg_exec/darwin/bin",
@ -33,7 +29,6 @@
},
"PATH": [
"{PYPE_CONFIG}/launchers",
"{PYPE_APP_ROOT}",
"{FFMPEG_PATH}",
"{PATH}"
],

View file

@ -102,3 +102,6 @@ def register_environment_actions():
module, str(e)
)
)
class ApplicationLaunchFailed(Exception):
pass

View file

@ -1,4 +1,4 @@
from settings import style, MainWidget
from .settings import style, MainWidget
__all__ = (

View file

@ -120,21 +120,9 @@ class TrayManager:
self.start_modules()
def _add_version_item(self):
config_file_path = os.path.join(
os.environ["PYPE_SETUP_PATH"], "pypeapp", "config.ini"
)
default_config = {}
if os.path.exists(config_file_path):
config = configparser.ConfigParser()
config.read(config_file_path)
try:
default_config = config["CLIENT"]
except Exception:
pass
subversion = default_config.get("subversion")
client_name = default_config.get("client_name")
subversion = os.environ.get("PYPE_SUBVERSION")
client_name = os.environ.get("PYPE_CLIENT")
version_string = pype.version.__version__
if subversion:
@ -224,7 +212,7 @@ class TrayManager:
"Module \"{}\" does not have attribute \"{}\"."
" Check your settings please."
).format(import_path, key))
p = os.environ["AVALON_SCHEMA"]
obj = module.tray_init(self.tray_widget, self.main_window)
name = obj.__class__.__name__
if hasattr(obj, 'tray_menu'):

@ -1 +1 @@
Subproject commit d2fcbe96efbca3676ff09a824ef9f5c61483f960
Subproject commit 3c10ad50aa1905dcd06959e08e7e0994561eb3e4

@ -1 +1 @@
Subproject commit f0298b2d0757e1ae126d740cbe08835f6a4ee5e0
Subproject commit 178f5cdd1859d079bc16094b321f8f06c1306c36

View file

@ -1,3 +1,4 @@
aiohttp
appdirs
arrow
certifi
@ -5,13 +6,16 @@ Click
clique==1.5.0
coverage
cx_Freeze
ftrack-python-api
ffmpeg-python
google-api-python-client
jsonschema
keyring
log4mongo
OpenTimelineIO
pathlib2
Pillow
pyinput
pymongo
pytest
pytest-cov
@ -28,3 +32,4 @@ recommonmark
toml
tqdm
wheel
wsrpc_aiohttp

View file

@ -41,6 +41,7 @@ buildOptions = dict(
excludes=[],
bin_includes=[],
include_files=[
"igniter",
"pype",
"repos",
"schema",

View file

@ -6,17 +6,116 @@ from pathlib import Path
import pytest
import appdirs
from igniter.bootstrap_repos import BootstrapRepos
from igniter.bootstrap_repos import PypeVersion
from pype.lib import PypeSettingsRegistry
@pytest.fixture
def fix_bootstrap(tmp_path):
def fix_bootstrap(tmp_path, pytestconfig):
bs = BootstrapRepos()
bs.live_repo_dir = Path(os.path.abspath('repos'))
bs.live_repo_dir = pytestconfig.rootpath / 'repos'
bs.data_dir = tmp_path
return bs
def test_pype_version():
v1 = PypeVersion(1, 2, 3)
assert str(v1) == "1.2.3"
v2 = PypeVersion(1, 2, 3, client="x")
assert str(v2) == "1.2.3-x"
v3 = PypeVersion(1, 2, 3, variant="staging")
assert str(v3) == "1.2.3-staging"
v4 = PypeVersion(1, 2, 3, variant="staging", client="client")
assert str(v4) == "1.2.3-staging-client"
v5 = PypeVersion(1, 2, 3, variant="foo", client="x")
assert str(v5) == "1.2.3-x"
assert v4 < v5
v6 = PypeVersion(1, 2, 3, variant="foo")
assert str(v6) == "1.2.3"
v7 = PypeVersion(2, 0, 0)
assert v1 < v7
v8 = PypeVersion(0, 1, 5)
assert v8 < v7
v9 = PypeVersion(1, 2, 4)
assert v9 > v1
v10 = PypeVersion(1, 2, 2)
assert v10 < v1
assert v5 == v2
sort_versions = [
PypeVersion(3, 2, 1),
PypeVersion(1, 2, 3),
PypeVersion(0, 0, 1),
PypeVersion(4, 8, 10),
PypeVersion(4, 8, 20),
PypeVersion(4, 8, 9),
PypeVersion(1, 2, 3, variant="staging"),
PypeVersion(1, 2, 3, client="client")
]
res = sorted(sort_versions)
assert res[0] == sort_versions[2]
assert res[1] == sort_versions[6]
assert res[2] == sort_versions[1]
assert res[-1] == sort_versions[4]
str_versions = [
"5.5.1",
"5.5.2-client",
"5.5.3-client-strange",
"5.5.4-staging",
"5.5.5-staging-client",
"5.6.3",
"5.6.3-staging"
]
res_versions = []
for v in str_versions:
res_versions.append(PypeVersion(version=v))
sorted_res_versions = sorted(res_versions)
assert str(sorted_res_versions[0]) == str_versions[0]
assert str(sorted_res_versions[-1]) == str_versions[5]
with pytest.raises(ValueError):
_ = PypeVersion()
with pytest.raises(ValueError):
_ = PypeVersion(major=1)
with pytest.raises(ValueError):
_ = PypeVersion(version="booobaa")
v11 = PypeVersion(version="4.6.7-staging-client")
assert v11.major == 4
assert v11.minor == 6
assert v11.subversion == 7
assert v11.variant == "staging"
assert v11.client == "client"
def test_get_version_path_from_list():
versions = [
PypeVersion(1, 2, 3, path=Path('/foo/bar')),
PypeVersion(3, 4, 5, variant="staging", path=Path("/bar/baz")),
PypeVersion(6, 7, 8, client="x", path=Path("boo/goo"))
]
path = BootstrapRepos.get_version_path_from_list(
"3.4.5-staging", versions)
assert path == Path("/bar/baz")
def test_install_live_repos(fix_bootstrap, printer):
rf = fix_bootstrap.install_live_repos()
sep = os.path.sep
@ -50,11 +149,20 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer):
test_versions_1 = [
"pype-repositories-v5.5.1.zip",
"pype-repositories-v5.5.2-client.zip",
"pype-repositories-v5.5.3-client-strange.zip",
"pype-repositories-v5.5.4-staging.zip",
"pype-repositories-v5.5.5-staging-client.zip",
"pype-repositories-v5.6.3.zip",
"pype-repositories-v5.6.3-staging.zip"
]
test_versions_2 = [
"pype-repositories-v7.2.6.zip",
"pype-repositories-v7.2.7-client.zip",
"pype-repositories-v7.2.8-client-strange.zip",
"pype-repositories-v7.2.9-staging.zip",
"pype-repositories-v7.2.10-staging-client.zip",
"pype-repositories-v7.0.1.zip",
]
@ -63,6 +171,10 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer):
"pype-repositories-v3.0.1.zip",
"pype-repositories-v4.1.0.zip",
"pype-repositories-v4.1.2.zip",
"pype-repositories-v3.0.1-client.zip",
"pype-repositories-v3.0.1-client-strange.zip",
"pype-repositories-v3.0.1-staging.zip",
"pype-repositories-v3.0.1-staging-client.zip",
"pype-repositories-v3.2.0.zip",
]
@ -87,7 +199,7 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer):
# we should have results as file were created
assert result is not None, "no Pype version found"
# latest item in `result` should be latest version found.
assert list(result.values())[-1] == Path(
assert result[-1].path == Path(
fix_bootstrap.data_dir / test_versions_3[3]
), "not a latest version of Pype 3"
@ -97,8 +209,8 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer):
# we should have results as file were created
assert result is not None, "no Pype version found"
# latest item in `result` should be latest version found.
assert list(result.values())[-1] == Path(
e_path / test_versions_1[1]
assert result[-1].path == Path(
e_path / test_versions_1[5]
), "not a latest version of Pype 1"
monkeypatch.delenv("PYPE_PATH", raising=False)
@ -115,12 +227,12 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer):
# we should have results as file were created
assert result is not None, "no Pype version found"
# latest item in `result` should be latest version found.
assert list(result.values())[-1] == Path(
r_path / test_versions_2[0]
assert result[-1].path == Path(
r_path / test_versions_2[4]
), "not a latest version of Pype 2"
result = fix_bootstrap.find_pype(e_path)
assert result is not None, "no Pype version found"
assert list(result.values())[-1] == Path(
e_path / test_versions_1[1]
assert result[-1].path == Path(
e_path / test_versions_1[5]
), "not a latest version of Pype 1"