Blender Kitsu: Fix Gazu Module out of sync #119
@ -1,165 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
@ -1,64 +0,0 @@
|
||||
from . import client as raw
|
||||
from . import cache
|
||||
from . import helpers
|
||||
|
||||
from . import asset
|
||||
from . import casting
|
||||
from . import context
|
||||
from . import entity
|
||||
from . import edit
|
||||
from . import files
|
||||
from . import project
|
||||
from . import person
|
||||
from . import shot
|
||||
from . import sync
|
||||
from . import task
|
||||
from . import user
|
||||
from . import playlist
|
||||
|
||||
from .exception import AuthFailedException, ParameterException
|
||||
from .__version__ import __version__
|
||||
|
||||
|
||||
def get_host(client=raw.default_client):
|
||||
return raw.get_host(client=client)
|
||||
|
||||
|
||||
def set_host(url, client=raw.default_client):
|
||||
raw.set_host(url, client=client)
|
||||
|
||||
|
||||
def log_in(email, password, client=raw.default_client):
|
||||
tokens = {}
|
||||
try:
|
||||
tokens = raw.post(
|
||||
"auth/login", {"email": email, "password": password}, client=client
|
||||
)
|
||||
except ParameterException:
|
||||
pass
|
||||
|
||||
if not tokens or (
|
||||
"login" in tokens and tokens.get("login", False) == False
|
||||
):
|
||||
raise AuthFailedException
|
||||
else:
|
||||
raw.set_tokens(tokens, client=client)
|
||||
return tokens
|
||||
|
||||
|
||||
def log_out(client=raw.default_client):
|
||||
tokens = {}
|
||||
try:
|
||||
raw.get("auth/logout", client=client)
|
||||
except ParameterException:
|
||||
pass
|
||||
raw.set_tokens(tokens, client=client)
|
||||
return tokens
|
||||
|
||||
|
||||
def get_event_host(client=raw.default_client):
|
||||
return raw.get_event_host(client=client)
|
||||
|
||||
|
||||
def set_event_host(url, client=raw.default_client):
|
||||
raw.set_event_host(url, client=client)
|
@ -1 +0,0 @@
|
||||
__version__ = "0.8.30"
|
@ -1,530 +0,0 @@
|
||||
from .helpers import normalize_model_parameter
|
||||
|
||||
from . import client as raw
|
||||
from . import project as gazu_project
|
||||
|
||||
from .sorting import sort_by_name
|
||||
|
||||
from .cache import cache
|
||||
|
||||
from .shot import get_episode
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
@cache
|
||||
def all_assets_for_open_projects(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Assets stored in the database for open projects.
|
||||
"""
|
||||
all_assets = []
|
||||
for project in gazu_project.all_open_projects(client=default):
|
||||
all_assets.extend(all_assets_for_project(project, client))
|
||||
return sort_by_name(all_assets)
|
||||
|
||||
|
||||
@cache
|
||||
def all_assets_for_project(project, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
|
||||
Returns:
|
||||
list: Assets stored in the database for given project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
|
||||
if project is None:
|
||||
return sort_by_name(raw.fetch_all("assets/all", client=client))
|
||||
else:
|
||||
path = "projects/%s/assets" % project["id"]
|
||||
return sort_by_name(raw.fetch_all(path, client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def all_assets_for_episode(episode, client=default):
|
||||
"""
|
||||
Args:
|
||||
episode (str / dict): The episode dict or the episode ID.
|
||||
|
||||
Returns:
|
||||
list: Assets stored in the database for given episode.
|
||||
"""
|
||||
episode = normalize_model_parameter(episode)
|
||||
|
||||
return sort_by_name(
|
||||
raw.fetch_all("assets", {"source_id": episode["id"]}, client=client)
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def all_assets_for_shot(shot, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
|
||||
Returns:
|
||||
list: Assets stored in the database for given shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
path = "shots/%s/assets" % shot["id"]
|
||||
return sort_by_name(raw.fetch_all(path, client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def all_assets_for_project_and_type(project, asset_type, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
asset_type (str / dict): The asset type dict or the asset type ID.
|
||||
|
||||
Returns:
|
||||
list: Assets stored in the database for given project and asset type.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
asset_type = normalize_model_parameter(asset_type)
|
||||
|
||||
project_id = project["id"]
|
||||
asset_type_id = asset_type["id"]
|
||||
path = "projects/{project_id}/asset-types/{asset_type_id}/assets"
|
||||
path = path.format(project_id=project_id, asset_type_id=asset_type_id)
|
||||
|
||||
assets = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(assets)
|
||||
|
||||
|
||||
@cache
|
||||
def get_asset_by_name(project, name, asset_type=None, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
name (str): The asset name
|
||||
asset_type (str / dict): Asset type dict or ID (optional).
|
||||
|
||||
Returns:
|
||||
dict: Asset matching given name for given project and asset type.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
|
||||
path = "assets/all"
|
||||
if asset_type is None:
|
||||
params = {"project_id": project["id"], "name": name}
|
||||
else:
|
||||
asset_type = normalize_model_parameter(asset_type)
|
||||
params = {
|
||||
"project_id": project["id"],
|
||||
"name": name,
|
||||
"entity_type_id": asset_type["id"],
|
||||
}
|
||||
return raw.fetch_first(path, params, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_asset(asset_id, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset_id (str): Id of claimed asset.
|
||||
|
||||
Returns:
|
||||
dict: Asset matching given ID.
|
||||
"""
|
||||
return raw.fetch_one("assets", asset_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_asset_url(asset, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset (str / dict): The asset dict or the asset ID.
|
||||
|
||||
Returns:
|
||||
url (str): Web url associated to the given asset
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
asset = get_asset(asset["id"])
|
||||
project = gazu_project.get_project(asset["project_id"])
|
||||
episode_id = "main"
|
||||
path = "{host}/productions/{project_id}/"
|
||||
if project["production_type"] != "tvshow":
|
||||
path += "assets/{asset_id}/"
|
||||
else:
|
||||
path += "episodes/{episode_id}/assets/{asset_id}/"
|
||||
if len(asset["episode_id"]) > 0:
|
||||
episode_id = asset["episode_id"]
|
||||
|
||||
return path.format(
|
||||
host=raw.get_api_url_from_host(),
|
||||
project_id=asset["project_id"],
|
||||
asset_id=asset["id"],
|
||||
episode_id=episode_id,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def new_asset(
|
||||
project,
|
||||
asset_type,
|
||||
name,
|
||||
description="",
|
||||
extra_data={},
|
||||
episode=None,
|
||||
client=default,
|
||||
):
|
||||
"""
|
||||
Create a new asset in the database for given project and asset type.
|
||||
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
asset_type (str / dict): The asset type dict or the asset type ID.
|
||||
name (str): Asset name.
|
||||
description (str): Additional information.
|
||||
extra_data (dict): Free field to add any kind of metadata.
|
||||
episode (str / dict): The episode this asset is linked to.
|
||||
|
||||
Returns:
|
||||
dict: Created asset.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
asset_type = normalize_model_parameter(asset_type)
|
||||
episode = normalize_model_parameter(episode)
|
||||
|
||||
data = {"name": name, "description": description, "data": extra_data}
|
||||
|
||||
if episode is not None:
|
||||
data["episode_id"] = episode["id"]
|
||||
|
||||
asset = get_asset_by_name(project, name, asset_type, client=client)
|
||||
if asset is None:
|
||||
asset = raw.post(
|
||||
"data/projects/%s/asset-types/%s/assets/new"
|
||||
% (project["id"], asset_type["id"]),
|
||||
data,
|
||||
client=client,
|
||||
)
|
||||
return asset
|
||||
|
||||
|
||||
def update_asset(asset, client=default):
|
||||
"""
|
||||
Save given asset data into the API. It assumes that the asset already
|
||||
exists.
|
||||
|
||||
Args:
|
||||
asset (dict): Asset to save.
|
||||
"""
|
||||
if "episode_id" in asset:
|
||||
asset["source_id"] = asset["episode_id"]
|
||||
return raw.put("data/entities/%s" % asset["id"], asset, client=client)
|
||||
|
||||
|
||||
def update_asset_data(asset, data={}, client=default):
|
||||
"""
|
||||
Update the metadata for the provided asset. Keys that are not provided are
|
||||
not changed.
|
||||
|
||||
Args:
|
||||
asset (dict / ID): The asset dict or ID to save in database.
|
||||
data (dict): Free field to set metadata of any kind.
|
||||
|
||||
Returns:
|
||||
dict: Updated asset.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
current_asset = get_asset(asset["id"], client=client)
|
||||
updated_asset = {"id": current_asset["id"], "data": current_asset["data"]}
|
||||
updated_asset["data"].update(data)
|
||||
return update_asset(updated_asset, client=client)
|
||||
|
||||
|
||||
def remove_asset(asset, force=False, client=default):
|
||||
"""
|
||||
Remove given asset from database.
|
||||
|
||||
Args:
|
||||
asset (dict): Asset to remove.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
path = "data/assets/%s" % asset["id"]
|
||||
params = {}
|
||||
if force:
|
||||
params = {"force": "true"}
|
||||
return raw.delete(path, params, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def all_asset_types(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Asset types stored in the database.
|
||||
"""
|
||||
return sort_by_name(raw.fetch_all("asset-types", client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def all_asset_types_for_project(project, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
|
||||
Returns:
|
||||
list: Asset types from assets listed in given project.
|
||||
"""
|
||||
path = "projects/%s/asset-types" % project["id"]
|
||||
return sort_by_name(raw.fetch_all(path, client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def all_asset_types_for_shot(shot, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
|
||||
Returns:
|
||||
list: Asset types from assets casted in given shot.
|
||||
"""
|
||||
path = "shots/%s/asset-types" % shot["id"]
|
||||
return sort_by_name(raw.fetch_all(path, client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def get_asset_type(asset_type_id, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset_type_id (str/): Id of claimed asset type.
|
||||
|
||||
Returns:
|
||||
dict: Asset Type matching given ID.
|
||||
"""
|
||||
asset_type_id = normalize_model_parameter(asset_type_id)["id"]
|
||||
return raw.fetch_one("asset-types", asset_type_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_asset_type_by_name(name, client=default):
|
||||
"""
|
||||
Args:
|
||||
name (str): name of asset type.
|
||||
|
||||
Returns:
|
||||
dict: Asset Type matching given name.
|
||||
"""
|
||||
return raw.fetch_first("entity-types", {"name": name}, client=client)
|
||||
|
||||
|
||||
def new_asset_type(name, client=default):
|
||||
"""
|
||||
Create a new asset type in the database.
|
||||
|
||||
Args:
|
||||
name (str): The name of asset type to create.
|
||||
|
||||
Returns:
|
||||
(dict): Created asset type.
|
||||
"""
|
||||
data = {"name": name}
|
||||
asset_type = raw.fetch_first("entity-types", {"name": name}, client=client)
|
||||
if asset_type is None:
|
||||
asset_type = raw.create("entity-types", data, client=client)
|
||||
return asset_type
|
||||
|
||||
|
||||
def update_asset_type(asset_type, client=default):
|
||||
"""
|
||||
Save given asset type data into the API. It assumes that the asset type
|
||||
already exists.
|
||||
|
||||
Args:
|
||||
asset_type (dict): Asset Type to save.
|
||||
"""
|
||||
data = {"name": asset_type["name"]}
|
||||
path = "data/asset-types/%s" % asset_type["id"]
|
||||
return raw.put(path, data, client=client)
|
||||
|
||||
|
||||
def remove_asset_type(asset_type, client=default):
|
||||
"""
|
||||
Remove given asset type from database.
|
||||
|
||||
Args:
|
||||
asset_type (dict): Asset type to remove.
|
||||
"""
|
||||
asset_type = normalize_model_parameter(asset_type)
|
||||
path = "data/asset-types/%s" % asset_type["id"]
|
||||
return raw.delete(path, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_asset_instance(asset_instance_id, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset_instance_id (str): Id of claimed asset instance.
|
||||
|
||||
Returns:
|
||||
dict: Asset Instance matching given ID.
|
||||
"""
|
||||
return raw.fetch_one("asset-instances", asset_instance_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def all_shot_asset_instances_for_asset(asset, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset (str / dict): The asset dict or the asset ID.
|
||||
|
||||
Returns:
|
||||
list: Asset instances existing for a given asset.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
path = "assets/%s/shot-asset-instances" % asset["id"]
|
||||
return raw.fetch_all(path, client=client)
|
||||
|
||||
|
||||
def enable_asset_instance(asset_instance, client=default):
|
||||
"""
|
||||
Set active flag of given asset instance to True.
|
||||
|
||||
Args:
|
||||
asset_instance (str / dict): The asset instance dict or ID.
|
||||
"""
|
||||
asset_instance = normalize_model_parameter(asset_instance)
|
||||
data = {"active": True}
|
||||
path = "asset-instances/%s" % asset_instance["id"]
|
||||
return raw.put(path, data, client=client)
|
||||
|
||||
|
||||
def disable_asset_instance(asset_instance, client=default):
|
||||
"""
|
||||
Set active flag of given asset instance to False.
|
||||
|
||||
Args:
|
||||
asset_instance (str / dict): The asset instance dict or ID.
|
||||
"""
|
||||
asset_instance = normalize_model_parameter(asset_instance)
|
||||
data = {"active": False}
|
||||
path = "asset-instances/%s" % asset_instance["id"]
|
||||
return raw.put(path, data, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def all_scene_asset_instances_for_asset(asset, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset (str / dict): The asset dict or the asset ID.
|
||||
|
||||
Returns:
|
||||
list: Scene asset instances existing for a given asset.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
path = "assets/%s/scene-asset-instances" % asset["id"]
|
||||
return raw.fetch_all(path, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def all_asset_instances_for_shot(shot, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
|
||||
Returns:
|
||||
list: Asset instances existing for a given shot.
|
||||
"""
|
||||
path = "shots/%s/asset-instances" % shot["id"]
|
||||
return raw.fetch_all(path, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def all_asset_instances_for_asset(asset, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset (str / dict): The asset dict or the asset ID.
|
||||
|
||||
Returns:
|
||||
list: Asset instances existing for a given asset.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
path = "assets/%s/asset-asset-instances" % asset["id"]
|
||||
return raw.fetch_all(path, client=client)
|
||||
|
||||
|
||||
def new_asset_asset_instance(
|
||||
asset, asset_to_instantiate, description="", client=default
|
||||
):
|
||||
"""
|
||||
Creates a new asset instance for given asset. The instance number is
|
||||
automatically generated (increment highest number).
|
||||
|
||||
Args:
|
||||
asset (str / dict): The asset dict or the shot ID.
|
||||
asset_instance (str / dict): The asset instance dict or ID.
|
||||
description (str): Additional information (optional)
|
||||
|
||||
Returns:
|
||||
(dict): Created asset instance.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
asset_to_instantiate = normalize_model_parameter(asset_to_instantiate)
|
||||
data = {
|
||||
"asset_to_instantiate_id": asset_to_instantiate["id"],
|
||||
"description": description,
|
||||
}
|
||||
return raw.post(
|
||||
"data/assets/%s/asset-asset-instances" % asset["id"],
|
||||
data,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def import_assets_with_csv(project, csv_file_path, client=default):
|
||||
project = normalize_model_parameter(project)
|
||||
return raw.upload(
|
||||
"import/csv/projects/%s/assets" % project["id"],
|
||||
csv_file_path,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def export_assets_with_csv(
|
||||
project, csv_file_path, episode=None, assigned_to=None, client=default
|
||||
):
|
||||
project = normalize_model_parameter(project)
|
||||
episode = normalize_model_parameter(episode)
|
||||
assigned_to = normalize_model_parameter(assigned_to)
|
||||
params = {}
|
||||
if episode:
|
||||
params["episode_id"] = episode["id"]
|
||||
if assigned_to:
|
||||
params["assigned_to"] = assigned_to["id"]
|
||||
return raw.download(
|
||||
"export/csv/projects/%s/assets.csv" % project["id"],
|
||||
csv_file_path,
|
||||
params=params,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_episode_from_asset(asset, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset (dict): The asset dict.
|
||||
|
||||
Returns:
|
||||
dict: Episode which is parent of given asset.
|
||||
"""
|
||||
if asset["parent_id"] is None:
|
||||
return None
|
||||
else:
|
||||
return get_episode(asset["parent_id"], client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_asset_type_from_asset(asset, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset (dict): The asset dict.
|
||||
|
||||
Returns:
|
||||
dict: Asset type which is the type of given asset.
|
||||
"""
|
||||
return get_asset_type(asset["entity_type_id"], client=client)
|
@ -1,215 +0,0 @@
|
||||
import copy
|
||||
import datetime
|
||||
import json
|
||||
|
||||
from functools import wraps
|
||||
|
||||
cache_settings = {"enabled": False}
|
||||
cached_functions = []
|
||||
|
||||
|
||||
def enable():
|
||||
"""
|
||||
Enable caching on all decorated functions.
|
||||
"""
|
||||
cache_settings["enabled"] = True
|
||||
return cache_settings["enabled"]
|
||||
|
||||
|
||||
def disable():
|
||||
"""
|
||||
Disable caching on all decorated functions.
|
||||
"""
|
||||
cache_settings["enabled"] = False
|
||||
return cache_settings["enabled"]
|
||||
|
||||
|
||||
def clear_all():
|
||||
"""
|
||||
Clear all cached functions.
|
||||
"""
|
||||
for function in cached_functions:
|
||||
function.clear_cache()
|
||||
|
||||
|
||||
def remove_oldest_entry(memo, maxsize):
|
||||
"""
|
||||
Remove the oldest cache entry if there is more value stored than allowed.
|
||||
|
||||
Params:
|
||||
memo (dict): Cache used for function memoization.
|
||||
maxsize (int): Maximum number of entries for the cache.
|
||||
|
||||
Returns:
|
||||
Oldest entry for given cache.
|
||||
"""
|
||||
oldest_entry = None
|
||||
if maxsize > 0 and len(memo) > maxsize:
|
||||
oldest_entry_key = list(memo.keys())[0]
|
||||
for entry_key in memo.keys():
|
||||
oldest_date = memo[oldest_entry_key]["date_accessed"]
|
||||
if memo[entry_key]["date_accessed"] < oldest_date:
|
||||
oldest_entry_key = entry_key
|
||||
memo.pop(oldest_entry_key)
|
||||
return oldest_entry
|
||||
|
||||
|
||||
def get_cache_key(args, kwargs):
|
||||
"""
|
||||
Serialize arguments to get a cache key. It will be used to store function
|
||||
results.
|
||||
|
||||
Returns:
|
||||
str: generated key
|
||||
"""
|
||||
kwargscopy = kwargs.copy()
|
||||
if "client" in kwargscopy:
|
||||
kwargscopy["client"] = kwargscopy["client"].host
|
||||
if len(args) == 0 and len(kwargscopy) == 0:
|
||||
return ""
|
||||
elif len(args) == 0:
|
||||
return json.dumps(kwargscopy)
|
||||
elif len(kwargscopy.keys()) == 0:
|
||||
return json.dumps(args)
|
||||
else:
|
||||
return json.dumps([args, kwargscopy])
|
||||
|
||||
|
||||
def insert_value(function, cache_store, args, kwargs):
|
||||
"""
|
||||
Serialize function call arguments and store function result in given cache
|
||||
store.
|
||||
|
||||
Args:
|
||||
function (func): The function to cache value for.
|
||||
cache_store (dict): The cache which will contain the value to cache.
|
||||
args, kwargs: The arguments for which a cache must be set.
|
||||
|
||||
Returns:
|
||||
The cached value.
|
||||
"""
|
||||
returned_value = function(*args, **kwargs)
|
||||
key = get_cache_key(args, kwargs)
|
||||
cache_store[key] = {
|
||||
"date_accessed": datetime.datetime.now(),
|
||||
"value": returned_value,
|
||||
}
|
||||
return get_value(cache_store, key)
|
||||
|
||||
|
||||
def get_value(cache_store, key):
|
||||
"""
|
||||
It generates a deep copy of the requested value. It's needed because if a
|
||||
pointer is returned, the value can be changed. Which leads to a modified
|
||||
cache and unexpected results.
|
||||
|
||||
Returns:
|
||||
Value matching given key inside given cache store
|
||||
"""
|
||||
value = cache_store[key]["value"]
|
||||
return copy.deepcopy(value)
|
||||
|
||||
|
||||
def is_cache_enabled(state):
|
||||
"""
|
||||
Args:
|
||||
state: The state describing the cache state.
|
||||
|
||||
Returns:
|
||||
True if cache is enabled for given state.
|
||||
"""
|
||||
return cache_settings["enabled"] and state["enabled"]
|
||||
|
||||
|
||||
def is_cache_expired(memo, state, key):
|
||||
"""
|
||||
Check if cache is expired (outdated) for given wrapper state and cache key.
|
||||
|
||||
Args:
|
||||
memo (dict): The function cache
|
||||
state (dict): The parameters of the cache (enabled, expire, maxsize)
|
||||
key: The key to check
|
||||
|
||||
Returns:
|
||||
True if cache value is expired.
|
||||
|
||||
"""
|
||||
date = memo[key]["date_accessed"]
|
||||
expire = state["expire"]
|
||||
date_to_check = date + datetime.timedelta(seconds=expire)
|
||||
return expire > 0 and date_to_check < datetime.datetime.now()
|
||||
|
||||
|
||||
def cache(function, maxsize=300, expire=120):
|
||||
"""
|
||||
Decorator that generate cache wrapper and that adds cache feature to
|
||||
target function. A max cache size and and expiration time (in seconds) can
|
||||
be set too.
|
||||
|
||||
Args:
|
||||
function (func): Decorated function:
|
||||
maxsize: Number of value stored in cache (300 by default).
|
||||
expire: Time to live in seconds of stored value (disabled by default)
|
||||
"""
|
||||
cache_store = {}
|
||||
state = {"enabled": True, "expire": expire, "maxsize": maxsize}
|
||||
|
||||
statistics = {"hits": 0, "misses": 0, "expired_hits": 0}
|
||||
|
||||
def clear_cache():
|
||||
cache_store.clear()
|
||||
|
||||
def get_cache_infos():
|
||||
size = {"current_size": len(cache_store)}
|
||||
infos = {}
|
||||
for d in [state, statistics, size]:
|
||||
infos.update(d)
|
||||
|
||||
return infos
|
||||
|
||||
def set_expire(new_expire):
|
||||
state["expire"] = new_expire
|
||||
|
||||
def set_max_size(maxsize):
|
||||
state["maxsize"] = maxsize
|
||||
|
||||
def enable_cache():
|
||||
state["enabled"] = True
|
||||
|
||||
def disable_cache():
|
||||
state["enabled"] = False
|
||||
|
||||
@wraps(function)
|
||||
def wrapper(*args, **kwargs):
|
||||
|
||||
if is_cache_enabled(state):
|
||||
key = get_cache_key(args, kwargs)
|
||||
|
||||
if key in cache_store:
|
||||
if is_cache_expired(cache_store, state, key):
|
||||
statistics["expired_hits"] += 1
|
||||
return insert_value(function, cache_store, args, kwargs)
|
||||
else:
|
||||
statistics["hits"] += 1
|
||||
return get_value(cache_store, key)
|
||||
|
||||
else:
|
||||
statistics["misses"] += 1
|
||||
returned_value = insert_value(
|
||||
function, cache_store, args, kwargs
|
||||
)
|
||||
remove_oldest_entry(cache_store, state["maxsize"])
|
||||
return returned_value
|
||||
|
||||
else:
|
||||
return function(*args, **kwargs)
|
||||
|
||||
wrapper.set_cache_expire = set_expire
|
||||
wrapper.set_cache_max_size = set_max_size
|
||||
wrapper.clear_cache = clear_cache
|
||||
wrapper.enable_cache = enable_cache
|
||||
wrapper.disable_cache = disable_cache
|
||||
wrapper.get_cache_infos = get_cache_infos
|
||||
|
||||
cached_functions.append(wrapper)
|
||||
return wrapper
|
@ -1,153 +0,0 @@
|
||||
from . import client as raw
|
||||
|
||||
from .helpers import normalize_model_parameter
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
def update_shot_casting(project, shot, casting, client=default):
|
||||
"""
|
||||
Change casting of given shot with given casting (list of asset ids displayed
|
||||
into the shot).
|
||||
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
casting (dict): The casting description.
|
||||
Ex: `casting = [{"asset_id": "asset-1", "nb_occurences": 3}]`
|
||||
|
||||
Returns:
|
||||
dict: Related shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
project = normalize_model_parameter(project)
|
||||
path = "data/projects/%s/entities/%s/casting" % (project["id"], shot["id"])
|
||||
return raw.put(path, casting, client=client)
|
||||
|
||||
|
||||
def update_asset_casting(project, asset, casting, client=default):
|
||||
"""
|
||||
Change casting of given asset with given casting (list of asset ids
|
||||
displayed into the asset).
|
||||
|
||||
Args:
|
||||
asset (str / dict): The asset dict or the asset ID.
|
||||
casting (dict): The casting description.
|
||||
Ex: `casting = [{"asset_id": "asset-1", "nb_occurences": 3}]`
|
||||
|
||||
Returns:
|
||||
dict: Related asset.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
project = normalize_model_parameter(project)
|
||||
path = "data/projects/%s/entities/%s/casting" % (
|
||||
project["id"],
|
||||
asset["id"],
|
||||
)
|
||||
return raw.put(path, casting, client=client)
|
||||
|
||||
|
||||
def get_asset_type_casting(project, asset_type, client=default):
|
||||
"""
|
||||
Return casting for given asset_type.
|
||||
`casting = {
|
||||
"asset-id": [{"asset_id": "asset-1", "nb_occurences": 3}],
|
||||
...
|
||||
}
|
||||
`
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
asset_type (str / dict): The asset_type dict or the asset_type ID.
|
||||
|
||||
Returns:
|
||||
dict: Casting of the given asset_type.
|
||||
"""
|
||||
|
||||
project = normalize_model_parameter(project)
|
||||
asset_type = normalize_model_parameter(asset_type)
|
||||
path = "/data/projects/%s/asset-types/%s/casting" % (
|
||||
project["id"],
|
||||
asset_type["id"],
|
||||
)
|
||||
return raw.get(path, client=client)
|
||||
|
||||
|
||||
def get_sequence_casting(sequence, client=default):
|
||||
"""
|
||||
Return casting for given sequence.
|
||||
`casting = {
|
||||
"shot-id": [{"asset_id": "asset-1", "nb_occurences": 3}]},
|
||||
...
|
||||
}
|
||||
`
|
||||
Args:
|
||||
sequence (dict): The sequence dict
|
||||
|
||||
Returns:
|
||||
dict: Casting of the given sequence.
|
||||
"""
|
||||
path = "/data/projects/%s/sequences/%s/casting" % (
|
||||
sequence["project_id"],
|
||||
sequence["id"],
|
||||
)
|
||||
return raw.get(path, client=client)
|
||||
|
||||
|
||||
def get_shot_casting(shot, client=default):
|
||||
"""
|
||||
Return casting for given shot.
|
||||
`[{"asset_id": "asset-1", "nb_occurences": 3}]}`
|
||||
Args:
|
||||
shot (dict): The shot dict
|
||||
|
||||
Returns:
|
||||
dict: Casting of the given shot.
|
||||
"""
|
||||
path = "/data/projects/%s/entities/%s/casting" % (
|
||||
shot["project_id"],
|
||||
shot["id"],
|
||||
)
|
||||
return raw.get(path, client=client)
|
||||
|
||||
|
||||
def get_asset_casting(asset, client=default):
|
||||
"""
|
||||
Return casting for given asset.
|
||||
`[{"asset_id": "asset-1", "nb_occurences": 3}]}`
|
||||
Args:
|
||||
asset (dict): The asset dict
|
||||
|
||||
Returns:
|
||||
dict: Casting for given asset.
|
||||
"""
|
||||
path = "/data/projects/%s/entities/%s/casting" % (
|
||||
asset["project_id"],
|
||||
asset["id"],
|
||||
)
|
||||
return raw.get(path, client=client)
|
||||
|
||||
|
||||
def get_asset_cast_in(asset, client=default):
|
||||
"""
|
||||
Return entity list where given asset is casted.
|
||||
Args:
|
||||
asset (dict): The asset dict
|
||||
|
||||
Returns:
|
||||
dict: Entity list where given asset is casted.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
path = "/data/assets/%s/cast-in" % asset["id"]
|
||||
return raw.get(path, client=client)
|
||||
|
||||
|
||||
def all_entity_links_for_project(project, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (dict): The project
|
||||
|
||||
Returns:
|
||||
dict: Entity links for given project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
path = "/data/projects/%s/entity-links" % project["id"]
|
||||
return raw.get(path, client=client)
|
@ -1,488 +0,0 @@
|
||||
import sys
|
||||
import functools
|
||||
import json
|
||||
import shutil
|
||||
import urllib
|
||||
|
||||
from .encoder import CustomJSONEncoder
|
||||
|
||||
if sys.version_info[0] == 3:
|
||||
from json import JSONDecodeError
|
||||
else:
|
||||
JSONDecodeError = ValueError
|
||||
|
||||
from .__version__ import __version__
|
||||
|
||||
from .exception import (
|
||||
TooBigFileException,
|
||||
NotAuthenticatedException,
|
||||
NotAllowedException,
|
||||
MethodNotAllowedException,
|
||||
ParameterException,
|
||||
RouteNotFoundException,
|
||||
ServerErrorException,
|
||||
UploadFailedException,
|
||||
)
|
||||
|
||||
|
||||
class KitsuClient(object):
|
||||
def __init__(self, host, ssl_verify=True, cert=None):
|
||||
self.tokens = {"access_token": "", "refresh_token": ""}
|
||||
self.session = requests.Session()
|
||||
self.session.verify = ssl_verify
|
||||
self.session.cert = cert
|
||||
self.host = host
|
||||
self.event_host = host
|
||||
|
||||
|
||||
def create_client(host, ssl_verify=True, cert=None):
|
||||
return KitsuClient(host, ssl_verify, cert=None)
|
||||
|
||||
|
||||
default_client = None
|
||||
try:
|
||||
import requests
|
||||
|
||||
# Little hack to allow json encoder to manage dates.
|
||||
requests.models.complexjson.dumps = functools.partial(
|
||||
json.dumps, cls=CustomJSONEncoder
|
||||
)
|
||||
# Set host to "" otherwise requests.Session() takes a long time during Blender startup
|
||||
# Whyever that is.
|
||||
# host = "http://gazu.change.serverhost/api"
|
||||
host = ""
|
||||
default_client = create_client(host)
|
||||
except Exception:
|
||||
print("Warning, running in setup mode!")
|
||||
|
||||
|
||||
def host_is_up(client=default_client):
|
||||
"""
|
||||
Returns:
|
||||
True if the host is up.
|
||||
"""
|
||||
try:
|
||||
response = client.session.head(client.host)
|
||||
except Exception:
|
||||
return False
|
||||
return response.status_code == 200
|
||||
|
||||
|
||||
def host_is_valid(client=default_client):
|
||||
"""
|
||||
Check if the host is valid by simulating a fake login.
|
||||
Returns:
|
||||
True if the host is valid.
|
||||
"""
|
||||
if not host_is_up(client):
|
||||
return False
|
||||
try:
|
||||
post("auth/login", {"email": "", "password": ""})
|
||||
except Exception as exc:
|
||||
return type(exc) == ParameterException
|
||||
|
||||
|
||||
def get_host(client=default_client):
|
||||
"""
|
||||
Returns:
|
||||
Host on which requests are sent.
|
||||
"""
|
||||
return client.host
|
||||
|
||||
|
||||
def get_api_url_from_host(client=default_client):
|
||||
"""
|
||||
Returns:
|
||||
Zou url, retrieved from host.
|
||||
"""
|
||||
return client.host[:-4]
|
||||
|
||||
|
||||
def set_host(new_host, client=default_client):
|
||||
"""
|
||||
Returns:
|
||||
Set currently configured host on which requests are sent.
|
||||
"""
|
||||
client.host = new_host
|
||||
return client.host
|
||||
|
||||
|
||||
def get_event_host(client=default_client):
|
||||
"""
|
||||
Returns:
|
||||
Host on which listening for events.
|
||||
"""
|
||||
return client.event_host or client.host
|
||||
|
||||
|
||||
def set_event_host(new_host, client=default_client):
|
||||
"""
|
||||
Returns:
|
||||
Set currently configured host on which listening for events.
|
||||
"""
|
||||
client.event_host = new_host
|
||||
return client.event_host
|
||||
|
||||
|
||||
def set_tokens(new_tokens, client=default_client):
|
||||
"""
|
||||
Store authentication token to reuse them for all requests.
|
||||
|
||||
Args:
|
||||
new_tokens (dict): Tokens to use for authentication.
|
||||
"""
|
||||
client.tokens = new_tokens
|
||||
return client.tokens
|
||||
|
||||
|
||||
def make_auth_header(client=default_client):
|
||||
"""
|
||||
Returns:
|
||||
Headers required to authenticate.
|
||||
"""
|
||||
headers = {"User-Agent": "CGWire Gazu %s" % __version__}
|
||||
if "access_token" in client.tokens:
|
||||
headers["Authorization"] = "Bearer %s" % client.tokens["access_token"]
|
||||
return headers
|
||||
|
||||
|
||||
def url_path_join(*items):
|
||||
"""
|
||||
Make it easier to build url path by joining every arguments with a '/'
|
||||
character.
|
||||
|
||||
Args:
|
||||
items (list): Path elements
|
||||
"""
|
||||
return "/".join([item.lstrip("/").rstrip("/") for item in items])
|
||||
|
||||
|
||||
def get_full_url(path, client=default_client):
|
||||
"""
|
||||
Args:
|
||||
path (str): The path to integrate to host url.
|
||||
|
||||
Returns:
|
||||
The result of joining configured host url with given path.
|
||||
"""
|
||||
return url_path_join(get_host(client), path)
|
||||
|
||||
|
||||
def build_path_with_params(path, params):
|
||||
"""
|
||||
Add params to a path using urllib encoding
|
||||
|
||||
Args:
|
||||
path (str): The url base path
|
||||
params (dict): The parameters to add as a dict
|
||||
|
||||
Returns:
|
||||
str: the builded path
|
||||
"""
|
||||
if not params:
|
||||
return path
|
||||
|
||||
if hasattr(urllib, "urlencode"):
|
||||
path = "%s?%s" % (path, urllib.urlencode(params))
|
||||
else:
|
||||
path = "%s?%s" % (path, urllib.parse.urlencode(params))
|
||||
return path
|
||||
|
||||
|
||||
def get(path, json_response=True, params=None, client=default_client):
|
||||
"""
|
||||
Run a get request toward given path for configured host.
|
||||
|
||||
Returns:
|
||||
The request result.
|
||||
"""
|
||||
path = build_path_with_params(path, params)
|
||||
response = client.session.get(
|
||||
get_full_url(path, client=client),
|
||||
headers=make_auth_header(client=client),
|
||||
)
|
||||
check_status(response, path)
|
||||
|
||||
if json_response:
|
||||
return response.json()
|
||||
else:
|
||||
return response.text
|
||||
|
||||
|
||||
def post(path, data, client=default_client):
|
||||
"""
|
||||
Run a post request toward given path for configured host.
|
||||
|
||||
Returns:
|
||||
The request result.
|
||||
"""
|
||||
response = client.session.post(
|
||||
get_full_url(path, client),
|
||||
json=data,
|
||||
headers=make_auth_header(client=client),
|
||||
)
|
||||
check_status(response, path)
|
||||
try:
|
||||
result = response.json()
|
||||
except JSONDecodeError:
|
||||
print(response.text)
|
||||
raise
|
||||
return result
|
||||
|
||||
|
||||
def put(path, data, client=default_client):
|
||||
"""
|
||||
Run a put request toward given path for configured host.
|
||||
|
||||
Returns:
|
||||
The request result.
|
||||
"""
|
||||
response = client.session.put(
|
||||
get_full_url(path, client),
|
||||
json=data,
|
||||
headers=make_auth_header(client=client),
|
||||
)
|
||||
check_status(response, path)
|
||||
return response.json()
|
||||
|
||||
|
||||
def delete(path, params=None, client=default_client):
|
||||
"""
|
||||
Run a delete request toward given path for configured host.
|
||||
|
||||
Returns:
|
||||
The request result.
|
||||
"""
|
||||
path = build_path_with_params(path, params)
|
||||
|
||||
response = client.session.delete(
|
||||
get_full_url(path, client), headers=make_auth_header(client=client)
|
||||
)
|
||||
check_status(response, path)
|
||||
return response.text
|
||||
|
||||
|
||||
def check_status(request, path):
|
||||
"""
|
||||
Raise an exception related to status code, if the status code does not
|
||||
match a success code. Print error message when it's relevant.
|
||||
|
||||
Args:
|
||||
request (Request): The request to validate.
|
||||
|
||||
Returns:
|
||||
int: Status code
|
||||
|
||||
Raises:
|
||||
ParameterException: when 400 response occurs
|
||||
NotAuthenticatedException: when 401 response occurs
|
||||
RouteNotFoundException: when 404 response occurs
|
||||
NotAllowedException: when 403 response occurs
|
||||
MethodNotAllowedException: when 405 response occurs
|
||||
TooBigFileException: when 413 response occurs
|
||||
ServerErrorException: when 500 response occurs
|
||||
"""
|
||||
status_code = request.status_code
|
||||
if status_code == 404:
|
||||
raise RouteNotFoundException(path)
|
||||
elif status_code == 403:
|
||||
raise NotAllowedException(path)
|
||||
elif status_code == 400:
|
||||
text = request.json().get("message", "No additional information")
|
||||
raise ParameterException(path, text)
|
||||
elif status_code == 405:
|
||||
raise MethodNotAllowedException(path)
|
||||
elif status_code == 413:
|
||||
raise TooBigFileException(
|
||||
"%s: You send a too big file. "
|
||||
"Change your proxy configuration to allow bigger files." % path
|
||||
)
|
||||
elif status_code in [401, 422]:
|
||||
raise NotAuthenticatedException(path)
|
||||
elif status_code in [500, 502]:
|
||||
try:
|
||||
stacktrace = request.json().get(
|
||||
"stacktrace", "No stacktrace sent by the server"
|
||||
)
|
||||
message = request.json().get(
|
||||
"message", "No message sent by the server"
|
||||
)
|
||||
print("A server error occured!\n")
|
||||
print("Server stacktrace:\n%s" % stacktrace)
|
||||
print("Error message:\n%s\n" % message)
|
||||
except Exception:
|
||||
print(request.text)
|
||||
raise ServerErrorException(path)
|
||||
return status_code
|
||||
|
||||
|
||||
def fetch_all(path, params=None, client=default_client):
|
||||
"""
|
||||
Args:
|
||||
path (str): The path for which we want to retrieve all entries.
|
||||
|
||||
Returns:
|
||||
list: All entries stored in database for a given model. You can add a
|
||||
filter to the model name like this: "tasks?project_id=project-id"
|
||||
"""
|
||||
return get(url_path_join("data", path), params=params, client=client)
|
||||
|
||||
|
||||
def fetch_first(path, params=None, client=default_client):
|
||||
"""
|
||||
Args:
|
||||
path (str): The path for which we want to retrieve the first entry.
|
||||
|
||||
Returns:
|
||||
dict: The first entry for which a model is required.
|
||||
"""
|
||||
entries = get(url_path_join("data", path), params=params, client=client)
|
||||
if len(entries) > 0:
|
||||
return entries[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def fetch_one(model_name, id, client=default_client):
|
||||
"""
|
||||
Function dedicated at targeting routes that returns a single model
|
||||
instance.
|
||||
|
||||
Args:
|
||||
model_name (str): Model type name.
|
||||
id (str): Model instance ID.
|
||||
|
||||
Returns:
|
||||
dict: The model instance matching id and model name.
|
||||
"""
|
||||
return get(url_path_join("data", model_name, id), client=client)
|
||||
|
||||
|
||||
def create(model_name, data, client=default_client):
|
||||
"""
|
||||
Create an entry for given model and data.
|
||||
|
||||
Args:
|
||||
model (str): The model type involved
|
||||
data (str): The data to use for creation
|
||||
|
||||
Returns:
|
||||
dict: Created entry
|
||||
"""
|
||||
return post(url_path_join("data", model_name), data, client=client)
|
||||
|
||||
|
||||
def update(model_name, model_id, data, client=default_client):
|
||||
"""
|
||||
Update an entry for given model, id and data.
|
||||
|
||||
Args:
|
||||
model (str): The model type involved
|
||||
id (str): The target model id
|
||||
data (dict): The data to update
|
||||
|
||||
Returns:
|
||||
dict: Updated entry
|
||||
"""
|
||||
return put(
|
||||
url_path_join("data", model_name, model_id), data, client=client
|
||||
)
|
||||
|
||||
|
||||
def upload(path, file_path, data={}, extra_files=[], client=default_client):
|
||||
"""
|
||||
Upload file located at *file_path* to given url *path*.
|
||||
|
||||
Args:
|
||||
path (str): The url path to upload file.
|
||||
file_path (str): The file location on the hard drive.
|
||||
|
||||
Returns:
|
||||
Response: Request response object.
|
||||
"""
|
||||
url = get_full_url(path, client)
|
||||
files = _build_file_dict(file_path, extra_files)
|
||||
response = client.session.post(
|
||||
url, data=data, headers=make_auth_header(client=client), files=files
|
||||
)
|
||||
check_status(response, path)
|
||||
try:
|
||||
result = response.json()
|
||||
except JSONDecodeError:
|
||||
print(response.text)
|
||||
raise
|
||||
if "message" in result:
|
||||
raise UploadFailedException(result["message"])
|
||||
return result
|
||||
|
||||
|
||||
def _build_file_dict(file_path, extra_files):
|
||||
files = {"file": open(file_path, "rb")}
|
||||
i = 2
|
||||
for file_path in extra_files:
|
||||
files["file-%s" % i] = open(file_path, "rb")
|
||||
i += 1
|
||||
return files
|
||||
|
||||
|
||||
def download(path, file_path, params=None, client=default_client):
|
||||
"""
|
||||
Download file located at *file_path* to given url *path*.
|
||||
|
||||
Args:
|
||||
path (str): The url path to download file from.
|
||||
file_path (str): The location to store the file on the hard drive.
|
||||
|
||||
Returns:
|
||||
Response: Request response object.
|
||||
|
||||
"""
|
||||
path = build_path_with_params(path, params)
|
||||
with client.session.get(
|
||||
get_full_url(path, client),
|
||||
headers=make_auth_header(client=client),
|
||||
stream=True,
|
||||
) as response:
|
||||
with open(file_path, "wb") as target_file:
|
||||
shutil.copyfileobj(response.raw, target_file)
|
||||
return response
|
||||
|
||||
|
||||
def get_file_data_from_url(url, full=False, client=default_client):
|
||||
"""
|
||||
Return data found at given url.
|
||||
"""
|
||||
if not full:
|
||||
url = get_full_url(url)
|
||||
response = requests.get(
|
||||
url,
|
||||
stream=True,
|
||||
headers=make_auth_header(client=client),
|
||||
)
|
||||
check_status(response, url)
|
||||
return response.content
|
||||
|
||||
|
||||
def import_data(model_name, data, client=default_client):
|
||||
"""
|
||||
Args:
|
||||
model_name (str): The data model to import
|
||||
data (dict): The data to import
|
||||
"""
|
||||
return post("/import/kitsu/%s" % model_name, data, client=client)
|
||||
|
||||
|
||||
def get_api_version(client=default_client):
|
||||
"""
|
||||
Returns:
|
||||
str: Current version of the API.
|
||||
"""
|
||||
return get("", client=client)["version"]
|
||||
|
||||
|
||||
def get_current_user(client=default_client):
|
||||
"""
|
||||
Returns:
|
||||
dict: User database information for user linked to auth tokens.
|
||||
"""
|
||||
return get("auth/authenticated", client=client)["user"]
|
@ -1,151 +0,0 @@
|
||||
from . import user as gazu_user
|
||||
from . import project as gazu_project
|
||||
from . import asset as gazu_asset
|
||||
from . import task as gazu_task
|
||||
from . import shot as gazu_shot
|
||||
from . import scene as gazu_scene
|
||||
|
||||
|
||||
def all_open_projects(user_context=False):
|
||||
"""
|
||||
Return the list of projects for which the user has a task.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_open_projects()
|
||||
else:
|
||||
return gazu_project.all_open_projects()
|
||||
|
||||
|
||||
def all_assets_for_project(project, user_context=False):
|
||||
"""
|
||||
Return the list of assets for which the user has a task.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_assets_for_project(project)
|
||||
else:
|
||||
return gazu_asset.all_assets_for_project(project)
|
||||
|
||||
|
||||
def all_asset_types_for_project(project, user_context=False):
|
||||
"""
|
||||
Return the list of asset types for which the user has a task.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_asset_types_for_project(project)
|
||||
else:
|
||||
return gazu_asset.all_asset_types_for_project(project)
|
||||
|
||||
|
||||
def all_assets_for_asset_type_and_project(
|
||||
project, asset_type, user_context=False
|
||||
):
|
||||
"""
|
||||
Return the list of assets for given project and asset_type and for which
|
||||
the user has a task.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_assets_for_asset_type_and_project(
|
||||
project, asset_type
|
||||
)
|
||||
else:
|
||||
return gazu_asset.all_assets_for_project_and_type(project, asset_type)
|
||||
|
||||
|
||||
def all_task_types_for_asset(asset, user_context=False):
|
||||
"""
|
||||
Return the list of tasks for given asset and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_task_types_for_asset(asset)
|
||||
else:
|
||||
return gazu_task.all_task_types_for_asset(asset)
|
||||
|
||||
|
||||
def all_task_types_for_shot(shot, user_context=False):
|
||||
"""
|
||||
Return the list of tasks for given shot and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_task_types_for_shot(shot)
|
||||
else:
|
||||
return gazu_task.all_task_types_for_shot(shot)
|
||||
|
||||
|
||||
def all_task_types_for_scene(scene, user_context=False):
|
||||
"""
|
||||
Return the list of tasks for given scene and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_task_types_for_scene(scene)
|
||||
else:
|
||||
return gazu_task.all_task_types_for_scene(scene)
|
||||
|
||||
|
||||
def all_task_types_for_sequence(sequence, user_context=False):
|
||||
"""
|
||||
Return the list of tasks for given sequence and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_task_types_for_sequence(sequence)
|
||||
else:
|
||||
return gazu_task.all_task_types_for_sequence(sequence)
|
||||
|
||||
|
||||
def all_sequences_for_project(project, user_context=False):
|
||||
"""
|
||||
Return the list of sequences for given project and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_sequences_for_project(project)
|
||||
else:
|
||||
return gazu_shot.all_sequences_for_project(project)
|
||||
|
||||
|
||||
def all_scenes_for_project(project, user_context=False):
|
||||
"""
|
||||
Return the list of scenes for given project and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_scenes_for_project(project)
|
||||
else:
|
||||
return gazu_scene.all_scenes(project)
|
||||
|
||||
|
||||
def all_shots_for_sequence(sequence, user_context=False):
|
||||
"""
|
||||
Return the list of shots for given sequence and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_shots_for_sequence(sequence)
|
||||
else:
|
||||
return gazu_shot.all_shots_for_sequence(sequence)
|
||||
|
||||
|
||||
def all_scenes_for_sequence(sequence, user_context=False):
|
||||
"""
|
||||
Return the list of scenes for given sequence and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_scenes_for_sequence(sequence)
|
||||
else:
|
||||
return gazu_scene.all_scenes_for_sequence(sequence)
|
||||
|
||||
|
||||
def all_sequences_for_episode(episode, user_context=False):
|
||||
"""
|
||||
Return the list of shots for given sequence and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_sequences_for_episode(episode)
|
||||
else:
|
||||
return gazu_shot.all_sequences_for_episode(episode)
|
||||
|
||||
|
||||
def all_episodes_for_project(project, user_context=False):
|
||||
"""
|
||||
Return the list of shots for given sequence and current user.
|
||||
"""
|
||||
if user_context:
|
||||
return gazu_user.all_episodes_for_project(project)
|
||||
else:
|
||||
return gazu_shot.all_episodes_for_project(project)
|
@ -1,52 +0,0 @@
|
||||
import gazu
|
||||
from . import client as raw
|
||||
from .sorting import sort_by_name
|
||||
|
||||
from .cache import cache
|
||||
from .helpers import normalize_model_parameter
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
# TODO Contribute these to gazu module or remove, this file is temporary
|
||||
|
||||
|
||||
@cache
|
||||
def get_all_edits_with_tasks(relations=False, client=default):
|
||||
"""
|
||||
Retrieve all edit entries.
|
||||
"""
|
||||
params = {}
|
||||
if relations:
|
||||
params = {"relations": "true"}
|
||||
path = "edits/with-tasks"
|
||||
edits_with_tasks = raw.fetch_all(path, params, client=client)
|
||||
return sort_by_name(edits_with_tasks)
|
||||
|
||||
|
||||
@cache
|
||||
def get_all_previews_for_edit(edit, client=default):
|
||||
"""
|
||||
Args:
|
||||
episode (str / dict): The episode dict or the episode ID.
|
||||
|
||||
Returns:
|
||||
list: Shots which are children of given episode.
|
||||
"""
|
||||
edit = normalize_model_parameter(edit)
|
||||
edit_previews = raw.fetch_all(f"edits/{edit['id']}/preview-files", client=client)
|
||||
for key in [key for key in enumerate(edit_previews.keys())]:
|
||||
return edit_previews[key[1]]
|
||||
|
||||
|
||||
@cache
|
||||
def all_tasks_for_edit(edit, relations=False, client=default):
|
||||
"""
|
||||
Retrieve all tasks directly linked to given edit.
|
||||
"""
|
||||
edit = normalize_model_parameter(edit)
|
||||
params = {}
|
||||
if relations:
|
||||
params = {"relations": "true"}
|
||||
path = "edits/%s/tasks" % edit["id"]
|
||||
tasks = raw.fetch_all(path, params, client=client)
|
||||
return sort_by_name(tasks)
|
@ -1,15 +0,0 @@
|
||||
import json
|
||||
import datetime
|
||||
|
||||
|
||||
class CustomJSONEncoder(json.JSONEncoder):
|
||||
"""
|
||||
This JSON encoder is here to handle dates which are not handled by default.
|
||||
The standard does not want to assum how you handle dates.
|
||||
"""
|
||||
|
||||
def default(self, obj):
|
||||
if isinstance(obj, datetime.datetime):
|
||||
return obj.isoformat()
|
||||
|
||||
return json.JSONEncoder.default(self, obj)
|
@ -1,119 +0,0 @@
|
||||
from . import client as raw
|
||||
|
||||
from .cache import cache
|
||||
from .sorting import sort_by_name
|
||||
from .helpers import normalize_model_parameter
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
@cache
|
||||
def all_entities(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Retrieve all entities
|
||||
"""
|
||||
return raw.fetch_all("entities", client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def all_entity_types(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Entity types listed in database.
|
||||
"""
|
||||
return sort_by_name(raw.fetch_all("entity-types", client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def get_entity(entity_id, client=default):
|
||||
"""
|
||||
Args:
|
||||
id (str, client=default): ID of claimed entity.
|
||||
|
||||
Returns:
|
||||
dict: Retrieve entity matching given ID (It can be an entity of any
|
||||
kind: asset, shot, sequence or episode).
|
||||
"""
|
||||
return raw.fetch_one("entities", entity_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_entity_by_name(entity_name, client=default):
|
||||
"""
|
||||
Args:
|
||||
name (str, client=default): The name of the claimed entity.
|
||||
|
||||
Returns:
|
||||
Retrieve entity matching given name.
|
||||
"""
|
||||
return raw.fetch_first("entities", {"name": entity_name}, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_entity_type(entity_type_id, client=default):
|
||||
"""
|
||||
Args:
|
||||
id (str, client=default): ID of claimed entity type.
|
||||
, client=client
|
||||
Returns:
|
||||
Retrieve entity type matching given ID (It can be an entity type of any
|
||||
kind).
|
||||
"""
|
||||
return raw.fetch_one("entity-types", entity_type_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_entity_type_by_name(entity_type_name, client=default):
|
||||
"""
|
||||
Args:
|
||||
name (str, client=default): The name of the claimed entity type
|
||||
|
||||
Returns:
|
||||
Retrieve entity type matching given name.
|
||||
"""
|
||||
return raw.fetch_first(
|
||||
"entity-types", {"name": entity_type_name}, client=client
|
||||
)
|
||||
|
||||
|
||||
def new_entity_type(name, client=default):
|
||||
"""
|
||||
Creates an entity type with the given name.
|
||||
|
||||
Args:
|
||||
name (str, client=default): The name of the entity type
|
||||
|
||||
Returns:
|
||||
dict: The created entity type
|
||||
"""
|
||||
data = {"name": name}
|
||||
return raw.create("entity-types", data, client=client)
|
||||
|
||||
|
||||
def remove_entity(entity, force=False, client=default):
|
||||
"""
|
||||
Remove given entity from database.
|
||||
|
||||
Args:
|
||||
entity (dict): Entity to remove.
|
||||
"""
|
||||
entity = normalize_model_parameter(entity)
|
||||
path = "data/entities/%s" % entity["id"]
|
||||
params = {}
|
||||
if force:
|
||||
params = {"force": "true"}
|
||||
return raw.delete(path, params, client=client)
|
||||
|
||||
def update_entity(entity, client=default):
|
||||
"""
|
||||
Save given shot data into the API. Metadata are fully replaced by the ones
|
||||
set on given shot.
|
||||
|
||||
Args:
|
||||
Entity (dict): The shot dict to update.
|
||||
|
||||
Returns:
|
||||
dict: Updated entity.
|
||||
"""
|
||||
return raw.put(f"data/entities/{entity['id']}", entity, client=client)
|
@ -1,93 +0,0 @@
|
||||
class HostException(Exception):
|
||||
"""
|
||||
Error raised when host is not valid.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AuthFailedException(Exception):
|
||||
"""
|
||||
Error raised when user credentials are wrong.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class NotAuthenticatedException(Exception):
|
||||
"""
|
||||
Error raised when a 401 error (not authenticated) is sent by the API.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class NotAllowedException(Exception):
|
||||
"""
|
||||
Error raised when a 403 error (not authorized) is sent by the API.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class MethodNotAllowedException(Exception):
|
||||
"""
|
||||
Error raised when a 405 error (method not handled) is sent by the API.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class RouteNotFoundException(Exception):
|
||||
"""
|
||||
Error raised when a 404 error (not found) is sent by the API.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ServerErrorException(Exception):
|
||||
"""
|
||||
Error raised when a 500 error (server error) is sent by the API.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ParameterException(Exception):
|
||||
"""
|
||||
Error raised when a 400 error (argument error) is sent by the API.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UploadFailedException(Exception):
|
||||
"""
|
||||
Error raised when an error while uploading a file, mainly to handle cases
|
||||
where processing that occurs on the remote server fails.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TooBigFileException(Exception):
|
||||
"""
|
||||
Error raised when a 413 error (payload too big error) is sent by the API.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TaskStatusNotFound(Exception):
|
||||
"""
|
||||
Error raised when a task status is not found.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class DownloadFileException(Exception):
|
||||
"""
|
||||
Error raised when a file can't be downloaded.
|
||||
"""
|
File diff suppressed because it is too large
Load Diff
@ -1,140 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import datetime
|
||||
import shutil
|
||||
import requests
|
||||
import tempfile
|
||||
import mimetypes
|
||||
|
||||
from .exception import DownloadFileException
|
||||
|
||||
if sys.version_info[0] == 3:
|
||||
import urllib.parse as urlparse
|
||||
else:
|
||||
import urlparse
|
||||
|
||||
_UUID_RE = re.compile(
|
||||
"([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}){1}"
|
||||
)
|
||||
|
||||
|
||||
def normalize_model_parameter(model_parameter):
|
||||
"""
|
||||
Args:
|
||||
model_parameter (str / dict): The parameter to convert.
|
||||
|
||||
Returns:
|
||||
dict: If `model_parameter` is an ID (a string), it turns it into a model
|
||||
dict. If it's already a dict, the `model_parameter` is returned as it
|
||||
is. It returns None if the paramater is None.
|
||||
"""
|
||||
if model_parameter is None:
|
||||
return None
|
||||
elif isinstance(model_parameter, dict):
|
||||
return model_parameter
|
||||
else:
|
||||
try:
|
||||
id_str = str(model_parameter)
|
||||
except Exception:
|
||||
raise ValueError("Failed to cast argument to str")
|
||||
|
||||
if _UUID_RE.match(id_str):
|
||||
return {"id": id_str}
|
||||
else:
|
||||
raise ValueError("Wrong format: expected ID string or Data dict")
|
||||
|
||||
|
||||
def normalize_list_of_models_for_links(models=[]):
|
||||
"""
|
||||
Args:
|
||||
models (list): The models to convert.
|
||||
|
||||
Returns:
|
||||
list: A list of ids of the models.
|
||||
"""
|
||||
if not isinstance(models, list):
|
||||
models = [models]
|
||||
|
||||
return [normalize_model_parameter(model)["id"] for model in models]
|
||||
|
||||
|
||||
def validate_date_format(date_text):
|
||||
try:
|
||||
datetime.datetime.strptime(date_text, "%Y-%m-%dT%H:%M:%S")
|
||||
except ValueError:
|
||||
try:
|
||||
datetime.datetime.strptime(date_text, "%Y-%m-%d")
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
"Incorrect date format for %s, should be YYYY-mm-dd or YYYY-mm-ddTHH:MM:SS"
|
||||
% date_text
|
||||
)
|
||||
return date_text
|
||||
|
||||
|
||||
def sanitize_filename(filename):
|
||||
forbidden = "@|():%/,\\[]<>*?;`\n"
|
||||
return "".join(
|
||||
[c for c in filename.replace("..", "_") if c not in forbidden]
|
||||
).strip()
|
||||
|
||||
|
||||
def download_file(url, file_path=None, headers={}):
|
||||
"""
|
||||
Download file located at *file_path* to given url *url*.
|
||||
|
||||
Args:
|
||||
url (str): The url path to download file from.
|
||||
file_path (str): The location to store the file on the hard drive.
|
||||
headers (dict): The headers to pass to requests
|
||||
|
||||
Returns:
|
||||
str: The location where the file is stored.
|
||||
|
||||
"""
|
||||
with requests.get(
|
||||
url,
|
||||
headers=headers,
|
||||
stream=True,
|
||||
) as response:
|
||||
if response.ok:
|
||||
if file_path is None:
|
||||
file_path = tempfile.gettempdir()
|
||||
|
||||
if os.path.isdir(file_path):
|
||||
file_path = os.path.join(file_path, "")
|
||||
|
||||
(dir, filename) = os.path.split(file_path)
|
||||
|
||||
if not filename:
|
||||
url_parts = urlparse.urlparse(url)
|
||||
filename = url_parts.path.split("/")[-1]
|
||||
if not dir:
|
||||
dir = os.getcwd()
|
||||
|
||||
name, ext = os.path.splitext(filename)
|
||||
|
||||
if ext == "":
|
||||
if "Content-Type" in response.headers:
|
||||
guessed_ext = mimetypes.guess_extension(
|
||||
response.headers["Content-Type"]
|
||||
)
|
||||
if guessed_ext is not None:
|
||||
ext = guessed_ext
|
||||
|
||||
if name == "":
|
||||
name = "file"
|
||||
|
||||
filename = sanitize_filename(name + ext)
|
||||
|
||||
file_path = os.path.join(dir, filename)
|
||||
|
||||
with open(file_path, "wb") as target_file:
|
||||
shutil.copyfileobj(response.raw, target_file)
|
||||
return file_path
|
||||
else:
|
||||
raise DownloadFileException(
|
||||
"File (%s) can't be downloaded (%i %s)."
|
||||
% (url, response.status_code, response.reason)
|
||||
)
|
@ -1,224 +0,0 @@
|
||||
from . import client as raw
|
||||
|
||||
from .sorting import sort_by_name
|
||||
from .helpers import (
|
||||
normalize_model_parameter,
|
||||
normalize_list_of_models_for_links,
|
||||
)
|
||||
from .cache import cache
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
@cache
|
||||
def all_organisations(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Organisations listed in database.
|
||||
"""
|
||||
return sort_by_name(raw.fetch_all("organisations", client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def all_departments(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Departments listed in database.
|
||||
"""
|
||||
return sort_by_name(raw.fetch_all("departments", client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def all_persons(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Persons listed in database.
|
||||
"""
|
||||
return sort_by_name(raw.fetch_all("persons", client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def get_person(id, client=default):
|
||||
"""
|
||||
Args:
|
||||
id (str): An uuid identifying a person.
|
||||
|
||||
Returns:
|
||||
dict: Person corresponding to given id.
|
||||
"""
|
||||
return raw.fetch_one("persons", id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_person_by_desktop_login(desktop_login, client=default):
|
||||
"""
|
||||
Args:
|
||||
desktop_login (str): Login used to sign in on the desktop computer.
|
||||
|
||||
Returns:
|
||||
dict: Person corresponding to given desktop computer login.
|
||||
"""
|
||||
return raw.fetch_first(
|
||||
"persons", {"desktop_login": desktop_login}, client=client
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_person_by_email(email, client=default):
|
||||
"""
|
||||
Args:
|
||||
email (str): User's email.
|
||||
|
||||
Returns:
|
||||
dict: Person corresponding to given email.
|
||||
"""
|
||||
return raw.fetch_first("persons", {"email": email}, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_person_by_full_name(full_name, client=default):
|
||||
"""
|
||||
Args:
|
||||
full_name (str): User's full name
|
||||
|
||||
Returns:
|
||||
dict: Person corresponding to given name.
|
||||
"""
|
||||
if " " in full_name:
|
||||
first_name, last_name = full_name.lower().split(" ")
|
||||
else:
|
||||
first_name, last_name = full_name.lower().strip(), ""
|
||||
for person in all_persons():
|
||||
is_right_first_name = (
|
||||
first_name == person["first_name"].lower().strip()
|
||||
)
|
||||
is_right_last_name = (
|
||||
len(last_name) == 0 or last_name == person["last_name"].lower()
|
||||
)
|
||||
if is_right_first_name and is_right_last_name:
|
||||
return person
|
||||
return None
|
||||
|
||||
|
||||
@cache
|
||||
def get_person_url(person, client=default):
|
||||
"""
|
||||
Args:
|
||||
person (str / dict): The person dict or the person ID.
|
||||
|
||||
Returns:
|
||||
url (str): Web url associated to the given person
|
||||
"""
|
||||
person = normalize_model_parameter(person)
|
||||
path = "{host}/people/{person_id}/"
|
||||
return path.format(
|
||||
host=raw.get_api_url_from_host(client=client),
|
||||
person_id=person["id"],
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_organisation(client=default):
|
||||
"""
|
||||
Returns:
|
||||
dict: Database information for organisation linked to auth tokens.
|
||||
"""
|
||||
return raw.get("auth/authenticated", client=client)["organisation"]
|
||||
|
||||
|
||||
def new_person(
|
||||
first_name,
|
||||
last_name,
|
||||
email,
|
||||
phone="",
|
||||
role="user",
|
||||
desktop_login="",
|
||||
departments=[],
|
||||
client=default,
|
||||
):
|
||||
"""
|
||||
Create a new person based on given parameters. His/her password will is
|
||||
set automatically to default.
|
||||
|
||||
Args:
|
||||
first_name (str):
|
||||
last_name (str):
|
||||
email (str):
|
||||
phone (str):
|
||||
role (str): user, manager, admin (wich match CG artist, Supervisor
|
||||
and studio manager)
|
||||
desktop_login (str): The login the users uses to log on its computer.
|
||||
departments (list): The departments for the person.
|
||||
Returns:
|
||||
dict: Created person.
|
||||
"""
|
||||
person = get_person_by_email(email)
|
||||
if person is None:
|
||||
person = raw.post(
|
||||
"data/persons/new",
|
||||
{
|
||||
"first_name": first_name,
|
||||
"last_name": last_name,
|
||||
"email": email,
|
||||
"phone": phone,
|
||||
"role": role,
|
||||
"desktop_login": desktop_login,
|
||||
"departments": normalize_list_of_models_for_links(departments),
|
||||
},
|
||||
client=client,
|
||||
)
|
||||
return person
|
||||
|
||||
|
||||
def update_person(person, client=default):
|
||||
"""
|
||||
Update a person.
|
||||
|
||||
Args:
|
||||
person (dict): The person dict that needs to be upgraded.
|
||||
|
||||
Returns:
|
||||
dict: The updated person.
|
||||
"""
|
||||
|
||||
if "departments" in person:
|
||||
person["departments"] = normalize_list_of_models_for_links(
|
||||
person["departments"]
|
||||
)
|
||||
|
||||
person = normalize_model_parameter(person)
|
||||
return raw.put(
|
||||
"data/persons/%s" % (person["id"]),
|
||||
person,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def set_avatar(person, file_path, client=default):
|
||||
"""
|
||||
Upload picture and set it as avatar for given person.
|
||||
|
||||
Args:
|
||||
person (str / dict): The person dict or the person ID.
|
||||
file_path (str): Path where the avatar file is located on the hard
|
||||
drive.
|
||||
"""
|
||||
person = normalize_model_parameter(person)
|
||||
return raw.upload(
|
||||
"/pictures/thumbnails/persons/%s" % person["id"],
|
||||
file_path,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def get_presence_log(year, month, client=default):
|
||||
"""
|
||||
Args:
|
||||
year (int):
|
||||
month (int):
|
||||
|
||||
Returns:
|
||||
The presence log table for given month and year.
|
||||
"""
|
||||
path = "data/persons/presence-logs/%s-%s" % (year, str(month).zfill(2))
|
||||
return raw.get(path, json_response=False, client=client)
|
@ -1,153 +0,0 @@
|
||||
from . import client as raw
|
||||
|
||||
from .helpers import normalize_model_parameter
|
||||
from .sorting import sort_by_name
|
||||
|
||||
from .cache import cache
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
@cache
|
||||
def all_playlists(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: All playlists for all projects.
|
||||
"""
|
||||
return sort_by_name(raw.fetch_all("playlists", client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def all_shots_for_playlist(playlist, client=default):
|
||||
"""
|
||||
Args:
|
||||
playlist (str / dict): The playlist dict or the playlist ID.
|
||||
|
||||
Returns:
|
||||
list: All shots linked to the given playlist
|
||||
"""
|
||||
playlist = normalize_model_parameter(playlist)
|
||||
playlist = raw.fetch_one("playlists", playlist["id"], client=client)
|
||||
return sort_by_name(playlist["shots"])
|
||||
|
||||
|
||||
@cache
|
||||
def all_playlists_for_project(project, client=default, page=1):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
|
||||
Returns:
|
||||
list: All playlists for the given project
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
return sort_by_name(
|
||||
raw.fetch_all(
|
||||
"projects/%s/playlists" % project["id"],
|
||||
params={"page": page},
|
||||
client=client,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def all_playlists_for_episode(episode, client=default):
|
||||
"""
|
||||
|
||||
Args:
|
||||
episode (str / dict): The episode dict or the episode ID.
|
||||
|
||||
Returns:
|
||||
list: All playlists for the given episode.
|
||||
"""
|
||||
|
||||
project = normalize_model_parameter(episode["project_id"])
|
||||
return sort_by_name(
|
||||
raw.fetch_all(
|
||||
"projects/%s/episodes/%s/playlists"
|
||||
% (
|
||||
project["id"],
|
||||
episode["id"],
|
||||
),
|
||||
client=client,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_playlist(playlist, client=default):
|
||||
"""
|
||||
Args:
|
||||
playlist (str / dict): The playlist dict or the playlist ID.
|
||||
|
||||
Returns:
|
||||
dict: playlist object for given id.
|
||||
"""
|
||||
|
||||
playlist = normalize_model_parameter(playlist)
|
||||
return raw.fetch_one("playlists", playlist["id"], client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_playlist_by_name(project, name, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
name (str): The playlist name
|
||||
|
||||
Returns:
|
||||
dict: Playlist matching given name for given project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
params = {"project_id": project["id"], "name": name}
|
||||
return raw.fetch_first("playlists", params=params, client=client)
|
||||
|
||||
|
||||
def new_playlist(
|
||||
project,
|
||||
name,
|
||||
episode=None,
|
||||
for_entity="shot",
|
||||
for_client=False,
|
||||
client=default,
|
||||
):
|
||||
"""
|
||||
Create a new playlist in the database for given project.
|
||||
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
name (str): Playlist name.
|
||||
|
||||
Returns:
|
||||
dict: Created playlist.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
data = {
|
||||
"name": name,
|
||||
"project_id": project["id"],
|
||||
"for_entity": for_entity,
|
||||
"for_client": for_client,
|
||||
}
|
||||
if episode is not None:
|
||||
episode = normalize_model_parameter(episode)
|
||||
data["episode_id"] = episode["id"]
|
||||
playlist = get_playlist_by_name(project, name, client=client)
|
||||
if playlist is None:
|
||||
playlist = raw.post("data/playlists/", data, client=client)
|
||||
return playlist
|
||||
|
||||
|
||||
def update_playlist(playlist, client=default):
|
||||
"""
|
||||
Save given playlist data into the API. Metadata are fully replaced by
|
||||
the ones set on given playlist.
|
||||
|
||||
Args:
|
||||
playlist (dict): The playlist dict to update.
|
||||
|
||||
Returns:
|
||||
dict: Updated playlist.
|
||||
"""
|
||||
return raw.put(
|
||||
"data/playlists/%s" % playlist["id"], playlist, client=client
|
||||
)
|
@ -1,377 +0,0 @@
|
||||
from . import client as raw
|
||||
|
||||
from .sorting import sort_by_name
|
||||
from .cache import cache
|
||||
from .helpers import (
|
||||
normalize_model_parameter,
|
||||
normalize_list_of_models_for_links,
|
||||
)
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
@cache
|
||||
def all_project_status(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Project status listed in database.
|
||||
"""
|
||||
return sort_by_name(raw.fetch_all("project-status", client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def get_project_status_by_name(project_status_name, client=default):
|
||||
"""
|
||||
Args:
|
||||
project_status_name (str): Name of claimed project status.
|
||||
|
||||
Returns:
|
||||
dict: Project status corresponding to given name.
|
||||
"""
|
||||
return raw.fetch_first(
|
||||
"project-status", {"name": project_status_name}, client=client
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def all_projects(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Projects stored in the database.
|
||||
"""
|
||||
return sort_by_name(raw.fetch_all("projects", client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def all_open_projects(client=default):
|
||||
"""
|
||||
Returns:
|
||||
Open projects stored in the database.
|
||||
"""
|
||||
return sort_by_name(raw.fetch_all("projects/open", client=client))
|
||||
|
||||
|
||||
@cache
|
||||
def get_project(project_id, client=default):
|
||||
"""
|
||||
Args:
|
||||
project_id (str): ID of claimed project.
|
||||
|
||||
Returns:
|
||||
dict: Project corresponding to given id.
|
||||
"""
|
||||
return raw.fetch_one("projects", project_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_project_url(project, section="assets", client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
section (str): The section we want to open in the browser.
|
||||
|
||||
Returns:
|
||||
url (str): Web url associated to the given project
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
path = "{host}/productions/{project_id}/{section}/"
|
||||
return path.format(
|
||||
host=raw.get_api_url_from_host(),
|
||||
project_id=project["id"],
|
||||
section=section,
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_project_by_name(project_name, client=default):
|
||||
"""
|
||||
Args:
|
||||
project_name (str): Name of claimed project.
|
||||
|
||||
Returns:
|
||||
dict: Project corresponding to given name.
|
||||
"""
|
||||
return raw.fetch_first("projects", {"name": project_name}, client=client)
|
||||
|
||||
|
||||
def new_project(
|
||||
name,
|
||||
production_type="short",
|
||||
team=[],
|
||||
asset_types=[],
|
||||
task_statuses=[],
|
||||
task_types=[],
|
||||
client=default,
|
||||
):
|
||||
"""
|
||||
Creates a new project.
|
||||
|
||||
Args:
|
||||
name (str): Name of the project to create.
|
||||
production_type (str): short, featurefilm, tvshow.
|
||||
team (list): Team of the project.
|
||||
asset_types (list): Asset types of the project.
|
||||
task_statuses (list): Task statuses of the project.
|
||||
task_types (list): Task types of the project.
|
||||
Returns:
|
||||
dict: Created project.
|
||||
"""
|
||||
project = get_project_by_name(name, client=client)
|
||||
if project is None:
|
||||
project = raw.create(
|
||||
"projects",
|
||||
{
|
||||
"name": name,
|
||||
"production_type": production_type,
|
||||
"team": normalize_list_of_models_for_links(team),
|
||||
"asset_types": normalize_list_of_models_for_links(asset_types),
|
||||
"task_statuses": normalize_list_of_models_for_links(
|
||||
task_statuses
|
||||
),
|
||||
"task_types": normalize_list_of_models_for_links(task_types),
|
||||
},
|
||||
client=client,
|
||||
)
|
||||
return project
|
||||
|
||||
|
||||
def remove_project(project, force=False, client=default):
|
||||
"""
|
||||
Remove given project from database. (Prior to do that, make sure, there
|
||||
is no asset or shot left).
|
||||
|
||||
Args:
|
||||
project (dict / str): Project to remove.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
path = "data/projects/%s" % project["id"]
|
||||
if force:
|
||||
path += "?force=true"
|
||||
return raw.delete(path, client=client)
|
||||
|
||||
|
||||
def update_project(project, client=default):
|
||||
"""
|
||||
Save given project data into the API. Metadata are fully replaced by the
|
||||
ones set on given project.
|
||||
|
||||
Args:
|
||||
project (dict): The project to update.
|
||||
|
||||
Returns:
|
||||
dict: Updated project.
|
||||
"""
|
||||
if "team" in project:
|
||||
project["team"] = normalize_list_of_models_for_links(project["team"])
|
||||
if "asset_types" in project:
|
||||
project["asset_types"] = normalize_list_of_models_for_links(
|
||||
project["asset_types"]
|
||||
)
|
||||
if "task_statuses" in project:
|
||||
project["task_statuses"] = normalize_list_of_models_for_links(
|
||||
project["task_statuses"]
|
||||
)
|
||||
if "task_types" in project:
|
||||
project["task_types"] = normalize_list_of_models_for_links(
|
||||
project["task_types"]
|
||||
)
|
||||
return raw.put("data/projects/%s" % project["id"], project, client=client)
|
||||
|
||||
|
||||
def update_project_data(project, data={}, client=default):
|
||||
"""
|
||||
Update the metadata for the provided project. Keys that are not provided
|
||||
are not changed.
|
||||
|
||||
Args:
|
||||
project (dict / ID): The project dict or id to save in database.
|
||||
data (dict): Free field to set metadata of any kind.
|
||||
|
||||
Returns:
|
||||
dict: Updated project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
project = get_project(project["id"], client=client)
|
||||
if "data" not in project or project["data"] is None:
|
||||
project["data"] = {}
|
||||
project["data"].update(data)
|
||||
return update_project(project, client=client)
|
||||
|
||||
|
||||
def close_project(project, client=default):
|
||||
"""
|
||||
Closes the provided project.
|
||||
|
||||
Args:
|
||||
project (dict / ID): The project dict or id to save in database.
|
||||
|
||||
Returns:
|
||||
dict: Updated project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
closed_status_id = None
|
||||
for status in all_project_status(client=client):
|
||||
if status["name"].lower() == "closed":
|
||||
closed_status_id = status["id"]
|
||||
|
||||
project["project_status_id"] = closed_status_id
|
||||
update_project(project, client=client)
|
||||
return project
|
||||
|
||||
|
||||
def add_asset_type(project, asset_type, client=default):
|
||||
project = normalize_model_parameter(project)
|
||||
asset_type = normalize_model_parameter(asset_type)
|
||||
data = {"asset_type_id": asset_type["id"]}
|
||||
return raw.post(
|
||||
"data/projects/%s/settings/asset-types" % project["id"],
|
||||
data,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def add_task_type(project, task_type, priority, client=default):
|
||||
project = normalize_model_parameter(project)
|
||||
task_type = normalize_model_parameter(task_type)
|
||||
data = {"task_type_id": task_type["id"], "priority": priority}
|
||||
return raw.post(
|
||||
"data/projects/%s/settings/task-types" % project["id"],
|
||||
data,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def add_task_status(project, task_status, client=default):
|
||||
project = normalize_model_parameter(project)
|
||||
task_status = normalize_model_parameter(task_status)
|
||||
data = {"task_status_id": task_status["id"]}
|
||||
return raw.post(
|
||||
"data/projects/%s/settings/task-status" % project["id"],
|
||||
data,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def add_metadata_descriptor(
|
||||
project,
|
||||
name,
|
||||
entity_type,
|
||||
choices=[],
|
||||
for_client=False,
|
||||
departments=[],
|
||||
client=default,
|
||||
):
|
||||
"""
|
||||
Create a new metadata descriptor for a project.
|
||||
|
||||
Args:
|
||||
project (dict / ID): The project dict or id.
|
||||
name (str): The name of the metadata descriptor
|
||||
entity_type (str): asset, shot or scene.
|
||||
choices (list): A list of possible values, empty list for free values.
|
||||
for_client (bool) : Wheter it should be displayed in Kitsu or not.
|
||||
departments (list): A list of departments dict or id.
|
||||
|
||||
Returns:
|
||||
dict: Created metadata descriptor.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
data = {
|
||||
"name": name,
|
||||
"choices": choices,
|
||||
"for_client": for_client,
|
||||
"entity_type": entity_type,
|
||||
"departments": normalize_list_of_models_for_links(departments),
|
||||
}
|
||||
return raw.post(
|
||||
"data/projects/%s/metadata-descriptors" % project["id"],
|
||||
data,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def get_metadata_descriptor(project, metadata_descriptor_id, client=default):
|
||||
"""
|
||||
Get a metadata descriptor matchind it's ID.
|
||||
|
||||
Args:
|
||||
project (dict / ID): The project dict or id.
|
||||
metadata_descriptor_id (dict / ID): The metadata descriptor dict or id.
|
||||
|
||||
Returns:
|
||||
dict: The metadata descriptor matchind the ID.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
metadata_descriptor = normalize_model_parameter(metadata_descriptor_id)
|
||||
return raw.fetch_one(
|
||||
"projects/%s/metadata-descriptors" % project["id"],
|
||||
metadata_descriptor["id"],
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def all_metadata_descriptors(project, client=default):
|
||||
"""
|
||||
Get all the metadata descriptors.
|
||||
|
||||
Args:
|
||||
project (dict / ID): The project dict or id.
|
||||
|
||||
Returns:
|
||||
list: The metadata descriptors.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
return raw.fetch_all(
|
||||
"projects/%s/metadata-descriptors" % project["id"],
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def update_metadata_descriptor(project, metadata_descriptor, client=default):
|
||||
"""
|
||||
Update a metadata descriptor.
|
||||
|
||||
Args:
|
||||
project (dict / ID): The project dict or id.
|
||||
metadata_descriptor (dict): The metadata descriptor that needs to be updated.
|
||||
|
||||
Returns:
|
||||
dict: The updated metadata descriptor.
|
||||
"""
|
||||
if "departments" in metadata_descriptor:
|
||||
metadata_descriptor[
|
||||
"departments"
|
||||
] = normalize_list_of_models_for_links(
|
||||
metadata_descriptor["departments"]
|
||||
)
|
||||
|
||||
project = normalize_model_parameter(project)
|
||||
return raw.put(
|
||||
"data/projects/%s/metadata-descriptors/%s"
|
||||
% (project["id"], metadata_descriptor["id"]),
|
||||
metadata_descriptor,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def remove_metadata_descriptor(
|
||||
project, metadata_descriptor_id, force=False, client=default
|
||||
):
|
||||
"""
|
||||
Remove a metadata descriptor.
|
||||
|
||||
Args:
|
||||
project (dict / ID): The project dict or id.
|
||||
metadata_descriptor_id (dict / ID): The metadata descriptor dict or id.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
metadata_descriptor = normalize_model_parameter(metadata_descriptor_id)
|
||||
params = {}
|
||||
if force:
|
||||
params = {"force": "true"}
|
||||
return raw.delete(
|
||||
"data/projects/%s/metadata-descriptors/%s"
|
||||
% (project["id"], metadata_descriptor["id"]),
|
||||
params,
|
||||
client=client,
|
||||
)
|
@ -1,189 +0,0 @@
|
||||
from . import client as raw
|
||||
|
||||
from .sorting import sort_by_name
|
||||
from .cache import cache
|
||||
from .helpers import normalize_model_parameter
|
||||
from .shot import get_sequence
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
def new_scene(project, sequence, name, client=default):
|
||||
"""
|
||||
Create a scene for given sequence.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
shot = {"name": name, "sequence_id": sequence["id"]}
|
||||
return raw.post(
|
||||
"data/projects/%s/scenes" % project["id"], shot, client=client
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def all_scenes(project=None, client=default):
|
||||
"""
|
||||
Retrieve all scenes.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
if project is not None:
|
||||
scenes = raw.fetch_all(
|
||||
"projects/%s/scenes" % project["id"], client=client
|
||||
)
|
||||
else:
|
||||
scenes = raw.fetch_all("scenes", client=client)
|
||||
return sort_by_name(scenes)
|
||||
|
||||
|
||||
@cache
|
||||
def all_scenes_for_project(project, client=default):
|
||||
"""
|
||||
Retrieve all scenes for given project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
scenes = raw.fetch_all("projects/%s/scenes" % project["id"], client=client)
|
||||
return sort_by_name(scenes)
|
||||
|
||||
|
||||
@cache
|
||||
def all_scenes_for_sequence(sequence, client=default):
|
||||
"""
|
||||
Retrieve all scenes which are children from given sequence.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
return sort_by_name(
|
||||
raw.fetch_all("sequences/%s/scenes" % sequence["id"], client=client),
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_scene(scene_id, client=default):
|
||||
"""
|
||||
Return scene corresponding to given scene ID.
|
||||
"""
|
||||
return raw.fetch_one("scenes", scene_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_scene_by_name(sequence, scene_name, client=default):
|
||||
"""
|
||||
Returns scene corresponding to given sequence and name.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
result = raw.fetch_all(
|
||||
"scenes/all",
|
||||
{"parent_id": sequence["id"], "name": scene_name},
|
||||
client=client,
|
||||
)
|
||||
return next(iter(result or []), None)
|
||||
|
||||
|
||||
def update_scene(scene, client=default):
|
||||
"""
|
||||
Save given scene data into the API.
|
||||
"""
|
||||
return raw.put("data/entities/%s" % scene["id"], scene, client=client)
|
||||
|
||||
|
||||
def new_scene_asset_instance(scene, asset, description="", client=default):
|
||||
"""
|
||||
Creates a new asset instance on given scene. The instance number is
|
||||
automatically generated (increment highest number).
|
||||
"""
|
||||
scene = normalize_model_parameter(scene)
|
||||
asset = normalize_model_parameter(asset)
|
||||
data = {"asset_id": asset["id"], "description": description}
|
||||
return raw.post(
|
||||
"data/scenes/%s/asset-instances" % scene["id"], data, client=client
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def all_asset_instances_for_scene(scene, client=default):
|
||||
"""
|
||||
Return the list of asset instances listed in a scene.
|
||||
"""
|
||||
scene = normalize_model_parameter(scene)
|
||||
return raw.get(
|
||||
"data/scenes/%s/asset-instances" % scene["id"], client=client
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_asset_instance_by_name(scene, name, client=default):
|
||||
"""
|
||||
Returns the asset instance of the scene that has the given name.
|
||||
"""
|
||||
return raw.fetch_first(
|
||||
"asset-instances",
|
||||
{"name": name, "scene_id": scene["id"]},
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def all_camera_instances_for_scene(scene, client=default):
|
||||
"""
|
||||
Return the list of camera instances listed in a scene.
|
||||
"""
|
||||
scene = normalize_model_parameter(scene)
|
||||
return raw.get(
|
||||
"data/scenes/%s/camera-instances" % scene["id"], client=client
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def all_shots_for_scene(scene, client=default):
|
||||
"""
|
||||
Return the list of shots issued from given scene.
|
||||
"""
|
||||
scene = normalize_model_parameter(scene)
|
||||
return raw.get("data/scenes/%s/shots" % scene["id"], client=client)
|
||||
|
||||
|
||||
def add_shot_to_scene(scene, shot, client=default):
|
||||
"""
|
||||
Link a shot to a scene to mark the fact it was generated out from that
|
||||
scene.
|
||||
"""
|
||||
scene = normalize_model_parameter(scene)
|
||||
shot = normalize_model_parameter(shot)
|
||||
data = {"shot_id": shot["id"]}
|
||||
return raw.post("data/scenes/%s/shots" % scene["id"], data, client=client)
|
||||
|
||||
|
||||
def remove_shot_from_scene(scene, shot, client=default):
|
||||
"""
|
||||
Remove link between a shot and a scene.
|
||||
"""
|
||||
scene = normalize_model_parameter(scene)
|
||||
shot = normalize_model_parameter(shot)
|
||||
return raw.delete(
|
||||
"data/scenes/%s/shots/%s" % (scene["id"], shot["id"]), client=client
|
||||
)
|
||||
|
||||
|
||||
def update_asset_instance_name(asset_instance, name, client=default):
|
||||
"""
|
||||
Update the name of given asset instance.
|
||||
"""
|
||||
path = "/data/asset-instances/%s" % asset_instance["id"]
|
||||
return raw.put(path, {"name": name}, client=client)
|
||||
|
||||
|
||||
def update_asset_instance_data(asset_instance, data, client=default):
|
||||
"""
|
||||
Update the extra data of given asset instance.
|
||||
"""
|
||||
asset_instance = normalize_model_parameter(asset_instance)
|
||||
path = "/data/asset-instances/%s" % asset_instance["id"]
|
||||
return raw.put(path, {"data": data}, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_sequence_from_scene(scene, client=default):
|
||||
"""
|
||||
Return sequence which is parent of given shot.
|
||||
"""
|
||||
scene = normalize_model_parameter(scene)
|
||||
return get_sequence(scene["parent_id"], client=client)
|
@ -1,628 +0,0 @@
|
||||
from . import client as raw
|
||||
|
||||
from .sorting import sort_by_name
|
||||
from .cache import cache
|
||||
from .helpers import normalize_model_parameter
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
@cache
|
||||
def all_previews_for_shot(shot, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
|
||||
Returns:
|
||||
list: Previews from database for given shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
return raw.fetch_all("shots/%s/preview-files" % shot["id"], client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def all_shots_for_project(project, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
|
||||
Returns:
|
||||
list: Shots from database or for given project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
shots = raw.fetch_all("projects/%s/shots" % project["id"], client=client)
|
||||
|
||||
return sort_by_name(shots)
|
||||
|
||||
|
||||
@cache
|
||||
def all_shots_for_episode(episode, client=default):
|
||||
"""
|
||||
Args:
|
||||
episode (str / dict): The episode dict or the episode ID.
|
||||
|
||||
Returns:
|
||||
list: Shots which are children of given episode.
|
||||
"""
|
||||
episode = normalize_model_parameter(episode)
|
||||
return sort_by_name(
|
||||
raw.fetch_all("episodes/%s/shots" % episode["id"], client=client)
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def all_shots_for_sequence(sequence, client=default):
|
||||
"""
|
||||
Args:
|
||||
sequence (str / dict): The sequence dict or the sequence ID.
|
||||
|
||||
Returns:
|
||||
list: Shots which are children of given sequence.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
return sort_by_name(
|
||||
raw.fetch_all("sequences/%s/shots" % sequence["id"], client=client)
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def all_sequences_for_project(project, client=default):
|
||||
"""
|
||||
Args:
|
||||
sequence (str / dict): The sequence dict or the sequence ID.
|
||||
|
||||
Returns:
|
||||
list: Sequences from database for given project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
path = "projects/%s/sequences" % project["id"]
|
||||
sequences = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(sequences)
|
||||
|
||||
|
||||
@cache
|
||||
def all_sequences_for_episode(episode, client=default):
|
||||
"""
|
||||
Args:
|
||||
sequence (str / dict): The sequence dict or the sequence ID.
|
||||
|
||||
Returns:
|
||||
list: Sequences which are children of given episode.
|
||||
"""
|
||||
episode = normalize_model_parameter(episode)
|
||||
path = "episodes/%s/sequences" % episode["id"]
|
||||
sequences = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(sequences)
|
||||
|
||||
|
||||
@cache
|
||||
def all_episodes_for_project(project, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
|
||||
Returns:
|
||||
list: Episodes from database for given project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
path = "projects/%s/episodes" % project["id"]
|
||||
episodes = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(episodes)
|
||||
|
||||
|
||||
@cache
|
||||
def get_episode(episode_id, client=default):
|
||||
"""
|
||||
Args:
|
||||
episode_id (str): Id of claimed episode.
|
||||
|
||||
Returns:
|
||||
dict: Episode corresponding to given episode ID.
|
||||
"""
|
||||
return raw.fetch_one("episodes", episode_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_episode_by_name(project, episode_name, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
episode_name (str): Name of claimed episode.
|
||||
|
||||
Returns:
|
||||
dict: Episode corresponding to given name and project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
return raw.fetch_first(
|
||||
"episodes",
|
||||
{"project_id": project["id"], "name": episode_name},
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_episode_from_sequence(sequence, client=default):
|
||||
"""
|
||||
Args:
|
||||
sequence (dict): The sequence dict.
|
||||
|
||||
Returns:
|
||||
dict: Episode which is parent of given sequence.
|
||||
"""
|
||||
if sequence["parent_id"] is None:
|
||||
return None
|
||||
else:
|
||||
return get_episode(sequence["parent_id"], client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_sequence(sequence_id, client=default):
|
||||
"""
|
||||
Args:
|
||||
sequence_id (str): ID of claimed sequence.
|
||||
|
||||
Returns:
|
||||
dict: Sequence corresponding to given sequence ID.
|
||||
"""
|
||||
return raw.fetch_one("sequences", sequence_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_sequence_by_name(project, sequence_name, episode=None, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
sequence_name (str): Name of claimed sequence.
|
||||
episode (str / dict): The episode dict or the episode ID (optional).
|
||||
|
||||
Returns:
|
||||
dict: Seqence corresponding to given name and project (and episode in
|
||||
case of TV Show).
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
if episode is None:
|
||||
params = {"project_id": project["id"], "name": sequence_name}
|
||||
else:
|
||||
episode = normalize_model_parameter(episode)
|
||||
params = {"episode_id": episode["id"], "name": sequence_name}
|
||||
return raw.fetch_first("sequences", params, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_sequence_from_shot(shot, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
|
||||
Returns:
|
||||
dict: Sequence which is parent of given shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
return get_sequence(shot["parent_id"], client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_shot(shot_id, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot_id (str): Id of claimed shot.
|
||||
|
||||
Returns:
|
||||
dict: Shot corresponding to given shot ID.
|
||||
"""
|
||||
return raw.fetch_one("shots", shot_id, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def get_shot_by_name(sequence, shot_name, client=default):
|
||||
"""
|
||||
Args:
|
||||
sequence (str / dict): The sequence dict or the sequence ID.
|
||||
shot_name (str): Name of claimed shot.
|
||||
|
||||
Returns:
|
||||
dict: Shot corresponding to given name and sequence.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
return raw.fetch_first(
|
||||
"shots/all",
|
||||
{"sequence_id": sequence["id"], "name": shot_name},
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_episode_url(episode, client=default):
|
||||
"""
|
||||
Args:
|
||||
episode (str / dict): The episode dict or the episode ID.
|
||||
|
||||
Returns:
|
||||
url (str): Web url associated to the given episode
|
||||
"""
|
||||
episode = normalize_model_parameter(episode)
|
||||
episode = get_episode(episode["id"])
|
||||
path = "{host}/productions/{project_id}/episodes/{episode_id}/shots"
|
||||
return path.format(
|
||||
host=raw.get_api_url_from_host(client=client),
|
||||
project_id=episode["project_id"],
|
||||
episode_id=episode["id"],
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_shot_url(shot, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
|
||||
Returns:
|
||||
url (str): Web url associated to the given shot
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
shot = get_shot(shot["id"])
|
||||
path = "{host}/productions/{project_id}/"
|
||||
if shot["episode_id"] is None:
|
||||
path += "shots/{shot_id}/"
|
||||
else:
|
||||
path += "episodes/{episode_id}/shots/{shot_id}/"
|
||||
return path.format(
|
||||
host=raw.get_api_url_from_host(client=client),
|
||||
project_id=shot["project_id"],
|
||||
shot_id=shot["id"],
|
||||
episode_id=shot["episode_id"],
|
||||
)
|
||||
|
||||
|
||||
def new_sequence(project, name, episode=None, client=default):
|
||||
"""
|
||||
Create a sequence for given project and episode.
|
||||
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
episode (str / dict): The episode dict or the episode ID.
|
||||
name (str): The name of the sequence to create.
|
||||
|
||||
Returns:
|
||||
Created sequence.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
data = {"name": name}
|
||||
|
||||
if episode is not None:
|
||||
episode = normalize_model_parameter(episode)
|
||||
data["episode_id"] = episode["id"]
|
||||
|
||||
sequence = get_sequence_by_name(
|
||||
project, name, episode=episode, client=client
|
||||
)
|
||||
if sequence is None:
|
||||
path = "data/projects/%s/sequences" % project["id"]
|
||||
return raw.post(path, data, client=client)
|
||||
else:
|
||||
return sequence
|
||||
|
||||
|
||||
def new_shot(
|
||||
project,
|
||||
sequence,
|
||||
name,
|
||||
nb_frames=None,
|
||||
frame_in=None,
|
||||
frame_out=None,
|
||||
description=None,
|
||||
data={},
|
||||
client=default,
|
||||
):
|
||||
"""
|
||||
Create a shot for given sequence and project. Add frame in and frame out
|
||||
parameters to shot extra data. Allow to set metadata too.
|
||||
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
sequence (str / dict): The sequence dict or the sequence ID.
|
||||
name (str): The name of the shot to create.
|
||||
frame_in (int):
|
||||
frame_out (int):
|
||||
data (dict): Free field to set metadata of any kind.
|
||||
|
||||
Returns:
|
||||
Created shot.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
|
||||
if frame_in is not None:
|
||||
data["frame_in"] = frame_in
|
||||
if frame_out is not None:
|
||||
data["frame_out"] = frame_out
|
||||
|
||||
data = {"name": name, "data": data, "sequence_id": sequence["id"]}
|
||||
if nb_frames is not None:
|
||||
data["nb_frames"] = nb_frames
|
||||
|
||||
if description is not None:
|
||||
data["description"] = description
|
||||
|
||||
shot = get_shot_by_name(sequence, name, client=client)
|
||||
if shot is None:
|
||||
path = "data/projects/%s/shots" % project["id"]
|
||||
return raw.post(path, data, client=client)
|
||||
else:
|
||||
return shot
|
||||
|
||||
|
||||
def update_shot(shot, client=default):
|
||||
"""
|
||||
Save given shot data into the API. Metadata are fully replaced by the ones
|
||||
set on given shot.
|
||||
|
||||
Args:
|
||||
shot (dict): The shot dict to update.
|
||||
|
||||
Returns:
|
||||
dict: Updated shot.
|
||||
"""
|
||||
return raw.put("data/entities/%s" % shot["id"], shot, client=client)
|
||||
|
||||
|
||||
def update_sequence(sequence, client=default):
|
||||
"""
|
||||
Save given sequence data into the API. Metadata are fully replaced by the
|
||||
ones set on given sequence.
|
||||
|
||||
Args:
|
||||
sequence (dict): The sequence dict to update.
|
||||
|
||||
Returns:
|
||||
dict: Updated sequence.
|
||||
"""
|
||||
return raw.put(
|
||||
"data/entities/%s" % sequence["id"], sequence, client=client
|
||||
)
|
||||
|
||||
|
||||
@cache
|
||||
def get_asset_instances_for_shot(shot, client=default):
|
||||
"""
|
||||
Return the list of asset instances linked to given shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
return raw.get("data/shots/%s/asset-instances" % shot["id"], client=client)
|
||||
|
||||
|
||||
def update_shot_data(shot, data={}, client=default):
|
||||
"""
|
||||
Update the metadata for the provided shot. Keys that are not provided are
|
||||
not changed.
|
||||
|
||||
Args:
|
||||
shot (dict / ID): The shot dict or ID to save in database.
|
||||
data (dict): Free field to set metadata of any kind.
|
||||
|
||||
Returns:
|
||||
dict: Updated shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
current_shot = get_shot(shot["id"], client=client)
|
||||
updated_shot = {"id": current_shot["id"], "data": current_shot["data"]}
|
||||
updated_shot["data"].update(data)
|
||||
return update_shot(updated_shot, client=client)
|
||||
|
||||
|
||||
def update_sequence_data(sequence, data={}, client=default):
|
||||
"""
|
||||
Update the metadata for the provided sequence. Keys that are not provided
|
||||
are not changed.
|
||||
|
||||
Args:
|
||||
sequence (dict / ID): The sequence dicto or ID to save in database.
|
||||
data (dict): Free field to set metadata of any kind.
|
||||
|
||||
Returns:
|
||||
dict: Updated sequence.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
current_sequence = get_sequence(sequence["id"], client=client)
|
||||
|
||||
if not current_sequence.get("data"):
|
||||
current_sequence["data"] = {}
|
||||
|
||||
updated_sequence = {
|
||||
"id": current_sequence["id"],
|
||||
"data": current_sequence["data"],
|
||||
}
|
||||
updated_sequence["data"].update(data)
|
||||
return update_sequence(updated_sequence, client)
|
||||
|
||||
|
||||
def remove_shot(shot, force=False, client=default):
|
||||
"""
|
||||
Remove given shot from database.
|
||||
|
||||
Args:
|
||||
shot (dict / str): Shot to remove.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
path = "data/shots/%s" % shot["id"]
|
||||
params = {}
|
||||
if force:
|
||||
params = {"force": "true"}
|
||||
return raw.delete(path, params, client=client)
|
||||
|
||||
|
||||
def restore_shot(shot, client=default):
|
||||
"""
|
||||
Restore given shot into database (uncancel it).
|
||||
|
||||
Args:
|
||||
shot (dict / str): Shot to restore.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
path = "data/shots/%s" % shot["id"]
|
||||
data = {"canceled": False}
|
||||
return raw.put(path, data, client=client)
|
||||
|
||||
|
||||
def new_episode(project, name, client=default):
|
||||
"""
|
||||
Create an episode for given project.
|
||||
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
name (str): The name of the episode to create.
|
||||
|
||||
Returns:
|
||||
dict: Created episode.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
data = {"name": name}
|
||||
episode = get_episode_by_name(project, name, client=client)
|
||||
if episode is None:
|
||||
return raw.post(
|
||||
"data/projects/%s/episodes" % project["id"], data, client=client
|
||||
)
|
||||
else:
|
||||
return episode
|
||||
|
||||
|
||||
def update_episode(episode, client=default):
|
||||
"""
|
||||
Save given episode data into the API. Metadata are fully replaced by the
|
||||
ones set on given episode.
|
||||
|
||||
Args:
|
||||
episode (dict): The episode dict to update.
|
||||
|
||||
Returns:
|
||||
dict: Updated episode.
|
||||
"""
|
||||
return raw.put("data/entities/%s" % episode["id"], episode, client=client)
|
||||
|
||||
|
||||
def update_episode_data(episode, data={}, client=default):
|
||||
"""
|
||||
Update the metadata for the provided episode. Keys that are not provided
|
||||
are not changed.
|
||||
|
||||
Args:
|
||||
episode (dict / ID): The episode dict or ID to save in database.
|
||||
data (dict): Free field to set metadata of any kind.
|
||||
|
||||
Returns:
|
||||
dict: Updated episode.
|
||||
"""
|
||||
episode = normalize_model_parameter(episode)
|
||||
current_episode = get_sequence(episode["id"], client=client)
|
||||
updated_episode = {
|
||||
"id": current_episode["id"],
|
||||
"data": current_episode["data"],
|
||||
}
|
||||
updated_episode["data"].update(data)
|
||||
return update_episode(updated_episode, client=client)
|
||||
|
||||
|
||||
def remove_episode(episode, force=False, client=default):
|
||||
"""
|
||||
Remove given episode and related from database.
|
||||
|
||||
Args:
|
||||
episode (dict / str): Episode to remove.
|
||||
"""
|
||||
episode = normalize_model_parameter(episode)
|
||||
path = "data/episodes/%s" % episode["id"]
|
||||
params = {}
|
||||
if force:
|
||||
params = {"force": "true"}
|
||||
return raw.delete(path, params=params, client=client)
|
||||
|
||||
|
||||
def remove_sequence(sequence, force=False, client=default):
|
||||
"""
|
||||
Remove given sequence and related from database.
|
||||
|
||||
Args:
|
||||
sequence (dict / str): Sequence to remove.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
path = "data/sequences/%s" % sequence["id"]
|
||||
params = {}
|
||||
if force:
|
||||
params = {"force": "true"}
|
||||
return raw.delete(path, params=params, client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def all_asset_instances_for_shot(shot, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
|
||||
Returns:
|
||||
list: Asset instances linked to given shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
return raw.get("data/shots/%s/asset-instances" % shot["id"], client=client)
|
||||
|
||||
|
||||
def add_asset_instance_to_shot(shot, asset_instance, client=default):
|
||||
"""
|
||||
Link a new asset instance to given shot.
|
||||
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
asset_instance (str / dict): The asset instance dict or ID.
|
||||
|
||||
Returns:
|
||||
dict: Related shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
asset_instance = normalize_model_parameter(asset_instance)
|
||||
data = {"asset_instance_id": asset_instance["id"]}
|
||||
path = "data/shots/%s/asset-instances" % shot["id"]
|
||||
return raw.post(path, data, client=client)
|
||||
|
||||
|
||||
def remove_asset_instance_from_shot(shot, asset_instance, client=default):
|
||||
"""
|
||||
Remove link between an asset instance and given shot.
|
||||
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
asset_instance (str / dict): The asset instance dict or ID.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
asset_instance = normalize_model_parameter(asset_instance)
|
||||
path = "data/shots/%s/asset-instances/%s" % (
|
||||
shot["id"],
|
||||
asset_instance["id"],
|
||||
)
|
||||
return raw.delete(path, client=client)
|
||||
|
||||
|
||||
def import_shots_with_csv(project, csv_file_path, client=default):
|
||||
project = normalize_model_parameter(project)
|
||||
return raw.upload(
|
||||
"import/csv/projects/%s/shots" % project["id"],
|
||||
csv_file_path,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
def export_shots_with_csv(
|
||||
project, csv_file_path, episode=None, assigned_to=None, client=default
|
||||
):
|
||||
project = normalize_model_parameter(project)
|
||||
episode = normalize_model_parameter(episode)
|
||||
assigned_to = normalize_model_parameter(assigned_to)
|
||||
params = {}
|
||||
if episode:
|
||||
params["episode_id"] = episode["id"]
|
||||
if assigned_to:
|
||||
params["assigned_to"] = assigned_to["id"]
|
||||
return raw.download(
|
||||
"export/csv/projects/%s/shots.csv" % project["id"],
|
||||
csv_file_path,
|
||||
params=params,
|
||||
client=client,
|
||||
)
|
@ -1,11 +0,0 @@
|
||||
def sort_by_name(dicts):
|
||||
"""
|
||||
Sorting of a list of dicts. The sorting is based on the name field.
|
||||
|
||||
Args:
|
||||
list: The list of dicts to sort.
|
||||
|
||||
Returns:
|
||||
Sorted list.
|
||||
"""
|
||||
return sorted(dicts, key=lambda k: k.get("name", "").lower())
|
@ -1,172 +0,0 @@
|
||||
from . import client as raw
|
||||
|
||||
from .helpers import normalize_model_parameter, validate_date_format
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
def get_last_events(
|
||||
page_size=20000, project=None, after=None, before=None, client=default
|
||||
):
|
||||
"""
|
||||
Get last events that occured on the machine.
|
||||
|
||||
Args:
|
||||
page_size (int): Number of events to retrieve.
|
||||
project (dict/id): Get only events related to this project.
|
||||
after (dict/id): Get only events occuring after given date.
|
||||
before (dict/id): Get only events occuring before given date.
|
||||
|
||||
|
||||
Returns:
|
||||
dict: Last events matching criterions.
|
||||
"""
|
||||
path = "/data/events/last"
|
||||
params = {"page_size": page_size}
|
||||
if project is not None:
|
||||
project = normalize_model_parameter(project)
|
||||
params["project_id"] = project["id"]
|
||||
if after is not None:
|
||||
params["after"] = validate_date_format(after)
|
||||
if before is not None:
|
||||
params["before"] = validate_date_format(before)
|
||||
return raw.get(path, params=params, client=client)
|
||||
|
||||
|
||||
def import_entities(entities, client=default):
|
||||
"""
|
||||
Import entities from another instance to target instance (keep id and audit
|
||||
dates).
|
||||
Args:
|
||||
entities (list): Entities to import.
|
||||
|
||||
Returns:
|
||||
dict: Entities created.
|
||||
"""
|
||||
return raw.post("import/kitsu/entities", entities, client=client)
|
||||
|
||||
|
||||
def import_tasks(tasks, client=default):
|
||||
"""
|
||||
Import tasks from another instance to target instance (keep id and audit
|
||||
dates).
|
||||
Args:
|
||||
tasks (list): Tasks to import.
|
||||
|
||||
Returns:
|
||||
dict: Tasks created.
|
||||
"""
|
||||
return raw.post("import/kitsu/tasks", tasks, client=client)
|
||||
|
||||
|
||||
def import_entity_links(links, client=default):
|
||||
"""
|
||||
Import enitity links from another instance to target instance (keep id and
|
||||
audit dates).
|
||||
Args:
|
||||
links (list): Entity links to import.
|
||||
|
||||
Returns:
|
||||
dict: Entity links created.
|
||||
"""
|
||||
return raw.post("import/kitsu/entity-links", links, client=client)
|
||||
|
||||
|
||||
def get_model_list_diff(source_list, target_list):
|
||||
"""
|
||||
Args:
|
||||
source_list (list): List of models to compare.
|
||||
target_list (list): List of models for which we want a diff.
|
||||
|
||||
Returns:
|
||||
tuple: Two lists, one containing the missing models in the target list
|
||||
and one containing the models that should not be in the target list.
|
||||
"""
|
||||
missing = []
|
||||
source_ids = {m["id"]: True for m in source_list}
|
||||
target_ids = {m["id"]: True for m in target_list}
|
||||
for model in source_list:
|
||||
if model["id"] not in target_ids:
|
||||
missing.append(model)
|
||||
unexpected = [
|
||||
model for model in target_list if model["id"] not in source_ids
|
||||
]
|
||||
return (missing, unexpected)
|
||||
|
||||
|
||||
def get_link_list_diff(source_list, target_list):
|
||||
"""
|
||||
Args:
|
||||
source_list (list): List of links to compare.
|
||||
target_list (list): List of links for which we want a diff.
|
||||
|
||||
Returns:
|
||||
tuple: Two lists, one containing the missing links in the target list
|
||||
and one containing the links that should not be in the target list.
|
||||
Links are identified by their in ID and their out ID.
|
||||
"""
|
||||
|
||||
def get_link_key(l):
|
||||
return l["entity_in_id"] + "-" + l["entity_out_id"]
|
||||
|
||||
missing = []
|
||||
unexpected = []
|
||||
source_ids = {get_link_key(m): True for m in source_list}
|
||||
target_ids = {get_link_key(m): True for m in target_list}
|
||||
for link in source_list:
|
||||
if get_link_key(link) not in target_ids:
|
||||
missing.append(link)
|
||||
for link in target_list:
|
||||
if get_link_key(link) not in source_ids:
|
||||
unexpected.append(link)
|
||||
return (missing, unexpected)
|
||||
|
||||
|
||||
def get_id_map_by_name(source_list, target_list):
|
||||
"""
|
||||
Args:
|
||||
source_list (list): List of links to compare.
|
||||
target_list (list): List of links for which we want a diff.
|
||||
|
||||
Returns:
|
||||
dict: A dict where keys are the source model names and the values are
|
||||
the IDs of the target models with same name.
|
||||
It's useful to match a model from the source list to its relative in
|
||||
the target list based on its name.
|
||||
"""
|
||||
link_map = {}
|
||||
name_map = {}
|
||||
for model in target_list:
|
||||
name_map[model["name"].lower()] = model["id"]
|
||||
for model in source_list:
|
||||
if model["name"].lower() in name_map:
|
||||
link_map[model["name"]] = name_map[model["name"].lower()]
|
||||
return link_map
|
||||
|
||||
|
||||
def get_id_map_by_id(source_list, target_list, field="name"):
|
||||
"""
|
||||
Args:
|
||||
source_list (list): List of links to compare.
|
||||
target_list (list): List of links for which we want a diff.
|
||||
|
||||
Returns:
|
||||
dict: A dict where keys are the source model names and the values are
|
||||
the IDs of the target models with same name.
|
||||
It's useful to match a model from the source list to its relative in
|
||||
the target list based on its name.
|
||||
"""
|
||||
link_map = {}
|
||||
name_map = {}
|
||||
for model in target_list:
|
||||
name_map[model[field].lower()] = model["id"]
|
||||
for model in source_list:
|
||||
if model[field].lower() in name_map:
|
||||
link_map[model["id"]] = name_map[model[field].lower()]
|
||||
return link_map
|
||||
|
||||
|
||||
def is_changed(source_model, target_model):
|
||||
source_date = source_model["updated_at"]
|
||||
target_date = target_model["updated_at"]
|
||||
return source_date > target_date
|
File diff suppressed because it is too large
Load Diff
@ -1,270 +0,0 @@
|
||||
import datetime
|
||||
from .exception import NotAuthenticatedException
|
||||
|
||||
from . import client as raw
|
||||
from .sorting import sort_by_name
|
||||
from .helpers import normalize_model_parameter
|
||||
|
||||
from .cache import cache
|
||||
|
||||
default = raw.default_client
|
||||
|
||||
|
||||
@cache
|
||||
def all_open_projects(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Projects for which the user is part of the team. Admins see all
|
||||
projects
|
||||
"""
|
||||
projects = raw.fetch_all("user/projects/open", client=client)
|
||||
return sort_by_name(projects)
|
||||
|
||||
|
||||
@cache
|
||||
def all_asset_types_for_project(project, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
|
||||
Returns:
|
||||
list: Asset types for which the user has a task assigned for given
|
||||
project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
path = "user/projects/%s/asset-types" % project["id"]
|
||||
asset_types = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(asset_types)
|
||||
|
||||
|
||||
@cache
|
||||
def all_assets_for_asset_type_and_project(project, asset_type, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
asset_type (str / dict): The asset type dict or ID.
|
||||
|
||||
Returns:
|
||||
list: Assets for given project and asset type and for which the user has
|
||||
a task assigned.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
asset_type = normalize_model_parameter(asset_type)
|
||||
path = "user/projects/%s/asset-types/%s/assets" % (
|
||||
project["id"],
|
||||
asset_type["id"],
|
||||
)
|
||||
assets = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(assets)
|
||||
|
||||
|
||||
@cache
|
||||
def all_tasks_for_asset(asset, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset (str / dict): The asset dict or the asset ID.
|
||||
|
||||
Returns:
|
||||
list: Tasks for given asset and current user.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
path = "user/assets/%s/tasks" % asset["id"]
|
||||
tasks = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(tasks)
|
||||
|
||||
|
||||
@cache
|
||||
def all_tasks_for_shot(shot, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
|
||||
Returns:
|
||||
list: Tasks assigned to current user for given shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
path = "user/shots/%s/tasks" % shot["id"]
|
||||
tasks = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(tasks)
|
||||
|
||||
|
||||
@cache
|
||||
def all_tasks_for_scene(scene, client=default):
|
||||
"""
|
||||
Args:
|
||||
scene (str / dict): The scene dict or the scene ID.
|
||||
|
||||
Returns:
|
||||
list: Tasks assigned to current user for given scene.
|
||||
"""
|
||||
scene = normalize_model_parameter(scene)
|
||||
path = "user/scene/%s/tasks" % scene["id"]
|
||||
tasks = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(tasks)
|
||||
|
||||
|
||||
@cache
|
||||
def all_tasks_for_sequence(sequence, client=default):
|
||||
"""
|
||||
Return the list of tasks for given asset and current user.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
path = "user/sequences/%s/tasks" % sequence["id"]
|
||||
tasks = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(tasks)
|
||||
|
||||
|
||||
@cache
|
||||
def all_task_types_for_asset(asset, client=default):
|
||||
"""
|
||||
Args:
|
||||
asset (str / dict): The asset dict or the asset ID.
|
||||
|
||||
Returns:
|
||||
list: Task Types of tasks assigned to current user for given asset.
|
||||
"""
|
||||
asset = normalize_model_parameter(asset)
|
||||
path = "user/assets/%s/task-types" % asset["id"]
|
||||
tasks = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(tasks)
|
||||
|
||||
|
||||
@cache
|
||||
def all_task_types_for_shot(shot, client=default):
|
||||
"""
|
||||
Args:
|
||||
shot (str / dict): The shot dict or the shot ID.
|
||||
|
||||
Returns:
|
||||
list: Task Types of tasks assigned to current user for given shot.
|
||||
"""
|
||||
shot = normalize_model_parameter(shot)
|
||||
path = "user/shots/%s/task-types" % shot["id"]
|
||||
task_types = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(task_types)
|
||||
|
||||
|
||||
@cache
|
||||
def all_task_types_for_scene(scene, client=default):
|
||||
"""
|
||||
Args:
|
||||
scene (str / dict): The scene dict or the scene ID.
|
||||
|
||||
Returns:
|
||||
list: Task Types of tasks assigned to current user for given scene.
|
||||
"""
|
||||
scene = normalize_model_parameter(scene)
|
||||
path = "user/scenes/%s/task-types" % scene["id"]
|
||||
task_types = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(task_types)
|
||||
|
||||
|
||||
@cache
|
||||
def all_task_types_for_sequence(sequence, client=default):
|
||||
"""
|
||||
return the list of task_tyes for given asset and current user.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
path = "user/sequences/%s/task-types" % sequence["id"]
|
||||
task_types = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(task_types)
|
||||
|
||||
|
||||
@cache
|
||||
def all_sequences_for_project(project, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
|
||||
Returns:
|
||||
list: Sequences for which user has tasks assigned for given project.
|
||||
"""
|
||||
project = normalize_model_parameter(project)
|
||||
path = "user/projects/%s/sequences" % project["id"]
|
||||
sequences = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(sequences)
|
||||
|
||||
|
||||
@cache
|
||||
def all_episodes_for_project(project, client=default):
|
||||
"""
|
||||
Args:
|
||||
project (str / dict): The project dict or the project ID.
|
||||
|
||||
Returns:
|
||||
list: Episodes for which user has tasks assigned for given project.
|
||||
"""
|
||||
path = "user/projects/%s/episodes" % project["id"]
|
||||
asset_types = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(asset_types)
|
||||
|
||||
|
||||
@cache
|
||||
def all_shots_for_sequence(sequence, client=default):
|
||||
"""
|
||||
Args:
|
||||
sequence (str / dict): The sequence dict or the sequence ID.
|
||||
|
||||
Returns:
|
||||
list: Shots for which user has tasks assigned for given sequence.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
path = "user/sequences/%s/shots" % sequence["id"]
|
||||
shots = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(shots)
|
||||
|
||||
|
||||
@cache
|
||||
def all_scenes_for_sequence(sequence, client=default):
|
||||
"""
|
||||
Args:
|
||||
sequence (str / dict): The sequence dict or the sequence ID.
|
||||
|
||||
Returns:
|
||||
list: Scenes for which user has tasks assigned for given sequence.
|
||||
"""
|
||||
sequence = normalize_model_parameter(sequence)
|
||||
path = "user/sequences/%s/scenes" % sequence["id"]
|
||||
scenes = raw.fetch_all(path, client=client)
|
||||
return sort_by_name(scenes)
|
||||
|
||||
|
||||
@cache
|
||||
def all_tasks_to_do(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Tasks assigned to current user which are not complete.
|
||||
"""
|
||||
return raw.fetch_all("user/tasks", client=client)
|
||||
|
||||
|
||||
@cache
|
||||
def all_done_tasks(client=default):
|
||||
"""
|
||||
Returns:
|
||||
list: Tasks assigned to current user which are done.
|
||||
"""
|
||||
return raw.fetch_all("user/done-tasks", client=client)
|
||||
|
||||
|
||||
def log_desktop_session_log_in(client=default):
|
||||
"""
|
||||
Add a log entry to mention that the user logged in his computer.
|
||||
|
||||
Returns:
|
||||
dict: Desktop session log entry.
|
||||
"""
|
||||
path = "/data/user/desktop-login-logs"
|
||||
data = {"date": datetime.datetime.now().isoformat()}
|
||||
return raw.post(path, data, client=client)
|
||||
|
||||
|
||||
def is_authenticated(client=default):
|
||||
"""
|
||||
Returns:
|
||||
boolean: Current user authenticated or not
|
||||
"""
|
||||
try:
|
||||
return raw.get("auth/authenticated")["authenticated"]
|
||||
except NotAuthenticatedException:
|
||||
return False
|
Loading…
Reference in New Issue
Block a user