From 348104c32dd85232d4c8daff84ca9c57e98b398a Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 27 Jun 2024 14:08:49 +0200
Subject: [PATCH] removed fusion addon
---
.../fusion/client/ayon_fusion/__init__.py | 17 -
.../fusion/client/ayon_fusion/addon.py | 72 -
.../fusion/client/ayon_fusion/api/__init__.py | 39 -
.../fusion/client/ayon_fusion/api/action.py | 112 -
.../fusion/client/ayon_fusion/api/lib.py | 402 ---
.../fusion/client/ayon_fusion/api/menu.py | 190 -
.../fusion/client/ayon_fusion/api/pipeline.py | 439 ---
.../fusion/client/ayon_fusion/api/plugin.py | 278 --
.../fusion/client/ayon_fusion/api/pulse.py | 63 -
.../ayon_fusion/deploy/MenuScripts/README.md | 6 -
.../deploy/MenuScripts/install_pyside2.py | 29 -
.../deploy/MenuScripts/launch_menu.py | 47 -
.../ayon_fusion/deploy/ayon/Config/menu.fu | 60 -
.../deploy/ayon/fusion_shared.prefs | 19 -
.../hooks/pre_fusion_launch_menu_hook.py | 36 -
.../hooks/pre_fusion_profile_hook.py | 169 -
.../ayon_fusion/hooks/pre_fusion_setup.py | 71 -
.../ayon_fusion/hooks/pre_pyside_install.py | 185 -
.../plugins/create/create_image_saver.py | 63 -
.../plugins/create/create_saver.py | 149 -
.../plugins/create/create_workfile.py | 132 -
.../plugins/inventory/select_containers.py | 27 -
.../plugins/inventory/set_tool_color.py | 72 -
.../ayon_fusion/plugins/load/actions.py | 81 -
.../ayon_fusion/plugins/load/load_alembic.py | 72 -
.../ayon_fusion/plugins/load/load_fbx.py | 87 -
.../ayon_fusion/plugins/load/load_sequence.py | 291 --
.../ayon_fusion/plugins/load/load_usd.py | 87 -
.../ayon_fusion/plugins/load/load_workfile.py | 33 -
.../plugins/publish/collect_comp.py | 22 -
.../publish/collect_comp_frame_range.py | 44 -
.../plugins/publish/collect_inputs.py | 116 -
.../plugins/publish/collect_instances.py | 109 -
.../plugins/publish/collect_render.py | 208 --
.../plugins/publish/collect_workfile.py | 26 -
.../plugins/publish/extract_render_local.py | 207 --
.../plugins/publish/increment_current_file.py | 44 -
.../ayon_fusion/plugins/publish/save_scene.py | 21 -
.../publish/validate_background_depth.py | 54 -
.../plugins/publish/validate_comp_saved.py | 32 -
.../publish/validate_create_folder_checked.py | 44 -
.../validate_expected_frames_existence.py | 66 -
.../validate_filename_has_extension.py | 41 -
.../plugins/publish/validate_image_frame.py | 27 -
.../publish/validate_instance_frame_range.py | 41 -
.../publish/validate_instance_in_context.py | 80 -
.../publish/validate_saver_has_input.py | 36 -
.../publish/validate_saver_passthrough.py | 49 -
.../publish/validate_saver_resolution.py | 116 -
.../publish/validate_unique_subsets.py | 62 -
.../client/ayon_fusion/scripts/__init__.py | 0
.../scripts/duplicate_with_inputs.py | 45 -
.../ayon_fusion/vendor/attr/__init__.py | 78 -
.../ayon_fusion/vendor/attr/__init__.pyi | 475 ---
.../client/ayon_fusion/vendor/attr/_cmp.py | 152 -
.../client/ayon_fusion/vendor/attr/_cmp.pyi | 14 -
.../client/ayon_fusion/vendor/attr/_compat.py | 242 --
.../client/ayon_fusion/vendor/attr/_config.py | 23 -
.../client/ayon_fusion/vendor/attr/_funcs.py | 395 ---
.../client/ayon_fusion/vendor/attr/_make.py | 3052 -----------------
.../ayon_fusion/vendor/attr/_next_gen.py | 158 -
.../ayon_fusion/vendor/attr/_version_info.py | 85 -
.../ayon_fusion/vendor/attr/_version_info.pyi | 9 -
.../ayon_fusion/vendor/attr/converters.py | 111 -
.../ayon_fusion/vendor/attr/converters.pyi | 13 -
.../ayon_fusion/vendor/attr/exceptions.py | 92 -
.../ayon_fusion/vendor/attr/exceptions.pyi | 18 -
.../client/ayon_fusion/vendor/attr/filters.py | 52 -
.../ayon_fusion/vendor/attr/filters.pyi | 7 -
.../client/ayon_fusion/vendor/attr/py.typed | 0
.../client/ayon_fusion/vendor/attr/setters.py | 77 -
.../ayon_fusion/vendor/attr/setters.pyi | 20 -
.../ayon_fusion/vendor/attr/validators.py | 379 --
.../ayon_fusion/vendor/attr/validators.pyi | 68 -
.../ayon_fusion/vendor/urllib3/__init__.py | 85 -
.../vendor/urllib3/_collections.py | 337 --
.../ayon_fusion/vendor/urllib3/_version.py | 2 -
.../ayon_fusion/vendor/urllib3/connection.py | 539 ---
.../vendor/urllib3/connectionpool.py | 1067 ------
.../vendor/urllib3/contrib/__init__.py | 0
.../urllib3/contrib/_appengine_environ.py | 36 -
.../contrib/_securetransport/__init__.py | 0
.../contrib/_securetransport/bindings.py | 519 ---
.../contrib/_securetransport/low_level.py | 396 ---
.../vendor/urllib3/contrib/appengine.py | 314 --
.../vendor/urllib3/contrib/ntlmpool.py | 130 -
.../vendor/urllib3/contrib/pyopenssl.py | 511 ---
.../vendor/urllib3/contrib/securetransport.py | 922 -----
.../vendor/urllib3/contrib/socks.py | 216 --
.../ayon_fusion/vendor/urllib3/exceptions.py | 323 --
.../ayon_fusion/vendor/urllib3/fields.py | 274 --
.../ayon_fusion/vendor/urllib3/filepost.py | 98 -
.../vendor/urllib3/packages/__init__.py | 5 -
.../urllib3/packages/backports/__init__.py | 0
.../urllib3/packages/backports/makefile.py | 51 -
.../vendor/urllib3/packages/six.py | 1077 ------
.../packages/ssl_match_hostname/__init__.py | 24 -
.../ssl_match_hostname/_implementation.py | 160 -
.../ayon_fusion/vendor/urllib3/poolmanager.py | 536 ---
.../ayon_fusion/vendor/urllib3/request.py | 170 -
.../ayon_fusion/vendor/urllib3/response.py | 821 -----
.../vendor/urllib3/util/__init__.py | 49 -
.../vendor/urllib3/util/connection.py | 150 -
.../ayon_fusion/vendor/urllib3/util/proxy.py | 56 -
.../ayon_fusion/vendor/urllib3/util/queue.py | 22 -
.../vendor/urllib3/util/request.py | 143 -
.../vendor/urllib3/util/response.py | 107 -
.../ayon_fusion/vendor/urllib3/util/retry.py | 602 ----
.../ayon_fusion/vendor/urllib3/util/ssl_.py | 495 ---
.../vendor/urllib3/util/ssltransport.py | 221 --
.../vendor/urllib3/util/timeout.py | 268 --
.../ayon_fusion/vendor/urllib3/util/url.py | 432 ---
.../ayon_fusion/vendor/urllib3/util/wait.py | 153 -
.../fusion/client/ayon_fusion/version.py | 3 -
server_addon/fusion/package.py | 10 -
server_addon/fusion/server/__init__.py | 13 -
server_addon/fusion/server/imageio.py | 63 -
server_addon/fusion/server/settings.py | 185 -
118 files changed, 21923 deletions(-)
delete mode 100644 server_addon/fusion/client/ayon_fusion/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/addon.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/api/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/api/action.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/api/lib.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/api/menu.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/api/pipeline.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/api/plugin.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/api/pulse.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/README.md
delete mode 100644 server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/install_pyside2.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/launch_menu.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/deploy/ayon/Config/menu.fu
delete mode 100644 server_addon/fusion/client/ayon_fusion/deploy/ayon/fusion_shared.prefs
delete mode 100644 server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_launch_menu_hook.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_profile_hook.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_setup.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/hooks/pre_pyside_install.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/create/create_image_saver.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/create/create_saver.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/create/create_workfile.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/inventory/select_containers.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/inventory/set_tool_color.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/load/actions.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/load/load_alembic.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/load/load_fbx.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/load/load_sequence.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/load/load_usd.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/load/load_workfile.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/collect_comp.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/collect_comp_frame_range.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/collect_inputs.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/collect_instances.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/collect_render.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/collect_workfile.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/extract_render_local.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/increment_current_file.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/save_scene.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_background_depth.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_comp_saved.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_create_folder_checked.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_expected_frames_existence.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_filename_has_extension.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_image_frame.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_instance_frame_range.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_instance_in_context.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_has_input.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_passthrough.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_resolution.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/plugins/publish/validate_unique_subsets.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/scripts/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/scripts/duplicate_with_inputs.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/__init__.pyi
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/_cmp.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/_cmp.pyi
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/_compat.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/_config.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/_funcs.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/_make.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/_next_gen.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/_version_info.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/_version_info.pyi
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/converters.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/converters.pyi
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/exceptions.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/exceptions.pyi
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/filters.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/filters.pyi
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/py.typed
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/setters.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/setters.pyi
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/validators.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/attr/validators.pyi
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/_collections.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/_version.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/connection.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/connectionpool.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_appengine_environ.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/bindings.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/low_level.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/appengine.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/ntlmpool.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/pyopenssl.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/securetransport.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/socks.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/exceptions.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/fields.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/filepost.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/backports/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/backports/makefile.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/six.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/ssl_match_hostname/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/ssl_match_hostname/_implementation.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/poolmanager.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/request.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/response.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/__init__.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/connection.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/proxy.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/queue.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/request.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/response.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/retry.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/ssl_.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/ssltransport.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/timeout.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/url.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/wait.py
delete mode 100644 server_addon/fusion/client/ayon_fusion/version.py
delete mode 100644 server_addon/fusion/package.py
delete mode 100644 server_addon/fusion/server/__init__.py
delete mode 100644 server_addon/fusion/server/imageio.py
delete mode 100644 server_addon/fusion/server/settings.py
diff --git a/server_addon/fusion/client/ayon_fusion/__init__.py b/server_addon/fusion/client/ayon_fusion/__init__.py
deleted file mode 100644
index f2ddccdd87..0000000000
--- a/server_addon/fusion/client/ayon_fusion/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from .version import __version__
-from .addon import (
- get_fusion_version,
- FusionAddon,
- FUSION_ADDON_ROOT,
- FUSION_VERSIONS_DICT,
-)
-
-
-__all__ = (
- "__version__",
-
- "get_fusion_version",
- "FusionAddon",
- "FUSION_ADDON_ROOT",
- "FUSION_VERSIONS_DICT",
-)
diff --git a/server_addon/fusion/client/ayon_fusion/addon.py b/server_addon/fusion/client/ayon_fusion/addon.py
deleted file mode 100644
index ffc70b6ff4..0000000000
--- a/server_addon/fusion/client/ayon_fusion/addon.py
+++ /dev/null
@@ -1,72 +0,0 @@
-import os
-import re
-from ayon_core.addon import AYONAddon, IHostAddon
-from ayon_core.lib import Logger
-
-from .version import __version__
-
-FUSION_ADDON_ROOT = os.path.dirname(os.path.abspath(__file__))
-
-# FUSION_VERSIONS_DICT is used by the pre-launch hooks
-# The keys correspond to all currently supported Fusion versions
-# Each value is a list of corresponding Python home variables and a profile
-# number, which is used by the profile hook to set Fusion profile variables.
-FUSION_VERSIONS_DICT = {
- 9: ("FUSION_PYTHON36_HOME", 9),
- 16: ("FUSION16_PYTHON36_HOME", 16),
- 17: ("FUSION16_PYTHON36_HOME", 16),
- 18: ("FUSION_PYTHON3_HOME", 16),
-}
-
-
-def get_fusion_version(app_name):
- """
- The function is triggered by the prelaunch hooks to get the fusion version.
-
- `app_name` is obtained by prelaunch hooks from the
- `launch_context.env.get("AYON_APP_NAME")`.
-
- To get a correct Fusion version, a version number should be present
- in the `applications/fusion/variants` key
- of the Blackmagic Fusion Application Settings.
- """
-
- log = Logger.get_logger(__name__)
-
- if not app_name:
- return
-
- app_version_candidates = re.findall(r"\d+", app_name)
- if not app_version_candidates:
- return
- for app_version in app_version_candidates:
- if int(app_version) in FUSION_VERSIONS_DICT:
- return int(app_version)
- else:
- log.info(
- "Unsupported Fusion version: {app_version}".format(
- app_version=app_version
- )
- )
-
-
-class FusionAddon(AYONAddon, IHostAddon):
- name = "fusion"
- version = __version__
- host_name = "fusion"
-
- def get_launch_hook_paths(self, app):
- if app.host_name != self.host_name:
- return []
- return [os.path.join(FUSION_ADDON_ROOT, "hooks")]
-
- def add_implementation_envs(self, env, app):
- # Set default values if are not already set via settings
-
- defaults = {"AYON_LOG_NO_COLORS": "1"}
- for key, value in defaults.items():
- if not env.get(key):
- env[key] = value
-
- def get_workfile_extensions(self):
- return [".comp"]
diff --git a/server_addon/fusion/client/ayon_fusion/api/__init__.py b/server_addon/fusion/client/ayon_fusion/api/__init__.py
deleted file mode 100644
index d2feee6d23..0000000000
--- a/server_addon/fusion/client/ayon_fusion/api/__init__.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from .pipeline import (
- FusionHost,
- ls,
-
- imprint_container,
- parse_container
-)
-
-from .lib import (
- maintained_selection,
- update_frame_range,
- set_current_context_framerange,
- get_current_comp,
- get_bmd_library,
- comp_lock_and_undo_chunk
-)
-
-from .menu import launch_ayon_menu
-
-
-__all__ = [
- # pipeline
- "FusionHost",
- "ls",
-
- "imprint_container",
- "parse_container",
-
- # lib
- "maintained_selection",
- "update_frame_range",
- "set_current_context_framerange",
- "get_current_comp",
- "get_bmd_library",
- "comp_lock_and_undo_chunk",
-
- # menu
- "launch_ayon_menu",
-]
diff --git a/server_addon/fusion/client/ayon_fusion/api/action.py b/server_addon/fusion/client/ayon_fusion/api/action.py
deleted file mode 100644
index 02cd96f56c..0000000000
--- a/server_addon/fusion/client/ayon_fusion/api/action.py
+++ /dev/null
@@ -1,112 +0,0 @@
-import pyblish.api
-
-
-from ayon_fusion.api.lib import get_current_comp
-from ayon_core.pipeline.publish import get_errored_instances_from_context
-
-
-class SelectInvalidAction(pyblish.api.Action):
- """Select invalid nodes in Fusion when plug-in failed.
-
- To retrieve the invalid nodes this assumes a static `get_invalid()`
- method is available on the plugin.
-
- """
-
- label = "Select invalid"
- on = "failed" # This action is only available on a failed plug-in
- icon = "search" # Icon from Awesome Icon
-
- def process(self, context, plugin):
- errored_instances = get_errored_instances_from_context(
- context,
- plugin=plugin,
- )
-
- # Get the invalid nodes for the plug-ins
- self.log.info("Finding invalid nodes..")
- invalid = list()
- for instance in errored_instances:
- invalid_nodes = plugin.get_invalid(instance)
- if invalid_nodes:
- if isinstance(invalid_nodes, (list, tuple)):
- invalid.extend(invalid_nodes)
- else:
- self.log.warning(
- "Plug-in returned to be invalid, "
- "but has no selectable nodes."
- )
-
- if not invalid:
- # Assume relevant comp is current comp and clear selection
- self.log.info("No invalid tools found.")
- comp = get_current_comp()
- flow = comp.CurrentFrame.FlowView
- flow.Select() # No args equals clearing selection
- return
-
- # Assume a single comp
- first_tool = invalid[0]
- comp = first_tool.Comp()
- flow = comp.CurrentFrame.FlowView
- flow.Select() # No args equals clearing selection
- names = set()
- for tool in invalid:
- flow.Select(tool, True)
- comp.SetActiveTool(tool)
- names.add(tool.Name)
- self.log.info(
- "Selecting invalid tools: %s" % ", ".join(sorted(names))
- )
-
-
-class SelectToolAction(pyblish.api.Action):
- """Select invalid output tool in Fusion when plug-in failed.
-
- """
-
- label = "Select saver"
- on = "failed" # This action is only available on a failed plug-in
- icon = "search" # Icon from Awesome Icon
-
- def process(self, context, plugin):
- errored_instances = get_errored_instances_from_context(
- context,
- plugin=plugin,
- )
-
- # Get the invalid nodes for the plug-ins
- self.log.info("Finding invalid nodes..")
- tools = []
- for instance in errored_instances:
-
- tool = instance.data.get("tool")
- if tool is not None:
- tools.append(tool)
- else:
- self.log.warning(
- "Plug-in returned to be invalid, "
- f"but has no saver for instance {instance.name}."
- )
-
- if not tools:
- # Assume relevant comp is current comp and clear selection
- self.log.info("No invalid tools found.")
- comp = get_current_comp()
- flow = comp.CurrentFrame.FlowView
- flow.Select() # No args equals clearing selection
- return
-
- # Assume a single comp
- first_tool = tools[0]
- comp = first_tool.Comp()
- flow = comp.CurrentFrame.FlowView
- flow.Select() # No args equals clearing selection
- names = set()
- for tool in tools:
- flow.Select(tool, True)
- comp.SetActiveTool(tool)
- names.add(tool.Name)
- self.log.info(
- "Selecting invalid tools: %s" % ", ".join(sorted(names))
- )
diff --git a/server_addon/fusion/client/ayon_fusion/api/lib.py b/server_addon/fusion/client/ayon_fusion/api/lib.py
deleted file mode 100644
index 7f7d20010d..0000000000
--- a/server_addon/fusion/client/ayon_fusion/api/lib.py
+++ /dev/null
@@ -1,402 +0,0 @@
-import os
-import sys
-import re
-import contextlib
-
-from ayon_core.lib import Logger, BoolDef, UILabelDef
-from ayon_core.style import load_stylesheet
-from ayon_core.pipeline import registered_host
-from ayon_core.pipeline.create import CreateContext
-from ayon_core.pipeline.context_tools import get_current_folder_entity
-
-self = sys.modules[__name__]
-self._project = None
-
-
-def update_frame_range(start, end, comp=None, set_render_range=True,
- handle_start=0, handle_end=0):
- """Set Fusion comp's start and end frame range
-
- Args:
- start (float, int): start frame
- end (float, int): end frame
- comp (object, Optional): comp object from fusion
- set_render_range (bool, Optional): When True this will also set the
- composition's render start and end frame.
- handle_start (float, int, Optional): frame handles before start frame
- handle_end (float, int, Optional): frame handles after end frame
-
- Returns:
- None
-
- """
-
- if not comp:
- comp = get_current_comp()
-
- # Convert any potential none type to zero
- handle_start = handle_start or 0
- handle_end = handle_end or 0
-
- attrs = {
- "COMPN_GlobalStart": start - handle_start,
- "COMPN_GlobalEnd": end + handle_end
- }
-
- # set frame range
- if set_render_range:
- attrs.update({
- "COMPN_RenderStart": start,
- "COMPN_RenderEnd": end
- })
-
- with comp_lock_and_undo_chunk(comp):
- comp.SetAttrs(attrs)
-
-
-def set_current_context_framerange(folder_entity=None):
- """Set Comp's frame range based on current folder."""
- if folder_entity is None:
- folder_entity = get_current_folder_entity(
- fields={"attrib.frameStart",
- "attrib.frameEnd",
- "attrib.handleStart",
- "attrib.handleEnd"})
-
- folder_attributes = folder_entity["attrib"]
- start = folder_attributes["frameStart"]
- end = folder_attributes["frameEnd"]
- handle_start = folder_attributes["handleStart"]
- handle_end = folder_attributes["handleEnd"]
- update_frame_range(start, end, set_render_range=True,
- handle_start=handle_start,
- handle_end=handle_end)
-
-
-def set_current_context_fps(folder_entity=None):
- """Set Comp's frame rate (FPS) to based on current asset"""
- if folder_entity is None:
- folder_entity = get_current_folder_entity(fields={"attrib.fps"})
-
- fps = float(folder_entity["attrib"].get("fps", 24.0))
- comp = get_current_comp()
- comp.SetPrefs({
- "Comp.FrameFormat.Rate": fps,
- })
-
-
-def set_current_context_resolution(folder_entity=None):
- """Set Comp's resolution width x height default based on current folder"""
- if folder_entity is None:
- folder_entity = get_current_folder_entity(
- fields={"attrib.resolutionWidth", "attrib.resolutionHeight"})
-
- folder_attributes = folder_entity["attrib"]
- width = folder_attributes["resolutionWidth"]
- height = folder_attributes["resolutionHeight"]
- comp = get_current_comp()
-
- print("Setting comp frame format resolution to {}x{}".format(width,
- height))
- comp.SetPrefs({
- "Comp.FrameFormat.Width": width,
- "Comp.FrameFormat.Height": height,
- })
-
-
-def validate_comp_prefs(comp=None, force_repair=False):
- """Validate current comp defaults with folder settings.
-
- Validates fps, resolutionWidth, resolutionHeight, aspectRatio.
-
- This does *not* validate frameStart, frameEnd, handleStart and handleEnd.
- """
-
- if comp is None:
- comp = get_current_comp()
-
- log = Logger.get_logger("validate_comp_prefs")
-
- fields = {
- "path",
- "attrib.fps",
- "attrib.resolutionWidth",
- "attrib.resolutionHeight",
- "attrib.pixelAspect",
- }
- folder_entity = get_current_folder_entity(fields=fields)
- folder_path = folder_entity["path"]
- folder_attributes = folder_entity["attrib"]
-
- comp_frame_format_prefs = comp.GetPrefs("Comp.FrameFormat")
-
- # Pixel aspect ratio in Fusion is set as AspectX and AspectY so we convert
- # the data to something that is more sensible to Fusion
- folder_attributes["pixelAspectX"] = folder_attributes.pop("pixelAspect")
- folder_attributes["pixelAspectY"] = 1.0
-
- validations = [
- ("fps", "Rate", "FPS"),
- ("resolutionWidth", "Width", "Resolution Width"),
- ("resolutionHeight", "Height", "Resolution Height"),
- ("pixelAspectX", "AspectX", "Pixel Aspect Ratio X"),
- ("pixelAspectY", "AspectY", "Pixel Aspect Ratio Y")
- ]
-
- invalid = []
- for key, comp_key, label in validations:
- folder_value = folder_attributes[key]
- comp_value = comp_frame_format_prefs.get(comp_key)
- if folder_value != comp_value:
- invalid_msg = "{} {} should be {}".format(label,
- comp_value,
- folder_value)
- invalid.append(invalid_msg)
-
- if not force_repair:
- # Do not log warning if we force repair anyway
- log.warning(
- "Comp {pref} {value} does not match folder "
- "'{folder_path}' {pref} {folder_value}".format(
- pref=label,
- value=comp_value,
- folder_path=folder_path,
- folder_value=folder_value)
- )
-
- if invalid:
-
- def _on_repair():
- attributes = dict()
- for key, comp_key, _label in validations:
- value = folder_attributes[key]
- comp_key_full = "Comp.FrameFormat.{}".format(comp_key)
- attributes[comp_key_full] = value
- comp.SetPrefs(attributes)
-
- if force_repair:
- log.info("Applying default Comp preferences..")
- _on_repair()
- return
-
- from . import menu
- from ayon_core.tools.utils import SimplePopup
- dialog = SimplePopup(parent=menu.menu)
- dialog.setWindowTitle("Fusion comp has invalid configuration")
-
- msg = "Comp preferences mismatches '{}'".format(folder_path)
- msg += "\n" + "\n".join(invalid)
- dialog.set_message(msg)
- dialog.set_button_text("Repair")
- dialog.on_clicked.connect(_on_repair)
- dialog.show()
- dialog.raise_()
- dialog.activateWindow()
- dialog.setStyleSheet(load_stylesheet())
-
-
-@contextlib.contextmanager
-def maintained_selection(comp=None):
- """Reset comp selection from before the context after the context"""
- if comp is None:
- comp = get_current_comp()
-
- previous_selection = comp.GetToolList(True).values()
- try:
- yield
- finally:
- flow = comp.CurrentFrame.FlowView
- flow.Select() # No args equals clearing selection
- if previous_selection:
- for tool in previous_selection:
- flow.Select(tool, True)
-
-
-@contextlib.contextmanager
-def maintained_comp_range(comp=None,
- global_start=True,
- global_end=True,
- render_start=True,
- render_end=True):
- """Reset comp frame ranges from before the context after the context"""
- if comp is None:
- comp = get_current_comp()
-
- comp_attrs = comp.GetAttrs()
- preserve_attrs = {}
- if global_start:
- preserve_attrs["COMPN_GlobalStart"] = comp_attrs["COMPN_GlobalStart"]
- if global_end:
- preserve_attrs["COMPN_GlobalEnd"] = comp_attrs["COMPN_GlobalEnd"]
- if render_start:
- preserve_attrs["COMPN_RenderStart"] = comp_attrs["COMPN_RenderStart"]
- if render_end:
- preserve_attrs["COMPN_RenderEnd"] = comp_attrs["COMPN_RenderEnd"]
-
- try:
- yield
- finally:
- comp.SetAttrs(preserve_attrs)
-
-
-def get_frame_path(path):
- """Get filename for the Fusion Saver with padded number as '#'
-
- >>> get_frame_path("C:/test.exr")
- ('C:/test', 4, '.exr')
-
- >>> get_frame_path("filename.00.tif")
- ('filename.', 2, '.tif')
-
- >>> get_frame_path("foobar35.tif")
- ('foobar', 2, '.tif')
-
- Args:
- path (str): The path to render to.
-
- Returns:
- tuple: head, padding, tail (extension)
-
- """
- filename, ext = os.path.splitext(path)
-
- # Find a final number group
- match = re.match('.*?([0-9]+)$', filename)
- if match:
- padding = len(match.group(1))
- # remove number from end since fusion
- # will swap it with the frame number
- filename = filename[:-padding]
- else:
- padding = 4 # default Fusion padding
-
- return filename, padding, ext
-
-
-def get_fusion_module():
- """Get current Fusion instance"""
- fusion = getattr(sys.modules["__main__"], "fusion", None)
- return fusion
-
-
-def get_bmd_library():
- """Get bmd library"""
- bmd = getattr(sys.modules["__main__"], "bmd", None)
- return bmd
-
-
-def get_current_comp():
- """Get current comp in this session"""
- fusion = get_fusion_module()
- if fusion is not None:
- comp = fusion.CurrentComp
- return comp
-
-
-@contextlib.contextmanager
-def comp_lock_and_undo_chunk(
- comp,
- undo_queue_name="Script CMD",
- keep_undo=True,
-):
- """Lock comp and open an undo chunk during the context"""
- try:
- comp.Lock()
- comp.StartUndo(undo_queue_name)
- yield
- finally:
- comp.Unlock()
- comp.EndUndo(keep_undo)
-
-
-def update_content_on_context_change():
- """Update all Creator instances to current asset"""
- host = registered_host()
- context = host.get_current_context()
-
- folder_path = context["folder_path"]
- task = context["task_name"]
-
- create_context = CreateContext(host, reset=True)
-
- for instance in create_context.instances:
- instance_folder_path = instance.get("folderPath")
- if instance_folder_path and instance_folder_path != folder_path:
- instance["folderPath"] = folder_path
- instance_task = instance.get("task")
- if instance_task and instance_task != task:
- instance["task"] = task
-
- create_context.save_changes()
-
-
-def prompt_reset_context():
- """Prompt the user what context settings to reset.
- This prompt is used on saving to a different task to allow the scene to
- get matched to the new context.
- """
- # TODO: Cleanup this prototyped mess of imports and odd dialog
- from ayon_core.tools.attribute_defs.dialog import (
- AttributeDefinitionsDialog
- )
- from qtpy import QtCore
-
- definitions = [
- UILabelDef(
- label=(
- "You are saving your workfile into a different folder or task."
- "\n\n"
- "Would you like to update some settings to the new context?\n"
- )
- ),
- BoolDef(
- "fps",
- label="FPS",
- tooltip="Reset Comp FPS",
- default=True
- ),
- BoolDef(
- "frame_range",
- label="Frame Range",
- tooltip="Reset Comp start and end frame ranges",
- default=True
- ),
- BoolDef(
- "resolution",
- label="Comp Resolution",
- tooltip="Reset Comp resolution",
- default=True
- ),
- BoolDef(
- "instances",
- label="Publish instances",
- tooltip="Update all publish instance's folder and task to match "
- "the new folder and task",
- default=True
- ),
- ]
-
- dialog = AttributeDefinitionsDialog(definitions)
- dialog.setWindowFlags(
- dialog.windowFlags() | QtCore.Qt.WindowStaysOnTopHint
- )
- dialog.setWindowTitle("Saving to different context.")
- dialog.setStyleSheet(load_stylesheet())
- if not dialog.exec_():
- return None
-
- options = dialog.get_values()
- folder_entity = get_current_folder_entity()
- if options["frame_range"]:
- set_current_context_framerange(folder_entity)
-
- if options["fps"]:
- set_current_context_fps(folder_entity)
-
- if options["resolution"]:
- set_current_context_resolution(folder_entity)
-
- if options["instances"]:
- update_content_on_context_change()
-
- dialog.deleteLater()
diff --git a/server_addon/fusion/client/ayon_fusion/api/menu.py b/server_addon/fusion/client/ayon_fusion/api/menu.py
deleted file mode 100644
index 38d8c36bb1..0000000000
--- a/server_addon/fusion/client/ayon_fusion/api/menu.py
+++ /dev/null
@@ -1,190 +0,0 @@
-import os
-import sys
-
-from qtpy import QtWidgets, QtCore, QtGui
-
-from ayon_core.tools.utils import host_tools
-from ayon_core.style import load_stylesheet
-from ayon_core.lib import register_event_callback
-from ayon_fusion.scripts import (
- duplicate_with_inputs,
-)
-from ayon_fusion.api.lib import (
- set_current_context_framerange,
- set_current_context_resolution,
-)
-from ayon_core.pipeline import get_current_folder_path
-from ayon_core.resources import get_ayon_icon_filepath
-from ayon_core.tools.utils import get_qt_app
-
-from .pipeline import FusionEventHandler
-from .pulse import FusionPulse
-
-
-MENU_LABEL = os.environ["AYON_MENU_LABEL"]
-
-
-self = sys.modules[__name__]
-self.menu = None
-
-
-class AYONMenu(QtWidgets.QWidget):
- def __init__(self, *args, **kwargs):
- super(AYONMenu, self).__init__(*args, **kwargs)
-
- self.setObjectName(f"{MENU_LABEL}Menu")
-
- icon_path = get_ayon_icon_filepath()
- icon = QtGui.QIcon(icon_path)
- self.setWindowIcon(icon)
-
- self.setWindowFlags(
- QtCore.Qt.Window
- | QtCore.Qt.CustomizeWindowHint
- | QtCore.Qt.WindowTitleHint
- | QtCore.Qt.WindowMinimizeButtonHint
- | QtCore.Qt.WindowCloseButtonHint
- | QtCore.Qt.WindowStaysOnTopHint
- )
- self.render_mode_widget = None
- self.setWindowTitle(MENU_LABEL)
-
- context_label = QtWidgets.QLabel("Context", self)
- context_label.setStyleSheet(
- """QLabel {
- font-size: 14px;
- font-weight: 600;
- color: #5f9fb8;
- }"""
- )
- context_label.setAlignment(QtCore.Qt.AlignHCenter)
-
- workfiles_btn = QtWidgets.QPushButton("Workfiles...", self)
- create_btn = QtWidgets.QPushButton("Create...", self)
- load_btn = QtWidgets.QPushButton("Load...", self)
- publish_btn = QtWidgets.QPushButton("Publish...", self)
- manager_btn = QtWidgets.QPushButton("Manage...", self)
- libload_btn = QtWidgets.QPushButton("Library...", self)
- set_framerange_btn = QtWidgets.QPushButton("Set Frame Range", self)
- set_resolution_btn = QtWidgets.QPushButton("Set Resolution", self)
- duplicate_with_inputs_btn = QtWidgets.QPushButton(
- "Duplicate with input connections", self
- )
-
- layout = QtWidgets.QVBoxLayout(self)
- layout.setContentsMargins(10, 20, 10, 20)
-
- layout.addWidget(context_label)
-
- layout.addSpacing(20)
-
- layout.addWidget(workfiles_btn)
-
- layout.addSpacing(20)
-
- layout.addWidget(create_btn)
- layout.addWidget(load_btn)
- layout.addWidget(publish_btn)
- layout.addWidget(manager_btn)
-
- layout.addSpacing(20)
-
- layout.addWidget(libload_btn)
-
- layout.addSpacing(20)
-
- layout.addWidget(set_framerange_btn)
- layout.addWidget(set_resolution_btn)
-
- layout.addSpacing(20)
-
- layout.addWidget(duplicate_with_inputs_btn)
-
- self.setLayout(layout)
-
- # Store reference so we can update the label
- self.context_label = context_label
-
- workfiles_btn.clicked.connect(self.on_workfile_clicked)
- create_btn.clicked.connect(self.on_create_clicked)
- publish_btn.clicked.connect(self.on_publish_clicked)
- load_btn.clicked.connect(self.on_load_clicked)
- manager_btn.clicked.connect(self.on_manager_clicked)
- libload_btn.clicked.connect(self.on_libload_clicked)
- duplicate_with_inputs_btn.clicked.connect(
- self.on_duplicate_with_inputs_clicked
- )
- set_resolution_btn.clicked.connect(self.on_set_resolution_clicked)
- set_framerange_btn.clicked.connect(self.on_set_framerange_clicked)
-
- self._callbacks = []
- self.register_callback("taskChanged", self.on_task_changed)
- self.on_task_changed()
-
- # Force close current process if Fusion is closed
- self._pulse = FusionPulse(parent=self)
- self._pulse.start()
-
- # Detect Fusion events as AYON events
- self._event_handler = FusionEventHandler(parent=self)
- self._event_handler.start()
-
- def on_task_changed(self):
- # Update current context label
- label = get_current_folder_path()
- self.context_label.setText(label)
-
- def register_callback(self, name, fn):
- # Create a wrapper callback that we only store
- # for as long as we want it to persist as callback
- def _callback(*args):
- fn()
-
- self._callbacks.append(_callback)
- register_event_callback(name, _callback)
-
- def deregister_all_callbacks(self):
- self._callbacks[:] = []
-
- def on_workfile_clicked(self):
- host_tools.show_workfiles()
-
- def on_create_clicked(self):
- host_tools.show_publisher(tab="create")
-
- def on_publish_clicked(self):
- host_tools.show_publisher(tab="publish")
-
- def on_load_clicked(self):
- host_tools.show_loader(use_context=True)
-
- def on_manager_clicked(self):
- host_tools.show_scene_inventory()
-
- def on_libload_clicked(self):
- host_tools.show_library_loader()
-
- def on_duplicate_with_inputs_clicked(self):
- duplicate_with_inputs.duplicate_with_input_connections()
-
- def on_set_resolution_clicked(self):
- set_current_context_resolution()
-
- def on_set_framerange_clicked(self):
- set_current_context_framerange()
-
-
-def launch_ayon_menu():
- app = get_qt_app()
-
- ayon_menu = AYONMenu()
-
- stylesheet = load_stylesheet()
- ayon_menu.setStyleSheet(stylesheet)
-
- ayon_menu.show()
- self.menu = ayon_menu
-
- result = app.exec_()
- print("Shutting down..")
- sys.exit(result)
diff --git a/server_addon/fusion/client/ayon_fusion/api/pipeline.py b/server_addon/fusion/client/ayon_fusion/api/pipeline.py
deleted file mode 100644
index 04f0d3db9a..0000000000
--- a/server_addon/fusion/client/ayon_fusion/api/pipeline.py
+++ /dev/null
@@ -1,439 +0,0 @@
-"""
-Basic avalon integration
-"""
-import os
-import sys
-import logging
-import contextlib
-from pathlib import Path
-
-import pyblish.api
-from qtpy import QtCore
-
-from ayon_core.lib import (
- Logger,
- register_event_callback,
- emit_event
-)
-from ayon_core.pipeline import (
- register_loader_plugin_path,
- register_creator_plugin_path,
- register_inventory_action_path,
- AVALON_CONTAINER_ID,
-)
-from ayon_core.pipeline.load import any_outdated_containers
-from ayon_core.host import HostBase, IWorkfileHost, ILoadHost, IPublishHost
-from ayon_core.tools.utils import host_tools
-from ayon_fusion import FUSION_ADDON_ROOT
-
-
-from .lib import (
- get_current_comp,
- validate_comp_prefs,
- prompt_reset_context
-)
-
-log = Logger.get_logger(__name__)
-
-PLUGINS_DIR = os.path.join(FUSION_ADDON_ROOT, "plugins")
-
-PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
-LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
-CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
-INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
-
-# Track whether the workfile tool is about to save
-_about_to_save = False
-
-
-class FusionLogHandler(logging.Handler):
- # Keep a reference to fusion's Print function (Remote Object)
- _print = None
-
- @property
- def print(self):
- if self._print is not None:
- # Use cached
- return self._print
-
- _print = getattr(sys.modules["__main__"], "fusion").Print
- if _print is None:
- # Backwards compatibility: Print method on Fusion instance was
- # added around Fusion 17.4 and wasn't available on PyRemote Object
- # before
- _print = get_current_comp().Print
- self._print = _print
- return _print
-
- def emit(self, record):
- entry = self.format(record)
- self.print(entry)
-
-
-class FusionHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
- name = "fusion"
-
- def install(self):
- """Install fusion-specific functionality of AYON.
-
- This is where you install menus and register families, data
- and loaders into fusion.
-
- It is called automatically when installing via
- `ayon_core.pipeline.install_host(ayon_fusion.api)`
-
- See the Maya equivalent for inspiration on how to implement this.
-
- """
- # Remove all handlers associated with the root logger object, because
- # that one always logs as "warnings" incorrectly.
- for handler in logging.root.handlers[:]:
- logging.root.removeHandler(handler)
-
- # Attach default logging handler that prints to active comp
- logger = logging.getLogger()
- formatter = logging.Formatter(fmt="%(message)s\n")
- handler = FusionLogHandler()
- handler.setFormatter(formatter)
- logger.addHandler(handler)
- logger.setLevel(logging.DEBUG)
-
- pyblish.api.register_host("fusion")
- pyblish.api.register_plugin_path(PUBLISH_PATH)
- log.info("Registering Fusion plug-ins..")
-
- register_loader_plugin_path(LOAD_PATH)
- register_creator_plugin_path(CREATE_PATH)
- register_inventory_action_path(INVENTORY_PATH)
-
- # Register events
- register_event_callback("open", on_after_open)
- register_event_callback("workfile.save.before", before_workfile_save)
- register_event_callback("save", on_save)
- register_event_callback("new", on_new)
- register_event_callback("taskChanged", on_task_changed)
-
- # region workfile io api
- def has_unsaved_changes(self):
- comp = get_current_comp()
- return comp.GetAttrs()["COMPB_Modified"]
-
- def get_workfile_extensions(self):
- return [".comp"]
-
- def save_workfile(self, dst_path=None):
- comp = get_current_comp()
- comp.Save(dst_path)
-
- def open_workfile(self, filepath):
- # Hack to get fusion, see
- # ayon_fusion.api.pipeline.get_current_comp()
- fusion = getattr(sys.modules["__main__"], "fusion", None)
-
- return fusion.LoadComp(filepath)
-
- def get_current_workfile(self):
- comp = get_current_comp()
- current_filepath = comp.GetAttrs()["COMPS_FileName"]
- if not current_filepath:
- return None
-
- return current_filepath
-
- def work_root(self, session):
- work_dir = session["AYON_WORKDIR"]
- scene_dir = session.get("AVALON_SCENEDIR")
- if scene_dir:
- return os.path.join(work_dir, scene_dir)
- else:
- return work_dir
- # endregion
-
- @contextlib.contextmanager
- def maintained_selection(self):
- from .lib import maintained_selection
- return maintained_selection()
-
- def get_containers(self):
- return ls()
-
- def update_context_data(self, data, changes):
- comp = get_current_comp()
- comp.SetData("openpype", data)
-
- def get_context_data(self):
- comp = get_current_comp()
- return comp.GetData("openpype") or {}
-
-
-def on_new(event):
- comp = event["Rets"]["comp"]
- validate_comp_prefs(comp, force_repair=True)
-
-
-def on_save(event):
- comp = event["sender"]
- validate_comp_prefs(comp)
-
- # We are now starting the actual save directly
- global _about_to_save
- _about_to_save = False
-
-
-def on_task_changed():
- global _about_to_save
- print(f"Task changed: {_about_to_save}")
- # TODO: Only do this if not headless
- if _about_to_save:
- # Let's prompt the user to update the context settings or not
- prompt_reset_context()
-
-
-def on_after_open(event):
- comp = event["sender"]
- validate_comp_prefs(comp)
-
- if any_outdated_containers():
- log.warning("Scene has outdated content.")
-
- # Find AYON menu to attach to
- from . import menu
-
- def _on_show_scene_inventory():
- # ensure that comp is active
- frame = comp.CurrentFrame
- if not frame:
- print("Comp is closed, skipping show scene inventory")
- return
- frame.ActivateFrame() # raise comp window
- host_tools.show_scene_inventory()
-
- from ayon_core.tools.utils import SimplePopup
- from ayon_core.style import load_stylesheet
- dialog = SimplePopup(parent=menu.menu)
- dialog.setWindowTitle("Fusion comp has outdated content")
- dialog.set_message("There are outdated containers in "
- "your Fusion comp.")
- dialog.on_clicked.connect(_on_show_scene_inventory)
- dialog.show()
- dialog.raise_()
- dialog.activateWindow()
- dialog.setStyleSheet(load_stylesheet())
-
-
-def before_workfile_save(event):
- # Due to Fusion's external python process design we can't really
- # detect whether the current Fusion environment matches the one the artists
- # expects it to be. For example, our pipeline python process might
- # have been shut down, and restarted - which will restart it to the
- # environment Fusion started with; not necessarily where the artist
- # is currently working.
- # The `_about_to_save` var is used to detect context changes when
- # saving into another asset. If we keep it False it will be ignored
- # as context change. As such, before we change tasks we will only
- # consider it the current filepath is within the currently known
- # AVALON_WORKDIR. This way we avoid false positives of thinking it's
- # saving to another context and instead sometimes just have false negatives
- # where we fail to show the "Update on task change" prompt.
- comp = get_current_comp()
- filepath = comp.GetAttrs()["COMPS_FileName"]
- workdir = os.environ.get("AYON_WORKDIR")
- if Path(workdir) in Path(filepath).parents:
- global _about_to_save
- _about_to_save = True
-
-
-def ls():
- """List containers from active Fusion scene
-
- This is the host-equivalent of api.ls(), but instead of listing
- assets on disk, it lists assets already loaded in Fusion; once loaded
- they are called 'containers'
-
- Yields:
- dict: container
-
- """
-
- comp = get_current_comp()
- tools = comp.GetToolList(False).values()
-
- for tool in tools:
- container = parse_container(tool)
- if container:
- yield container
-
-
-def imprint_container(tool,
- name,
- namespace,
- context,
- loader=None):
- """Imprint a Loader with metadata
-
- Containerisation enables a tracking of version, author and origin
- for loaded assets.
-
- Arguments:
- tool (object): The node in Fusion to imprint as container, usually a
- Loader.
- name (str): Name of resulting assembly
- namespace (str): Namespace under which to host container
- context (dict): Asset information
- loader (str, optional): Name of loader used to produce this container.
-
- Returns:
- None
-
- """
-
- data = [
- ("schema", "openpype:container-2.0"),
- ("id", AVALON_CONTAINER_ID),
- ("name", str(name)),
- ("namespace", str(namespace)),
- ("loader", str(loader)),
- ("representation", context["representation"]["id"]),
- ]
-
- for key, value in data:
- tool.SetData("avalon.{}".format(key), value)
-
-
-def parse_container(tool):
- """Returns imprinted container data of a tool
-
- This reads the imprinted data from `imprint_container`.
-
- """
-
- data = tool.GetData('avalon')
- if not isinstance(data, dict):
- return
-
- # If not all required data return the empty container
- required = ['schema', 'id', 'name',
- 'namespace', 'loader', 'representation']
- if not all(key in data for key in required):
- return
-
- container = {key: data[key] for key in required}
-
- # Store the tool's name
- container["objectName"] = tool.Name
-
- # Store reference to the tool object
- container["_tool"] = tool
-
- return container
-
-
-class FusionEventThread(QtCore.QThread):
- """QThread which will periodically ping Fusion app for any events.
- The fusion.UIManager must be set up to be notified of events before they'll
- be reported by this thread, for example:
- fusion.UIManager.AddNotify("Comp_Save", None)
-
- """
-
- on_event = QtCore.Signal(dict)
-
- def run(self):
-
- app = getattr(sys.modules["__main__"], "app", None)
- if app is None:
- # No Fusion app found
- return
-
- # As optimization store the GetEvent method directly because every
- # getattr of UIManager.GetEvent tries to resolve the Remote Function
- # through the PyRemoteObject
- get_event = app.UIManager.GetEvent
- delay = int(os.environ.get("AYON_FUSION_CALLBACK_INTERVAL", 1000))
- while True:
- if self.isInterruptionRequested():
- return
-
- # Process all events that have been queued up until now
- while True:
- event = get_event(False)
- if not event:
- break
- self.on_event.emit(event)
-
- # Wait some time before processing events again
- # to not keep blocking the UI
- self.msleep(delay)
-
-
-class FusionEventHandler(QtCore.QObject):
- """Emits AYON events based on Fusion events captured in a QThread.
-
- This will emit the following AYON events based on Fusion actions:
- save: Comp_Save, Comp_SaveAs
- open: Comp_Opened
- new: Comp_New
-
- To use this you can attach it to you Qt UI so it runs in the background.
- E.g.
- >>> handler = FusionEventHandler(parent=window)
- >>> handler.start()
-
- """
- ACTION_IDS = [
- "Comp_Save",
- "Comp_SaveAs",
- "Comp_New",
- "Comp_Opened"
- ]
-
- def __init__(self, parent=None):
- super(FusionEventHandler, self).__init__(parent=parent)
-
- # Set up Fusion event callbacks
- fusion = getattr(sys.modules["__main__"], "fusion", None)
- ui = fusion.UIManager
-
- # Add notifications for the ones we want to listen to
- notifiers = []
- for action_id in self.ACTION_IDS:
- notifier = ui.AddNotify(action_id, None)
- notifiers.append(notifier)
-
- # TODO: Not entirely sure whether these must be kept to avoid
- # garbage collection
- self._notifiers = notifiers
-
- self._event_thread = FusionEventThread(parent=self)
- self._event_thread.on_event.connect(self._on_event)
-
- def start(self):
- self._event_thread.start()
-
- def stop(self):
- self._event_thread.stop()
-
- def _on_event(self, event):
- """Handle Fusion events to emit AYON events"""
- if not event:
- return
-
- what = event["what"]
-
- # Comp Save
- if what in {"Comp_Save", "Comp_SaveAs"}:
- if not event["Rets"].get("success"):
- # If the Save action is cancelled it will still emit an
- # event but with "success": False so we ignore those cases
- return
- # Comp was saved
- emit_event("save", data=event)
- return
-
- # Comp New
- elif what in {"Comp_New"}:
- emit_event("new", data=event)
-
- # Comp Opened
- elif what in {"Comp_Opened"}:
- emit_event("open", data=event)
diff --git a/server_addon/fusion/client/ayon_fusion/api/plugin.py b/server_addon/fusion/client/ayon_fusion/api/plugin.py
deleted file mode 100644
index 48e133cc63..0000000000
--- a/server_addon/fusion/client/ayon_fusion/api/plugin.py
+++ /dev/null
@@ -1,278 +0,0 @@
-from copy import deepcopy
-import os
-
-from ayon_fusion.api import (
- get_current_comp,
- comp_lock_and_undo_chunk,
-)
-
-from ayon_core.lib import (
- BoolDef,
- EnumDef,
-)
-from ayon_core.pipeline import (
- Creator,
- CreatedInstance,
- AVALON_INSTANCE_ID,
- AYON_INSTANCE_ID,
-)
-from ayon_core.pipeline.workfile import get_workdir
-from ayon_api import (
- get_project,
- get_folder_by_path,
- get_task_by_name
-)
-
-
-class GenericCreateSaver(Creator):
- default_variants = ["Main", "Mask"]
- description = "Fusion Saver to generate image sequence"
- icon = "fa5.eye"
-
- instance_attributes = [
- "reviewable"
- ]
-
- settings_category = "fusion"
-
- image_format = "exr"
-
- # TODO: This should be renamed together with Nuke so it is aligned
- temp_rendering_path_template = (
- "{workdir}/renders/fusion/{product[name]}/"
- "{product[name]}.{frame}.{ext}"
- )
-
- def create(self, product_name, instance_data, pre_create_data):
- self.pass_pre_attributes_to_instance(instance_data, pre_create_data)
-
- instance = CreatedInstance(
- product_type=self.product_type,
- product_name=product_name,
- data=instance_data,
- creator=self,
- )
- data = instance.data_to_store()
- comp = get_current_comp()
- with comp_lock_and_undo_chunk(comp):
- args = (-32768, -32768) # Magical position numbers
- saver = comp.AddTool("Saver", *args)
-
- self._update_tool_with_data(saver, data=data)
-
- # Register the CreatedInstance
- self._imprint(saver, data)
-
- # Insert the transient data
- instance.transient_data["tool"] = saver
-
- self._add_instance_to_context(instance)
-
- return instance
-
- def collect_instances(self):
- comp = get_current_comp()
- tools = comp.GetToolList(False, "Saver").values()
- for tool in tools:
- data = self.get_managed_tool_data(tool)
- if not data:
- continue
-
- # Add instance
- created_instance = CreatedInstance.from_existing(data, self)
-
- # Collect transient data
- created_instance.transient_data["tool"] = tool
-
- self._add_instance_to_context(created_instance)
-
- def update_instances(self, update_list):
- for created_inst, _changes in update_list:
- new_data = created_inst.data_to_store()
- tool = created_inst.transient_data["tool"]
- self._update_tool_with_data(tool, new_data)
- self._imprint(tool, new_data)
-
- def remove_instances(self, instances):
- for instance in instances:
- # Remove the tool from the scene
-
- tool = instance.transient_data["tool"]
- if tool:
- tool.Delete()
-
- # Remove the collected CreatedInstance to remove from UI directly
- self._remove_instance_from_context(instance)
-
- def _imprint(self, tool, data):
- # Save all data in a "openpype.{key}" = value data
-
- # Instance id is the tool's name so we don't need to imprint as data
- data.pop("instance_id", None)
-
- active = data.pop("active", None)
- if active is not None:
- # Use active value to set the passthrough state
- tool.SetAttrs({"TOOLB_PassThrough": not active})
-
- for key, value in data.items():
- tool.SetData(f"openpype.{key}", value)
-
- def _update_tool_with_data(self, tool, data):
- """Update tool node name and output path based on product data"""
- if "productName" not in data:
- return
-
- original_product_name = tool.GetData("openpype.productName")
- original_format = tool.GetData(
- "openpype.creator_attributes.image_format"
- )
-
- product_name = data["productName"]
- if (
- original_product_name != product_name
- or tool.GetData("openpype.task") != data["task"]
- or tool.GetData("openpype.folderPath") != data["folderPath"]
- or original_format != data["creator_attributes"]["image_format"]
- ):
- self._configure_saver_tool(data, tool, product_name)
-
- def _configure_saver_tool(self, data, tool, product_name):
- formatting_data = deepcopy(data)
-
- # get frame padding from anatomy templates
- frame_padding = self.project_anatomy.templates_obj.frame_padding
-
- # get output format
- ext = data["creator_attributes"]["image_format"]
-
- # Product change detected
- product_type = formatting_data["productType"]
- f_product_name = formatting_data["productName"]
-
- folder_path = formatting_data["folderPath"]
- folder_name = folder_path.rsplit("/", 1)[-1]
-
- # If the folder path and task do not match the current context then the
- # workdir is not just the `AYON_WORKDIR`. Hence, we need to actually
- # compute the resulting workdir
- if (
- data["folderPath"] == self.create_context.get_current_folder_path()
- and data["task"] == self.create_context.get_current_task_name()
- ):
- workdir = os.path.normpath(os.getenv("AYON_WORKDIR"))
- else:
- # TODO: Optimize this logic
- project_name = self.create_context.get_current_project_name()
- project_entity = get_project(project_name)
- folder_entity = get_folder_by_path(project_name,
- data["folderPath"])
- task_entity = get_task_by_name(project_name,
- folder_id=folder_entity["id"],
- task_name=data["task"])
- workdir = get_workdir(
- project_entity=project_entity,
- folder_entity=folder_entity,
- task_entity=task_entity,
- host_name=self.create_context.host_name,
- )
-
- formatting_data.update({
- "workdir": workdir,
- "frame": "0" * frame_padding,
- "ext": ext,
- "product": {
- "name": f_product_name,
- "type": product_type,
- },
- # TODO add more variants for 'folder' and 'task'
- "folder": {
- "name": folder_name,
- },
- "task": {
- "name": data["task"],
- },
- # Backwards compatibility
- "asset": folder_name,
- "subset": f_product_name,
- "family": product_type,
- })
-
- # build file path to render
- # TODO make sure the keys are available in 'formatting_data'
- temp_rendering_path_template = (
- self.temp_rendering_path_template
- .replace("{task}", "{task[name]}")
- )
-
- filepath = temp_rendering_path_template.format(**formatting_data)
-
- comp = get_current_comp()
- tool["Clip"] = comp.ReverseMapPath(os.path.normpath(filepath))
-
- # Rename tool
- if tool.Name != product_name:
- print(f"Renaming {tool.Name} -> {product_name}")
- tool.SetAttrs({"TOOLS_Name": product_name})
-
- def get_managed_tool_data(self, tool):
- """Return data of the tool if it matches creator identifier"""
- data = tool.GetData("openpype")
- if not isinstance(data, dict):
- return
-
- if (
- data.get("creator_identifier") != self.identifier
- or data.get("id") not in {
- AYON_INSTANCE_ID, AVALON_INSTANCE_ID
- }
- ):
- return
-
- # Get active state from the actual tool state
- attrs = tool.GetAttrs()
- passthrough = attrs["TOOLB_PassThrough"]
- data["active"] = not passthrough
-
- # Override publisher's UUID generation because tool names are
- # already unique in Fusion in a comp
- data["instance_id"] = tool.Name
-
- return data
-
- def get_instance_attr_defs(self):
- """Settings for publish page"""
- return self.get_pre_create_attr_defs()
-
- def pass_pre_attributes_to_instance(self, instance_data, pre_create_data):
- creator_attrs = instance_data["creator_attributes"] = {}
- for pass_key in pre_create_data.keys():
- creator_attrs[pass_key] = pre_create_data[pass_key]
-
- def _get_render_target_enum(self):
- rendering_targets = {
- "local": "Local machine rendering",
- "frames": "Use existing frames",
- }
- if "farm_rendering" in self.instance_attributes:
- rendering_targets["farm"] = "Farm rendering"
-
- return EnumDef(
- "render_target", items=rendering_targets, label="Render target"
- )
-
- def _get_reviewable_bool(self):
- return BoolDef(
- "review",
- default=("reviewable" in self.instance_attributes),
- label="Review",
- )
-
- def _get_image_format_enum(self):
- image_format_options = ["exr", "tga", "tif", "png", "jpg"]
- return EnumDef(
- "image_format",
- items=image_format_options,
- default=self.image_format,
- label="Output Image Format",
- )
diff --git a/server_addon/fusion/client/ayon_fusion/api/pulse.py b/server_addon/fusion/client/ayon_fusion/api/pulse.py
deleted file mode 100644
index 7128b7e1ff..0000000000
--- a/server_addon/fusion/client/ayon_fusion/api/pulse.py
+++ /dev/null
@@ -1,63 +0,0 @@
-import os
-import sys
-
-from qtpy import QtCore
-
-
-class PulseThread(QtCore.QThread):
- no_response = QtCore.Signal()
-
- def __init__(self, parent=None):
- super(PulseThread, self).__init__(parent=parent)
-
- def run(self):
- app = getattr(sys.modules["__main__"], "app", None)
-
- # Interval in milliseconds
- interval = os.environ.get("AYON_FUSION_PULSE_INTERVAL", 1000)
-
- while True:
- if self.isInterruptionRequested():
- return
-
- # We don't need to call Test because PyRemoteObject of the app
- # will actually fail to even resolve the Test function if it has
- # gone down. So we can actually already just check by confirming
- # the method is still getting resolved. (Optimization)
- if app.Test is None:
- self.no_response.emit()
-
- self.msleep(interval)
-
-
-class FusionPulse(QtCore.QObject):
- """A Timer that checks whether host app is still alive.
-
- This checks whether the Fusion process is still active at a certain
- interval. This is useful due to how Fusion runs its scripts. Each script
- runs in its own environment and process (a `fusionscript` process each).
- If Fusion would go down and we have a UI process running at the same time
- then it can happen that the `fusionscript.exe` will remain running in the
- background in limbo due to e.g. a Qt interface's QApplication that keeps
- running infinitely.
-
- Warning:
- When the host is not detected this will automatically exit
- the current process.
-
- """
-
- def __init__(self, parent=None):
- super(FusionPulse, self).__init__(parent=parent)
- self._thread = PulseThread(parent=self)
- self._thread.no_response.connect(self.on_no_response)
-
- def on_no_response(self):
- print("Pulse detected no response from Fusion..")
- sys.exit(1)
-
- def start(self):
- self._thread.start()
-
- def stop(self):
- self._thread.requestInterruption()
diff --git a/server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/README.md b/server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/README.md
deleted file mode 100644
index e291b8d8f2..0000000000
--- a/server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-### AYON deploy MenuScripts
-
-Note that this `MenuScripts` is not an official Fusion folder.
-AYON only uses this folder in `{fusion}/deploy/` to trigger the AYON menu actions.
-
-They are used in the actions defined in `.fu` files in `{fusion}/deploy/Config`.
\ No newline at end of file
diff --git a/server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/install_pyside2.py b/server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/install_pyside2.py
deleted file mode 100644
index e1240fd677..0000000000
--- a/server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/install_pyside2.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# This is just a quick hack for users running Py3 locally but having no
-# Qt library installed
-import os
-import subprocess
-import importlib
-
-
-try:
- from qtpy import API_NAME
-
- print(f"Qt binding: {API_NAME}")
- mod = importlib.import_module(API_NAME)
- print(f"Qt path: {mod.__file__}")
- print("Qt library found, nothing to do..")
-
-except ImportError:
- print("Assuming no Qt library is installed..")
- print('Installing PySide2 for Python 3.6: '
- f'{os.environ["FUSION16_PYTHON36_HOME"]}')
-
- # Get full path to python executable
- exe = "python.exe" if os.name == 'nt' else "python"
- python = os.path.join(os.environ["FUSION16_PYTHON36_HOME"], exe)
- assert os.path.exists(python), f"Python doesn't exist: {python}"
-
- # Do python -m pip install PySide2
- args = [python, "-m", "pip", "install", "PySide2"]
- print(f"Args: {args}")
- subprocess.Popen(args)
diff --git a/server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/launch_menu.py b/server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/launch_menu.py
deleted file mode 100644
index 0c5010f6a7..0000000000
--- a/server_addon/fusion/client/ayon_fusion/deploy/MenuScripts/launch_menu.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import os
-import sys
-
-if sys.version_info < (3, 7):
- # hack to handle discrepancy between distributed libraries and Python 3.6
- # mostly because wrong version of urllib3
- # TODO remove when not necessary
- from ayon_fusion import FUSION_ADDON_ROOT
-
- vendor_path = os.path.join(FUSION_ADDON_ROOT, "vendor")
- if vendor_path not in sys.path:
- sys.path.insert(0, vendor_path)
-
- print(f"Added vendorized libraries from {vendor_path}")
-
-from ayon_core.lib import Logger
-from ayon_core.pipeline import (
- install_host,
- registered_host,
-)
-
-
-def main(env):
- # This script working directory starts in Fusion application folder.
- # However the contents of that folder can conflict with Qt library dlls
- # so we make sure to move out of it to avoid DLL Load Failed errors.
- os.chdir("..")
- from ayon_fusion.api import FusionHost
- from ayon_fusion.api import menu
-
- # activate resolve from pype
- install_host(FusionHost())
-
- log = Logger.get_logger(__name__)
- log.info(f"Registered host: {registered_host()}")
-
- menu.launch_ayon_menu()
-
- # Initiate a QTimer to check if Fusion is still alive every X interval
- # If Fusion is not found - kill itself
- # todo(roy): Implement timer that ensures UI doesn't remain when e.g.
- # Fusion closes down
-
-
-if __name__ == "__main__":
- result = main(os.environ)
- sys.exit(not bool(result))
diff --git a/server_addon/fusion/client/ayon_fusion/deploy/ayon/Config/menu.fu b/server_addon/fusion/client/ayon_fusion/deploy/ayon/Config/menu.fu
deleted file mode 100644
index c968a1bb3d..0000000000
--- a/server_addon/fusion/client/ayon_fusion/deploy/ayon/Config/menu.fu
+++ /dev/null
@@ -1,60 +0,0 @@
-{
- Action
- {
- ID = "AYON_Menu",
- Category = "AYON",
- Name = "AYON Menu",
-
- Targets =
- {
- Composition =
- {
- Execute = _Lua [=[
- local scriptPath = app:MapPath("AYON:../MenuScripts/launch_menu.py")
- if bmd.fileexists(scriptPath) == false then
- print("[AYON Error] Can't run file: " .. scriptPath)
- else
- target:RunScript(scriptPath)
- end
- ]=],
- },
- },
- },
- Action
- {
- ID = "AYON_Install_PySide2",
- Category = "AYON",
- Name = "Install PySide2",
-
- Targets =
- {
- Composition =
- {
- Execute = _Lua [=[
- local scriptPath = app:MapPath("AYON:../MenuScripts/install_pyside2.py")
- if bmd.fileexists(scriptPath) == false then
- print("[AYON Error] Can't run file: " .. scriptPath)
- else
- target:RunScript(scriptPath)
- end
- ]=],
- },
- },
- },
- Menus
- {
- Target = "ChildFrame",
-
- Before "Help"
- {
- Sub "AYON"
- {
- "AYON_Menu{}",
- "_",
- Sub "Admin" {
- "AYON_Install_PySide2{}"
- }
- }
- },
- },
-}
diff --git a/server_addon/fusion/client/ayon_fusion/deploy/ayon/fusion_shared.prefs b/server_addon/fusion/client/ayon_fusion/deploy/ayon/fusion_shared.prefs
deleted file mode 100644
index 59b0f82bad..0000000000
--- a/server_addon/fusion/client/ayon_fusion/deploy/ayon/fusion_shared.prefs
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-Locked = true,
-Global = {
- Paths = {
- Map = {
- ["AYON:"] = "$(AYON_FUSION_ROOT)/deploy/ayon",
- ["Config:"] = "UserPaths:Config;AYON:Config",
- ["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts",
- },
- },
- Script = {
- PythonVersion = 3,
- Python3Forced = true
- },
- UserInterface = {
- Language = "en_US"
- },
- },
-}
diff --git a/server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_launch_menu_hook.py b/server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_launch_menu_hook.py
deleted file mode 100644
index 035cbb8d97..0000000000
--- a/server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_launch_menu_hook.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import os
-from ayon_applications import PreLaunchHook
-from ayon_fusion import FUSION_ADDON_ROOT
-
-
-class FusionLaunchMenuHook(PreLaunchHook):
- """Launch AYON menu on start of Fusion"""
- app_groups = ["fusion"]
- order = 9
-
- def execute(self):
- # Prelaunch hook is optional
- settings = self.data["project_settings"][self.host_name]
- if not settings["hooks"]["FusionLaunchMenuHook"]["enabled"]:
- return
-
- variant = self.application.name
- if variant.isnumeric():
- version = int(variant)
- if version < 18:
- print("Skipping launch of OpenPype menu on Fusion start "
- "because Fusion version below 18.0 does not support "
- "/execute argument on launch. "
- f"Version detected: {version}")
- return
- else:
- print(f"Application variant is not numeric: {variant}. "
- "Validation for Fusion version 18+ for /execute "
- "prelaunch argument skipped.")
-
- path = os.path.join(FUSION_ADDON_ROOT,
- "deploy",
- "MenuScripts",
- "launch_menu.py").replace("\\", "/")
- script = f"fusion:RunScript('{path}')"
- self.launch_context.launch_args.extend(["/execute", script])
diff --git a/server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_profile_hook.py b/server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_profile_hook.py
deleted file mode 100644
index 7758798bb6..0000000000
--- a/server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_profile_hook.py
+++ /dev/null
@@ -1,169 +0,0 @@
-import os
-import shutil
-import platform
-from pathlib import Path
-from ayon_fusion import (
- FUSION_ADDON_ROOT,
- FUSION_VERSIONS_DICT,
- get_fusion_version,
-)
-from ayon_applications import (
- PreLaunchHook,
- LaunchTypes,
- ApplicationLaunchFailed,
-)
-
-
-class FusionCopyPrefsPrelaunch(PreLaunchHook):
- """
- Prepares local Fusion profile directory, copies existing Fusion profile.
- This also sets FUSION MasterPrefs variable, which is used
- to apply Master.prefs file to override some Fusion profile settings to:
- - enable the AYON menu
- - force Python 3 over Python 2
- - force English interface
- Master.prefs is defined in openpype/hosts/fusion/deploy/fusion_shared.prefs
- """
-
- app_groups = {"fusion"}
- order = 2
- launch_types = {LaunchTypes.local}
-
- def get_fusion_profile_name(self, profile_version) -> str:
- # Returns 'Default', unless FUSION16_PROFILE is set
- return os.getenv(f"FUSION{profile_version}_PROFILE", "Default")
-
- def get_fusion_profile_dir(self, profile_version) -> Path:
- # Get FUSION_PROFILE_DIR variable
- fusion_profile = self.get_fusion_profile_name(profile_version)
- fusion_var_prefs_dir = os.getenv(
- f"FUSION{profile_version}_PROFILE_DIR"
- )
-
- # Check if FUSION_PROFILE_DIR exists
- if fusion_var_prefs_dir and Path(fusion_var_prefs_dir).is_dir():
- fu_prefs_dir = Path(fusion_var_prefs_dir, fusion_profile)
- self.log.info(f"{fusion_var_prefs_dir} is set to {fu_prefs_dir}")
- return fu_prefs_dir
-
- def get_profile_source(self, profile_version) -> Path:
- """Get Fusion preferences profile location.
- See Per-User_Preferences_and_Paths on VFXpedia for reference.
- """
- fusion_profile = self.get_fusion_profile_name(profile_version)
- profile_source = self.get_fusion_profile_dir(profile_version)
- if profile_source:
- return profile_source
- # otherwise get default location of the profile folder
- fu_prefs_dir = f"Blackmagic Design/Fusion/Profiles/{fusion_profile}"
- if platform.system() == "Windows":
- profile_source = Path(os.getenv("AppData"), fu_prefs_dir)
- elif platform.system() == "Darwin":
- profile_source = Path(
- "~/Library/Application Support/", fu_prefs_dir
- ).expanduser()
- elif platform.system() == "Linux":
- profile_source = Path("~/.fusion", fu_prefs_dir).expanduser()
- self.log.info(
- f"Locating source Fusion prefs directory: {profile_source}"
- )
- return profile_source
-
- def get_copy_fusion_prefs_settings(self):
- # Get copy preferences options from the global application settings
-
- copy_fusion_settings = self.data["project_settings"]["fusion"].get(
- "copy_fusion_settings", {}
- )
- if not copy_fusion_settings:
- self.log.error("Copy prefs settings not found")
- copy_status = copy_fusion_settings.get("copy_status", False)
- force_sync = copy_fusion_settings.get("force_sync", False)
- copy_path = copy_fusion_settings.get("copy_path") or None
- if copy_path:
- copy_path = Path(copy_path).expanduser()
- return copy_status, copy_path, force_sync
-
- def copy_fusion_profile(
- self, copy_from: Path, copy_to: Path, force_sync: bool
- ) -> None:
- """On the first Fusion launch copy the contents of Fusion profile
- directory to the working predefined location. If the Openpype profile
- folder exists, skip copying, unless re-sync is checked.
- If the prefs were not copied on the first launch,
- clean Fusion profile will be created in fu_profile_dir.
- """
- if copy_to.exists() and not force_sync:
- self.log.info(
- "Destination Fusion preferences folder already exists: "
- f"{copy_to} "
- )
- return
- self.log.info("Starting copying Fusion preferences")
- self.log.debug(f"force_sync option is set to {force_sync}")
- try:
- copy_to.mkdir(exist_ok=True, parents=True)
- except PermissionError:
- self.log.warning(f"Creating the folder not permitted at {copy_to}")
- return
- if not copy_from.exists():
- self.log.warning(f"Fusion preferences not found in {copy_from}")
- return
- for file in copy_from.iterdir():
- if file.suffix in (
- ".prefs",
- ".def",
- ".blocklist",
- ".fu",
- ".toolbars",
- ):
- # convert Path to str to be compatible with Python 3.6+
- shutil.copy(str(file), str(copy_to))
- self.log.info(
- f"Successfully copied preferences: {copy_from} to {copy_to}"
- )
-
- def execute(self):
- (
- copy_status,
- fu_profile_dir,
- force_sync,
- ) = self.get_copy_fusion_prefs_settings()
-
- # Get launched application context and return correct app version
- app_name = self.launch_context.env.get("AYON_APP_NAME")
- app_version = get_fusion_version(app_name)
- if app_version is None:
- version_names = ", ".join(str(x) for x in FUSION_VERSIONS_DICT)
- raise ApplicationLaunchFailed(
- "Unable to detect valid Fusion version number from app "
- f"name: {app_name}.\nMake sure to include at least a digit "
- "to indicate the Fusion version like '18'.\n"
- f"Detectable Fusion versions are: {version_names}"
- )
-
- _, profile_version = FUSION_VERSIONS_DICT[app_version]
- fu_profile = self.get_fusion_profile_name(profile_version)
-
- # do a copy of Fusion profile if copy_status toggle is enabled
- if copy_status and fu_profile_dir is not None:
- profile_source = self.get_profile_source(profile_version)
- dest_folder = Path(fu_profile_dir, fu_profile)
- self.copy_fusion_profile(profile_source, dest_folder, force_sync)
-
- # Add temporary profile directory variables to customize Fusion
- # to define where it can read custom scripts and tools from
- fu_profile_dir_variable = f"FUSION{profile_version}_PROFILE_DIR"
- self.log.info(f"Setting {fu_profile_dir_variable}: {fu_profile_dir}")
- self.launch_context.env[fu_profile_dir_variable] = str(fu_profile_dir)
-
- # Add custom Fusion Master Prefs and the temporary
- # profile directory variables to customize Fusion
- # to define where it can read custom scripts and tools from
- master_prefs_variable = f"FUSION{profile_version}_MasterPrefs"
-
- master_prefs = Path(
- FUSION_ADDON_ROOT, "deploy", "ayon", "fusion_shared.prefs")
-
- self.log.info(f"Setting {master_prefs_variable}: {master_prefs}")
- self.launch_context.env[master_prefs_variable] = str(master_prefs)
diff --git a/server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_setup.py b/server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_setup.py
deleted file mode 100644
index 25cf40f18d..0000000000
--- a/server_addon/fusion/client/ayon_fusion/hooks/pre_fusion_setup.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import os
-from ayon_applications import (
- PreLaunchHook,
- LaunchTypes,
- ApplicationLaunchFailed,
-)
-from ayon_fusion import (
- FUSION_ADDON_ROOT,
- FUSION_VERSIONS_DICT,
- get_fusion_version,
-)
-
-
-class FusionPrelaunch(PreLaunchHook):
- """
- Prepares AYON Fusion environment.
- Requires correct Python home variable to be defined in the environment
- settings for Fusion to point at a valid Python 3 build for Fusion.
- Python3 versions that are supported by Fusion:
- Fusion 9, 16, 17 : Python 3.6
- Fusion 18 : Python 3.6 - 3.10
- """
-
- app_groups = {"fusion"}
- order = 1
- launch_types = {LaunchTypes.local}
-
- def execute(self):
- # making sure python 3 is installed at provided path
- # Py 3.3-3.10 for Fusion 18+ or Py 3.6 for Fu 16-17
- app_data = self.launch_context.env.get("AYON_APP_NAME")
- app_version = get_fusion_version(app_data)
- if not app_version:
- raise ApplicationLaunchFailed(
- "Fusion version information not found in System settings.\n"
- "The key field in the 'applications/fusion/variants' should "
- "consist a number, corresponding to major Fusion version."
- )
- py3_var, _ = FUSION_VERSIONS_DICT[app_version]
- fusion_python3_home = self.launch_context.env.get(py3_var, "")
-
- for path in fusion_python3_home.split(os.pathsep):
- # Allow defining multiple paths, separated by os.pathsep,
- # to allow "fallback" to other path.
- # But make to set only a single path as final variable.
- py3_dir = os.path.normpath(path)
- if os.path.isdir(py3_dir):
- break
- else:
- raise ApplicationLaunchFailed(
- "Python 3 is not installed at the provided path.\n"
- "Make sure the environment in fusion settings has "
- "'FUSION_PYTHON3_HOME' set correctly and make sure "
- "Python 3 is installed in the given path."
- f"\n\nPYTHON PATH: {fusion_python3_home}"
- )
-
- self.log.info(f"Setting {py3_var}: '{py3_dir}'...")
- self.launch_context.env[py3_var] = py3_dir
-
- # Fusion 18+ requires FUSION_PYTHON3_HOME to also be on PATH
- if app_version >= 18:
- self.launch_context.env["PATH"] += os.pathsep + py3_dir
-
- self.launch_context.env[py3_var] = py3_dir
-
- # for hook installing PySide2
- self.data["fusion_python3_home"] = py3_dir
-
- self.log.info(f"Setting AYON_FUSION_ROOT: {FUSION_ADDON_ROOT}")
- self.launch_context.env["AYON_FUSION_ROOT"] = FUSION_ADDON_ROOT
diff --git a/server_addon/fusion/client/ayon_fusion/hooks/pre_pyside_install.py b/server_addon/fusion/client/ayon_fusion/hooks/pre_pyside_install.py
deleted file mode 100644
index 4678d5bac7..0000000000
--- a/server_addon/fusion/client/ayon_fusion/hooks/pre_pyside_install.py
+++ /dev/null
@@ -1,185 +0,0 @@
-import os
-import subprocess
-import platform
-import uuid
-
-from ayon_applications import PreLaunchHook, LaunchTypes
-
-
-class InstallPySideToFusion(PreLaunchHook):
- """Automatically installs Qt binding to fusion's python packages.
-
- Check if fusion has installed PySide2 and will try to install if not.
-
- For pipeline implementation is required to have Qt binding installed in
- fusion's python packages.
- """
-
- app_groups = {"fusion"}
- order = 2
- launch_types = {LaunchTypes.local}
-
- def execute(self):
- # Prelaunch hook is not crucial
- try:
- settings = self.data["project_settings"][self.host_name]
- if not settings["hooks"]["InstallPySideToFusion"]["enabled"]:
- return
- self.inner_execute()
- except Exception:
- self.log.warning(
- "Processing of {} crashed.".format(self.__class__.__name__),
- exc_info=True
- )
-
- def inner_execute(self):
- self.log.debug("Check for PySide2 installation.")
-
- fusion_python3_home = self.data.get("fusion_python3_home")
- if not fusion_python3_home:
- self.log.warning("'fusion_python3_home' was not provided. "
- "Installation of PySide2 not possible")
- return
-
- if platform.system().lower() == "windows":
- exe_filenames = ["python.exe"]
- else:
- exe_filenames = ["python3", "python"]
-
- for exe_filename in exe_filenames:
- python_executable = os.path.join(fusion_python3_home, exe_filename)
- if os.path.exists(python_executable):
- break
-
- if not os.path.exists(python_executable):
- self.log.warning(
- "Couldn't find python executable for fusion. {}".format(
- python_executable
- )
- )
- return
-
- # Check if PySide2 is installed and skip if yes
- if self._is_pyside_installed(python_executable):
- self.log.debug("Fusion has already installed PySide2.")
- return
-
- self.log.debug("Installing PySide2.")
- # Install PySide2 in fusion's python
- if self._windows_require_permissions(
- os.path.dirname(python_executable)):
- result = self._install_pyside_windows(python_executable)
- else:
- result = self._install_pyside(python_executable)
-
- if result:
- self.log.info("Successfully installed PySide2 module to fusion.")
- else:
- self.log.warning("Failed to install PySide2 module to fusion.")
-
- def _install_pyside_windows(self, python_executable):
- """Install PySide2 python module to fusion's python.
-
- Installation requires administration rights that's why it is required
- to use "pywin32" module which can execute command's and ask for
- administration rights.
- """
- try:
- import win32con
- import win32process
- import win32event
- import pywintypes
- from win32comext.shell.shell import ShellExecuteEx
- from win32comext.shell import shellcon
- except Exception:
- self.log.warning("Couldn't import \"pywin32\" modules")
- return False
-
- try:
- # Parameters
- # - use "-m pip" as module pip to install PySide2 and argument
- # "--ignore-installed" is to force install module to fusion's
- # site-packages and make sure it is binary compatible
- parameters = "-m pip install --ignore-installed PySide2"
-
- # Execute command and ask for administrator's rights
- process_info = ShellExecuteEx(
- nShow=win32con.SW_SHOWNORMAL,
- fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
- lpVerb="runas",
- lpFile=python_executable,
- lpParameters=parameters,
- lpDirectory=os.path.dirname(python_executable)
- )
- process_handle = process_info["hProcess"]
- win32event.WaitForSingleObject(process_handle,
- win32event.INFINITE)
- returncode = win32process.GetExitCodeProcess(process_handle)
- return returncode == 0
- except pywintypes.error:
- return False
-
- def _install_pyside(self, python_executable):
- """Install PySide2 python module to fusion's python."""
- try:
- # Parameters
- # - use "-m pip" as module pip to install PySide2 and argument
- # "--ignore-installed" is to force install module to fusion's
- # site-packages and make sure it is binary compatible
- env = dict(os.environ)
- del env['PYTHONPATH']
- args = [
- python_executable,
- "-m",
- "pip",
- "install",
- "--ignore-installed",
- "PySide2",
- ]
- process = subprocess.Popen(
- args, stdout=subprocess.PIPE, universal_newlines=True,
- env=env
- )
- process.communicate()
- return process.returncode == 0
- except PermissionError:
- self.log.warning(
- "Permission denied with command:"
- "\"{}\".".format(" ".join(args))
- )
- except OSError as error:
- self.log.warning(f"OS error has occurred: \"{error}\".")
- except subprocess.SubprocessError:
- pass
-
- def _is_pyside_installed(self, python_executable):
- """Check if PySide2 module is in fusion's pip list."""
- args = [python_executable, "-c", "from qtpy import QtWidgets"]
- process = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- _, stderr = process.communicate()
- stderr = stderr.decode()
- if stderr:
- return False
- return True
-
- def _windows_require_permissions(self, dirpath):
- if platform.system().lower() != "windows":
- return False
-
- try:
- # Attempt to create a temporary file in the folder
- temp_file_path = os.path.join(dirpath, uuid.uuid4().hex)
- with open(temp_file_path, "w"):
- pass
- os.remove(temp_file_path) # Clean up temporary file
- return False
-
- except PermissionError:
- return True
-
- except BaseException as exc:
- print(("Failed to determine if root requires permissions."
- "Unexpected error: {}").format(exc))
- return False
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/create/create_image_saver.py b/server_addon/fusion/client/ayon_fusion/plugins/create/create_image_saver.py
deleted file mode 100644
index d88219b268..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/create/create_image_saver.py
+++ /dev/null
@@ -1,63 +0,0 @@
-from ayon_core.lib import NumberDef
-
-from ayon_fusion.api.plugin import GenericCreateSaver
-
-
-class CreateImageSaver(GenericCreateSaver):
- """Fusion Saver to generate single image.
-
- Created to explicitly separate single ('image') or
- multi frame('render) outputs.
-
- This might be temporary creator until 'alias' functionality will be
- implemented to limit creation of additional product types with similar, but
- not the same workflows.
- """
- identifier = "io.openpype.creators.fusion.imagesaver"
- label = "Image (saver)"
- name = "image"
- product_type = "image"
- description = "Fusion Saver to generate image"
-
- default_frame = 0
-
- def get_detail_description(self):
- return """Fusion Saver to generate single image.
-
- This creator is expected for publishing of single frame `image` product
- type.
-
- Artist should provide frame number (integer) to specify which frame
- should be published. It must be inside of global timeline frame range.
-
- Supports local and deadline rendering.
-
- Supports selection from predefined set of output file extensions:
- - exr
- - tga
- - png
- - tif
- - jpg
-
- Created to explicitly separate single frame ('image') or
- multi frame ('render') outputs.
- """
-
- def get_pre_create_attr_defs(self):
- """Settings for create page"""
- attr_defs = [
- self._get_render_target_enum(),
- self._get_reviewable_bool(),
- self._get_frame_int(),
- self._get_image_format_enum(),
- ]
- return attr_defs
-
- def _get_frame_int(self):
- return NumberDef(
- "frame",
- default=self.default_frame,
- label="Frame",
- tooltip="Set frame to be rendered, must be inside of global "
- "timeline range"
- )
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/create/create_saver.py b/server_addon/fusion/client/ayon_fusion/plugins/create/create_saver.py
deleted file mode 100644
index 3e7d9486ce..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/create/create_saver.py
+++ /dev/null
@@ -1,149 +0,0 @@
-from ayon_core.lib import (
- UILabelDef,
- NumberDef,
- EnumDef
-)
-
-from ayon_fusion.api.plugin import GenericCreateSaver
-from ayon_fusion.api.lib import get_current_comp
-
-
-class CreateSaver(GenericCreateSaver):
- """Fusion Saver to generate image sequence of 'render' product type.
-
- Original Saver creator targeted for 'render' product type. It uses
- original not to descriptive name because of values in Settings.
- """
- identifier = "io.openpype.creators.fusion.saver"
- label = "Render (saver)"
- name = "render"
- product_type = "render"
- description = "Fusion Saver to generate image sequence"
-
- default_frame_range_option = "current_folder"
-
- def get_detail_description(self):
- return """Fusion Saver to generate image sequence.
-
- This creator is expected for publishing of image sequences for 'render'
- product type. (But can publish even single frame 'render'.)
-
- Select what should be source of render range:
- - "Current Folder context" - values set on folder on AYON server
- - "From render in/out" - from node itself
- - "From composition timeline" - from timeline
-
- Supports local and farm rendering.
-
- Supports selection from predefined set of output file extensions:
- - exr
- - tga
- - png
- - tif
- - jpg
- """
-
- def get_pre_create_attr_defs(self):
- """Settings for create page"""
- attr_defs = [
- self._get_render_target_enum(),
- self._get_reviewable_bool(),
- self._get_frame_range_enum(),
- self._get_image_format_enum(),
- *self._get_custom_frame_range_attribute_defs()
- ]
- return attr_defs
-
- def _get_frame_range_enum(self):
- frame_range_options = {
- "current_folder": "Current Folder context",
- "render_range": "From render in/out",
- "comp_range": "From composition timeline",
- "custom_range": "Custom frame range",
- }
-
- return EnumDef(
- "frame_range_source",
- items=frame_range_options,
- label="Frame range source",
- default=self.default_frame_range_option
- )
-
- @staticmethod
- def _get_custom_frame_range_attribute_defs() -> list:
-
- # Define custom frame range defaults based on current comp
- # timeline settings (if a comp is currently open)
- comp = get_current_comp()
- if comp is not None:
- attrs = comp.GetAttrs()
- frame_defaults = {
- "frameStart": int(attrs["COMPN_GlobalStart"]),
- "frameEnd": int(attrs["COMPN_GlobalEnd"]),
- "handleStart": int(
- attrs["COMPN_RenderStart"] - attrs["COMPN_GlobalStart"]
- ),
- "handleEnd": int(
- attrs["COMPN_GlobalEnd"] - attrs["COMPN_RenderEnd"]
- ),
- }
- else:
- frame_defaults = {
- "frameStart": 1001,
- "frameEnd": 1100,
- "handleStart": 0,
- "handleEnd": 0
- }
-
- return [
- UILabelDef(
- label="
Custom Frame Range
"
- "only used with 'Custom frame range' source"
- ),
- NumberDef(
- "custom_frameStart",
- label="Frame Start",
- default=frame_defaults["frameStart"],
- minimum=0,
- decimals=0,
- tooltip=(
- "Set the start frame for the export.\n"
- "Only used if frame range source is 'Custom frame range'."
- )
- ),
- NumberDef(
- "custom_frameEnd",
- label="Frame End",
- default=frame_defaults["frameEnd"],
- minimum=0,
- decimals=0,
- tooltip=(
- "Set the end frame for the export.\n"
- "Only used if frame range source is 'Custom frame range'."
- )
- ),
- NumberDef(
- "custom_handleStart",
- label="Handle Start",
- default=frame_defaults["handleStart"],
- minimum=0,
- decimals=0,
- tooltip=(
- "Set the start handles for the export, this will be "
- "added before the start frame.\n"
- "Only used if frame range source is 'Custom frame range'."
- )
- ),
- NumberDef(
- "custom_handleEnd",
- label="Handle End",
- default=frame_defaults["handleEnd"],
- minimum=0,
- decimals=0,
- tooltip=(
- "Set the end handles for the export, this will be added "
- "after the end frame.\n"
- "Only used if frame range source is 'Custom frame range'."
- )
- )
- ]
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/create/create_workfile.py b/server_addon/fusion/client/ayon_fusion/plugins/create/create_workfile.py
deleted file mode 100644
index 3dc14861df..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/create/create_workfile.py
+++ /dev/null
@@ -1,132 +0,0 @@
-import ayon_api
-
-from ayon_fusion.api import (
- get_current_comp
-)
-from ayon_core.pipeline import (
- AutoCreator,
- CreatedInstance,
-)
-
-
-class FusionWorkfileCreator(AutoCreator):
- identifier = "workfile"
- product_type = "workfile"
- label = "Workfile"
- icon = "fa5.file"
-
- default_variant = "Main"
-
- create_allow_context_change = False
-
- data_key = "openpype_workfile"
-
- def collect_instances(self):
-
- comp = get_current_comp()
- data = comp.GetData(self.data_key)
- if not data:
- return
-
- product_name = data.get("productName")
- if product_name is None:
- product_name = data["subset"]
- instance = CreatedInstance(
- product_type=self.product_type,
- product_name=product_name,
- data=data,
- creator=self
- )
- instance.transient_data["comp"] = comp
-
- self._add_instance_to_context(instance)
-
- def update_instances(self, update_list):
- for created_inst, _changes in update_list:
- comp = created_inst.transient_data["comp"]
- if not hasattr(comp, "SetData"):
- # Comp is not alive anymore, likely closed by the user
- self.log.error("Workfile comp not found for existing instance."
- " Comp might have been closed in the meantime.")
- continue
-
- # Imprint data into the comp
- data = created_inst.data_to_store()
- comp.SetData(self.data_key, data)
-
- def create(self, options=None):
- comp = get_current_comp()
- if not comp:
- self.log.error("Unable to find current comp")
- return
-
- existing_instance = None
- for instance in self.create_context.instances:
- if instance.product_type == self.product_type:
- existing_instance = instance
- break
-
- project_name = self.create_context.get_current_project_name()
- folder_path = self.create_context.get_current_folder_path()
- task_name = self.create_context.get_current_task_name()
- host_name = self.create_context.host_name
-
- existing_folder_path = None
- if existing_instance is not None:
- existing_folder_path = existing_instance["folderPath"]
-
- if existing_instance is None:
- folder_entity = ayon_api.get_folder_by_path(
- project_name, folder_path
- )
- task_entity = ayon_api.get_task_by_name(
- project_name, folder_entity["id"], task_name
- )
- product_name = self.get_product_name(
- project_name,
- folder_entity,
- task_entity,
- self.default_variant,
- host_name,
- )
- data = {
- "folderPath": folder_path,
- "task": task_name,
- "variant": self.default_variant,
- }
- data.update(self.get_dynamic_data(
- project_name,
- folder_entity,
- task_entity,
- self.default_variant,
- host_name,
- None
-
- ))
-
- new_instance = CreatedInstance(
- self.product_type, product_name, data, self
- )
- new_instance.transient_data["comp"] = comp
- self._add_instance_to_context(new_instance)
-
- elif (
- existing_folder_path != folder_path
- or existing_instance["task"] != task_name
- ):
- folder_entity = ayon_api.get_folder_by_path(
- project_name, folder_path
- )
- task_entity = ayon_api.get_task_by_name(
- project_name, folder_entity["id"], task_name
- )
- product_name = self.get_product_name(
- project_name,
- folder_entity,
- task_entity,
- self.default_variant,
- host_name,
- )
- existing_instance["folderPath"] = folder_path
- existing_instance["task"] = task_name
- existing_instance["productName"] = product_name
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/inventory/select_containers.py b/server_addon/fusion/client/ayon_fusion/plugins/inventory/select_containers.py
deleted file mode 100644
index e863c58ab3..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/inventory/select_containers.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from ayon_core.pipeline import InventoryAction
-
-
-class FusionSelectContainers(InventoryAction):
-
- label = "Select Containers"
- icon = "mouse-pointer"
- color = "#d8d8d8"
-
- def process(self, containers):
- from ayon_fusion.api import (
- get_current_comp,
- comp_lock_and_undo_chunk
- )
-
- tools = [i["_tool"] for i in containers]
-
- comp = get_current_comp()
- flow = comp.CurrentFrame.FlowView
-
- with comp_lock_and_undo_chunk(comp, self.label):
- # Clear selection
- flow.Select()
-
- # Select tool
- for tool in tools:
- flow.Select(tool)
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/inventory/set_tool_color.py b/server_addon/fusion/client/ayon_fusion/plugins/inventory/set_tool_color.py
deleted file mode 100644
index 2c02afe32c..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/inventory/set_tool_color.py
+++ /dev/null
@@ -1,72 +0,0 @@
-from qtpy import QtGui, QtWidgets
-
-from ayon_core.pipeline import InventoryAction
-from ayon_core import style
-from ayon_fusion.api import (
- get_current_comp,
- comp_lock_and_undo_chunk
-)
-
-
-class FusionSetToolColor(InventoryAction):
- """Update the color of the selected tools"""
-
- label = "Set Tool Color"
- icon = "plus"
- color = "#d8d8d8"
- _fallback_color = QtGui.QColor(1.0, 1.0, 1.0)
-
- def process(self, containers):
- """Color all selected tools the selected colors"""
-
- result = []
- comp = get_current_comp()
-
- # Get tool color
- first = containers[0]
- tool = first["_tool"]
- color = tool.TileColor
-
- if color is not None:
- qcolor = QtGui.QColor().fromRgbF(color["R"], color["G"], color["B"])
- else:
- qcolor = self._fallback_color
-
- # Launch pick color
- picked_color = self.get_color_picker(qcolor)
- if not picked_color:
- return
-
- with comp_lock_and_undo_chunk(comp):
- for container in containers:
- # Convert color to RGB 0-1 floats
- rgb_f = picked_color.getRgbF()
- rgb_f_table = {"R": rgb_f[0], "G": rgb_f[1], "B": rgb_f[2]}
-
- # Update tool
- tool = container["_tool"]
- tool.TileColor = rgb_f_table
-
- result.append(container)
-
- return result
-
- def get_color_picker(self, color):
- """Launch color picker and return chosen color
-
- Args:
- color(QtGui.QColor): Start color to display
-
- Returns:
- QtGui.QColor
-
- """
-
- color_dialog = QtWidgets.QColorDialog(color)
- color_dialog.setStyleSheet(style.load_stylesheet())
-
- accepted = color_dialog.exec_()
- if not accepted:
- return
-
- return color_dialog.selectedColor()
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/load/actions.py b/server_addon/fusion/client/ayon_fusion/plugins/load/actions.py
deleted file mode 100644
index dfa73e0b7a..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/load/actions.py
+++ /dev/null
@@ -1,81 +0,0 @@
-"""A module containing generic loader actions that will display in the Loader.
-
-"""
-
-from ayon_core.pipeline import load
-
-
-class FusionSetFrameRangeLoader(load.LoaderPlugin):
- """Set frame range excluding pre- and post-handles"""
-
- product_types = {
- "animation",
- "camera",
- "imagesequence",
- "render",
- "yeticache",
- "pointcache",
- "render",
- }
- representations = {"*"}
- extensions = {"*"}
-
- label = "Set frame range"
- order = 11
- icon = "clock-o"
- color = "white"
-
- def load(self, context, name, namespace, data):
-
- from ayon_fusion.api import lib
-
- version_attributes = context["version"]["attrib"]
-
- start = version_attributes.get("frameStart", None)
- end = version_attributes.get("frameEnd", None)
-
- if start is None or end is None:
- print("Skipping setting frame range because start or "
- "end frame data is missing..")
- return
-
- lib.update_frame_range(start, end)
-
-
-class FusionSetFrameRangeWithHandlesLoader(load.LoaderPlugin):
- """Set frame range including pre- and post-handles"""
-
- product_types = {
- "animation",
- "camera",
- "imagesequence",
- "render",
- "yeticache",
- "pointcache",
- "render",
- }
- representations = {"*"}
-
- label = "Set frame range (with handles)"
- order = 12
- icon = "clock-o"
- color = "white"
-
- def load(self, context, name, namespace, data):
-
- from ayon_fusion.api import lib
-
- version_attributes = context["version"]["attrib"]
- start = version_attributes.get("frameStart", None)
- end = version_attributes.get("frameEnd", None)
-
- if start is None or end is None:
- print("Skipping setting frame range because start or "
- "end frame data is missing..")
- return
-
- # Include handles
- start -= version_attributes.get("handleStart", 0)
- end += version_attributes.get("handleEnd", 0)
-
- lib.update_frame_range(start, end)
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/load/load_alembic.py b/server_addon/fusion/client/ayon_fusion/plugins/load/load_alembic.py
deleted file mode 100644
index 2e763b5330..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/load/load_alembic.py
+++ /dev/null
@@ -1,72 +0,0 @@
-from ayon_core.pipeline import (
- load,
- get_representation_path,
-)
-from ayon_fusion.api import (
- imprint_container,
- get_current_comp,
- comp_lock_and_undo_chunk
-)
-
-
-class FusionLoadAlembicMesh(load.LoaderPlugin):
- """Load Alembic mesh into Fusion"""
-
- product_types = {"pointcache", "model"}
- representations = {"*"}
- extensions = {"abc"}
-
- label = "Load alembic mesh"
- order = -10
- icon = "code-fork"
- color = "orange"
-
- tool_type = "SurfaceAlembicMesh"
-
- def load(self, context, name, namespace, data):
- # Fallback to folder name when namespace is None
- if namespace is None:
- namespace = context["folder"]["name"]
-
- # Create the Loader with the filename path set
- comp = get_current_comp()
- with comp_lock_and_undo_chunk(comp, "Create tool"):
-
- path = self.filepath_from_context(context)
-
- args = (-32768, -32768)
- tool = comp.AddTool(self.tool_type, *args)
- tool["Filename"] = path
-
- imprint_container(tool,
- name=name,
- namespace=namespace,
- context=context,
- loader=self.__class__.__name__)
-
- def switch(self, container, context):
- self.update(container, context)
-
- def update(self, container, context):
- """Update Alembic path"""
-
- tool = container["_tool"]
- assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
- comp = tool.Comp()
-
- repre_entity = context["representation"]
- path = get_representation_path(repre_entity)
-
- with comp_lock_and_undo_chunk(comp, "Update tool"):
- tool["Filename"] = path
-
- # Update the imprinted representation
- tool.SetData("avalon.representation", repre_entity["id"])
-
- def remove(self, container):
- tool = container["_tool"]
- assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
- comp = tool.Comp()
-
- with comp_lock_and_undo_chunk(comp, "Remove tool"):
- tool.Delete()
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/load/load_fbx.py b/server_addon/fusion/client/ayon_fusion/plugins/load/load_fbx.py
deleted file mode 100644
index a080fa3983..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/load/load_fbx.py
+++ /dev/null
@@ -1,87 +0,0 @@
-from ayon_core.pipeline import (
- load,
- get_representation_path,
-)
-from ayon_fusion.api import (
- imprint_container,
- get_current_comp,
- comp_lock_and_undo_chunk,
-)
-
-
-class FusionLoadFBXMesh(load.LoaderPlugin):
- """Load FBX mesh into Fusion"""
-
- product_types = {"*"}
- representations = {"*"}
- extensions = {
- "3ds",
- "amc",
- "aoa",
- "asf",
- "bvh",
- "c3d",
- "dae",
- "dxf",
- "fbx",
- "htr",
- "mcd",
- "obj",
- "trc",
- }
-
- label = "Load FBX mesh"
- order = -10
- icon = "code-fork"
- color = "orange"
-
- tool_type = "SurfaceFBXMesh"
-
- def load(self, context, name, namespace, data):
- # Fallback to folder name when namespace is None
- if namespace is None:
- namespace = context["folder"]["name"]
-
- # Create the Loader with the filename path set
- comp = get_current_comp()
- with comp_lock_and_undo_chunk(comp, "Create tool"):
- path = self.filepath_from_context(context)
-
- args = (-32768, -32768)
- tool = comp.AddTool(self.tool_type, *args)
- tool["ImportFile"] = path
-
- imprint_container(
- tool,
- name=name,
- namespace=namespace,
- context=context,
- loader=self.__class__.__name__,
- )
-
- def switch(self, container, context):
- self.update(container, context)
-
- def update(self, container, context):
- """Update path"""
-
- tool = container["_tool"]
- assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
- comp = tool.Comp()
-
- repre_entity = context["representation"]
- path = get_representation_path(repre_entity)
-
- with comp_lock_and_undo_chunk(comp, "Update tool"):
- tool["ImportFile"] = path
-
- # Update the imprinted representation
- tool.SetData("avalon.representation", repre_entity["id"])
-
- def remove(self, container):
- tool = container["_tool"]
- assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
- comp = tool.Comp()
-
- with comp_lock_and_undo_chunk(comp, "Remove tool"):
- tool.Delete()
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/load/load_sequence.py b/server_addon/fusion/client/ayon_fusion/plugins/load/load_sequence.py
deleted file mode 100644
index 233f1d7021..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/load/load_sequence.py
+++ /dev/null
@@ -1,291 +0,0 @@
-import contextlib
-
-import ayon_core.pipeline.load as load
-from ayon_fusion.api import (
- imprint_container,
- get_current_comp,
- comp_lock_and_undo_chunk,
-)
-from ayon_core.lib.transcoding import IMAGE_EXTENSIONS, VIDEO_EXTENSIONS
-
-comp = get_current_comp()
-
-
-@contextlib.contextmanager
-def preserve_inputs(tool, inputs):
- """Preserve the tool's inputs after context"""
-
- comp = tool.Comp()
-
- values = {}
- for name in inputs:
- tool_input = getattr(tool, name)
- value = tool_input[comp.TIME_UNDEFINED]
- values[name] = value
-
- try:
- yield
- finally:
- for name, value in values.items():
- tool_input = getattr(tool, name)
- tool_input[comp.TIME_UNDEFINED] = value
-
-
-@contextlib.contextmanager
-def preserve_trim(loader, log=None):
- """Preserve the relative trim of the Loader tool.
-
- This tries to preserve the loader's trim (trim in and trim out) after
- the context by reapplying the "amount" it trims on the clip's length at
- start and end.
-
- """
-
- # Get original trim as amount of "trimming" from length
- time = loader.Comp().TIME_UNDEFINED
- length = loader.GetAttrs()["TOOLIT_Clip_Length"][1] - 1
- trim_from_start = loader["ClipTimeStart"][time]
- trim_from_end = length - loader["ClipTimeEnd"][time]
-
- try:
- yield
- finally:
- length = loader.GetAttrs()["TOOLIT_Clip_Length"][1] - 1
- if trim_from_start > length:
- trim_from_start = length
- if log:
- log.warning(
- "Reducing trim in to %d "
- "(because of less frames)" % trim_from_start
- )
-
- remainder = length - trim_from_start
- if trim_from_end > remainder:
- trim_from_end = remainder
- if log:
- log.warning(
- "Reducing trim in to %d "
- "(because of less frames)" % trim_from_end
- )
-
- loader["ClipTimeStart"][time] = trim_from_start
- loader["ClipTimeEnd"][time] = length - trim_from_end
-
-
-def loader_shift(loader, frame, relative=True):
- """Shift global in time by i preserving duration
-
- This moves the loader by i frames preserving global duration. When relative
- is False it will shift the global in to the start frame.
-
- Args:
- loader (tool): The fusion loader tool.
- frame (int): The amount of frames to move.
- relative (bool): When True the shift is relative, else the shift will
- change the global in to frame.
-
- Returns:
- int: The resulting relative frame change (how much it moved)
-
- """
- comp = loader.Comp()
- time = comp.TIME_UNDEFINED
-
- old_in = loader["GlobalIn"][time]
- old_out = loader["GlobalOut"][time]
-
- if relative:
- shift = frame
- else:
- shift = frame - old_in
-
- if not shift:
- return 0
-
- # Shifting global in will try to automatically compensate for the change
- # in the "ClipTimeStart" and "HoldFirstFrame" inputs, so we preserve those
- # input values to "just shift" the clip
- with preserve_inputs(
- loader,
- inputs=[
- "ClipTimeStart",
- "ClipTimeEnd",
- "HoldFirstFrame",
- "HoldLastFrame",
- ],
- ):
- # GlobalIn cannot be set past GlobalOut or vice versa
- # so we must apply them in the order of the shift.
- if shift > 0:
- loader["GlobalOut"][time] = old_out + shift
- loader["GlobalIn"][time] = old_in + shift
- else:
- loader["GlobalIn"][time] = old_in + shift
- loader["GlobalOut"][time] = old_out + shift
-
- return int(shift)
-
-
-class FusionLoadSequence(load.LoaderPlugin):
- """Load image sequence into Fusion"""
-
- product_types = {
- "imagesequence",
- "review",
- "render",
- "plate",
- "image",
- "online",
- }
- representations = {"*"}
- extensions = set(
- ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS)
- )
-
- label = "Load sequence"
- order = -10
- icon = "code-fork"
- color = "orange"
-
- def load(self, context, name, namespace, data):
- # Fallback to folder name when namespace is None
- if namespace is None:
- namespace = context["folder"]["name"]
-
- # Use the first file for now
- path = self.filepath_from_context(context)
-
- # Create the Loader with the filename path set
- comp = get_current_comp()
- with comp_lock_and_undo_chunk(comp, "Create Loader"):
- args = (-32768, -32768)
- tool = comp.AddTool("Loader", *args)
- tool["Clip"] = comp.ReverseMapPath(path)
-
- # Set global in point to start frame (if in version.data)
- start = self._get_start(context["version"], tool)
- loader_shift(tool, start, relative=False)
-
- imprint_container(
- tool,
- name=name,
- namespace=namespace,
- context=context,
- loader=self.__class__.__name__,
- )
-
- def switch(self, container, context):
- self.update(container, context)
-
- def update(self, container, context):
- """Update the Loader's path
-
- Fusion automatically tries to reset some variables when changing
- the loader's path to a new file. These automatic changes are to its
- inputs:
- - ClipTimeStart: Fusion reset to 0 if duration changes
- - We keep the trim in as close as possible to the previous value.
- When there are less frames then the amount of trim we reduce
- it accordingly.
-
- - ClipTimeEnd: Fusion reset to 0 if duration changes
- - We keep the trim out as close as possible to the previous value
- within new amount of frames after trim in (ClipTimeStart) has
- been set.
-
- - GlobalIn: Fusion reset to comp's global in if duration changes
- - We change it to the "frameStart"
-
- - GlobalEnd: Fusion resets to globalIn + length if duration changes
- - We do the same like Fusion - allow fusion to take control.
-
- - HoldFirstFrame: Fusion resets this to 0
- - We preserve the value.
-
- - HoldLastFrame: Fusion resets this to 0
- - We preserve the value.
-
- - Reverse: Fusion resets to disabled if "Loop" is not enabled.
- - We preserve the value.
-
- - Depth: Fusion resets to "Format"
- - We preserve the value.
-
- - KeyCode: Fusion resets to ""
- - We preserve the value.
-
- - TimeCodeOffset: Fusion resets to 0
- - We preserve the value.
-
- """
-
- tool = container["_tool"]
- assert tool.ID == "Loader", "Must be Loader"
- comp = tool.Comp()
-
- repre_entity = context["representation"]
- path = self.filepath_from_context(context)
-
- # Get start frame from version data
- start = self._get_start(context["version"], tool)
-
- with comp_lock_and_undo_chunk(comp, "Update Loader"):
- # Update the loader's path whilst preserving some values
- with preserve_trim(tool, log=self.log):
- with preserve_inputs(
- tool,
- inputs=(
- "HoldFirstFrame",
- "HoldLastFrame",
- "Reverse",
- "Depth",
- "KeyCode",
- "TimeCodeOffset",
- ),
- ):
- tool["Clip"] = comp.ReverseMapPath(path)
-
- # Set the global in to the start frame of the sequence
- global_in_changed = loader_shift(tool, start, relative=False)
- if global_in_changed:
- # Log this change to the user
- self.log.debug(
- "Changed '%s' global in: %d" % (tool.Name, start)
- )
-
- # Update the imprinted representation
- tool.SetData("avalon.representation", repre_entity["id"])
-
- def remove(self, container):
- tool = container["_tool"]
- assert tool.ID == "Loader", "Must be Loader"
- comp = tool.Comp()
-
- with comp_lock_and_undo_chunk(comp, "Remove Loader"):
- tool.Delete()
-
- def _get_start(self, version_entity, tool):
- """Return real start frame of published files (incl. handles)"""
- attributes = version_entity["attrib"]
-
- # Get start frame directly with handle if it's in data
- start = attributes.get("frameStartHandle")
- if start is not None:
- return start
-
- # Get frame start without handles
- start = attributes.get("frameStart")
- if start is None:
- self.log.warning(
- "Missing start frame for version "
- "assuming starts at frame 0 for: "
- "{}".format(tool.Name)
- )
- return 0
-
- # Use `handleStart` if the data is available
- handle_start = attributes.get("handleStart")
- if handle_start:
- start -= handle_start
-
- return start
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/load/load_usd.py b/server_addon/fusion/client/ayon_fusion/plugins/load/load_usd.py
deleted file mode 100644
index 42ce339faf..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/load/load_usd.py
+++ /dev/null
@@ -1,87 +0,0 @@
-from ayon_core.pipeline import (
- load,
- get_representation_path,
-)
-from ayon_fusion.api import (
- imprint_container,
- get_current_comp,
- comp_lock_and_undo_chunk
-)
-from ayon_fusion.api.lib import get_fusion_module
-
-
-class FusionLoadUSD(load.LoaderPlugin):
- """Load USD into Fusion
-
- Support for USD was added since Fusion 18.5
- """
-
- product_types = {"*"}
- representations = {"*"}
- extensions = {"usd", "usda", "usdz"}
-
- label = "Load USD"
- order = -10
- icon = "code-fork"
- color = "orange"
-
- tool_type = "uLoader"
-
- @classmethod
- def apply_settings(cls, project_settings):
- super(FusionLoadUSD, cls).apply_settings(project_settings)
- if cls.enabled:
- # Enable only in Fusion 18.5+
- fusion = get_fusion_module()
- version = fusion.GetVersion()
- major = version[1]
- minor = version[2]
- is_usd_supported = (major, minor) >= (18, 5)
- cls.enabled = is_usd_supported
-
- def load(self, context, name, namespace, data):
- # Fallback to folder name when namespace is None
- if namespace is None:
- namespace = context["folder"]["name"]
-
- # Create the Loader with the filename path set
- comp = get_current_comp()
- with comp_lock_and_undo_chunk(comp, "Create tool"):
-
- path = self.fname
-
- args = (-32768, -32768)
- tool = comp.AddTool(self.tool_type, *args)
- tool["Filename"] = path
-
- imprint_container(tool,
- name=name,
- namespace=namespace,
- context=context,
- loader=self.__class__.__name__)
-
- def switch(self, container, context):
- self.update(container, context)
-
- def update(self, container, context):
-
- tool = container["_tool"]
- assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
- comp = tool.Comp()
-
- repre_entity = context["representation"]
- path = get_representation_path(repre_entity)
-
- with comp_lock_and_undo_chunk(comp, "Update tool"):
- tool["Filename"] = path
-
- # Update the imprinted representation
- tool.SetData("avalon.representation", repre_entity["id"])
-
- def remove(self, container):
- tool = container["_tool"]
- assert tool.ID == self.tool_type, f"Must be {self.tool_type}"
- comp = tool.Comp()
-
- with comp_lock_and_undo_chunk(comp, "Remove tool"):
- tool.Delete()
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/load/load_workfile.py b/server_addon/fusion/client/ayon_fusion/plugins/load/load_workfile.py
deleted file mode 100644
index c728f6b4aa..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/load/load_workfile.py
+++ /dev/null
@@ -1,33 +0,0 @@
-"""Import workfiles into your current comp.
-As all imported nodes are free floating and will probably be changed there
-is no update or reload function added for this plugin
-"""
-
-from ayon_core.pipeline import load
-
-from ayon_fusion.api import (
- get_current_comp,
- get_bmd_library,
-)
-
-
-class FusionLoadWorkfile(load.LoaderPlugin):
- """Load the content of a workfile into Fusion"""
-
- product_types = {"workfile"}
- representations = {"*"}
- extensions = {"comp"}
-
- label = "Load Workfile"
- order = -10
- icon = "code-fork"
- color = "orange"
-
- def load(self, context, name, namespace, data):
- # Get needed elements
- bmd = get_bmd_library()
- comp = get_current_comp()
- path = self.filepath_from_context(context)
-
- # Paste the content of the file into the current comp
- comp.Paste(bmd.readfile(path))
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_comp.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_comp.py
deleted file mode 100644
index 2e5bcd63db..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_comp.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import pyblish.api
-
-from ayon_fusion.api import get_current_comp
-
-
-class CollectCurrentCompFusion(pyblish.api.ContextPlugin):
- """Collect current comp"""
-
- order = pyblish.api.CollectorOrder - 0.4
- label = "Collect Current Comp"
- hosts = ["fusion"]
-
- def process(self, context):
- """Collect all image sequence tools"""
-
- current_comp = get_current_comp()
- assert current_comp, "Must have active Fusion composition"
- context.data["currentComp"] = current_comp
-
- # Store path to current file
- filepath = current_comp.GetAttrs().get("COMPS_FileName", "")
- context.data['currentFile'] = filepath
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_comp_frame_range.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_comp_frame_range.py
deleted file mode 100644
index 24a9a92337..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_comp_frame_range.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import pyblish.api
-
-
-def get_comp_render_range(comp):
- """Return comp's start-end render range and global start-end range."""
- comp_attrs = comp.GetAttrs()
- start = comp_attrs["COMPN_RenderStart"]
- end = comp_attrs["COMPN_RenderEnd"]
- global_start = comp_attrs["COMPN_GlobalStart"]
- global_end = comp_attrs["COMPN_GlobalEnd"]
-
- # Whenever render ranges are undefined fall back
- # to the comp's global start and end
- if start == -1000000000:
- start = global_start
- if end == -1000000000:
- end = global_end
-
- return start, end, global_start, global_end
-
-
-class CollectFusionCompFrameRanges(pyblish.api.ContextPlugin):
- """Collect current comp"""
-
- # We run this after CollectorOrder - 0.1 otherwise it gets
- # overridden by global plug-in `CollectContextEntities`
- order = pyblish.api.CollectorOrder - 0.05
- label = "Collect Comp Frame Ranges"
- hosts = ["fusion"]
-
- def process(self, context):
- """Collect all image sequence tools"""
-
- comp = context.data["currentComp"]
-
- # Store comp render ranges
- start, end, global_start, global_end = get_comp_render_range(comp)
-
- context.data.update({
- "renderFrameStart": int(start),
- "renderFrameEnd": int(end),
- "compFrameStart": int(global_start),
- "compFrameEnd": int(global_end)
- })
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_inputs.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_inputs.py
deleted file mode 100644
index 002c0a5672..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_inputs.py
+++ /dev/null
@@ -1,116 +0,0 @@
-import pyblish.api
-
-from ayon_core.pipeline import registered_host
-
-
-def collect_input_containers(tools):
- """Collect containers that contain any of the node in `nodes`.
-
- This will return any loaded Avalon container that contains at least one of
- the nodes. As such, the Avalon container is an input for it. Or in short,
- there are member nodes of that container.
-
- Returns:
- list: Input avalon containers
-
- """
-
- # Lookup by node ids
- lookup = frozenset([tool.Name for tool in tools])
-
- containers = []
- host = registered_host()
- for container in host.ls():
-
- name = container["_tool"].Name
-
- # We currently assume no "groups" as containers but just single tools
- # like a single "Loader" operator. As such we just check whether the
- # Loader is part of the processing queue.
- if name in lookup:
- containers.append(container)
-
- return containers
-
-
-def iter_upstream(tool):
- """Yields all upstream inputs for the current tool.
-
- Yields:
- tool: The input tools.
-
- """
-
- def get_connected_input_tools(tool):
- """Helper function that returns connected input tools for a tool."""
- inputs = []
-
- # Filter only to actual types that will have sensible upstream
- # connections. So we ignore just "Number" inputs as they can be
- # many to iterate, slowing things down quite a bit - and in practice
- # they don't have upstream connections.
- VALID_INPUT_TYPES = ['Image', 'Particles', 'Mask', 'DataType3D']
- for type_ in VALID_INPUT_TYPES:
- for input_ in tool.GetInputList(type_).values():
- output = input_.GetConnectedOutput()
- if output:
- input_tool = output.GetTool()
- inputs.append(input_tool)
-
- return inputs
-
- # Initialize process queue with the node's inputs itself
- queue = get_connected_input_tools(tool)
-
- # We keep track of which node names we have processed so far, to ensure we
- # don't process the same hierarchy again. We are not pushing the tool
- # itself into the set as that doesn't correctly recognize the same tool.
- # Since tool names are unique in a comp in Fusion we rely on that.
- collected = set(tool.Name for tool in queue)
-
- # Traverse upstream references for all nodes and yield them as we
- # process the queue.
- while queue:
- upstream_tool = queue.pop()
- yield upstream_tool
-
- # Find upstream tools that are not collected yet.
- upstream_inputs = get_connected_input_tools(upstream_tool)
- upstream_inputs = [t for t in upstream_inputs if
- t.Name not in collected]
-
- queue.extend(upstream_inputs)
- collected.update(tool.Name for tool in upstream_inputs)
-
-
-class CollectUpstreamInputs(pyblish.api.InstancePlugin):
- """Collect source input containers used for this publish.
-
- This will include `inputs` data of which loaded publishes were used in the
- generation of this publish. This leaves an upstream trace to what was used
- as input.
-
- """
-
- label = "Collect Inputs"
- order = pyblish.api.CollectorOrder + 0.2
- hosts = ["fusion"]
- families = ["render", "image"]
-
- def process(self, instance):
-
- # Get all upstream and include itself
- if not any(instance[:]):
- self.log.debug("No tool found in instance, skipping..")
- return
-
- tool = instance[0]
- nodes = list(iter_upstream(tool))
- nodes.append(tool)
-
- # Collect containers for the given set of nodes
- containers = collect_input_containers(nodes)
-
- inputs = [c["representation"] for c in containers]
- instance.data["inputRepresentations"] = inputs
- self.log.debug("Collected inputs: %s" % inputs)
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_instances.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_instances.py
deleted file mode 100644
index 921c282877..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_instances.py
+++ /dev/null
@@ -1,109 +0,0 @@
-import pyblish.api
-
-
-class CollectInstanceData(pyblish.api.InstancePlugin):
- """Collect Fusion saver instances
-
- This additionally stores the Comp start and end render range in the
- current context's data as "frameStart" and "frameEnd".
-
- """
-
- order = pyblish.api.CollectorOrder
- label = "Collect Instances Data"
- hosts = ["fusion"]
-
- def process(self, instance):
- """Collect all image sequence tools"""
-
- context = instance.context
-
- # Include creator attributes directly as instance data
- creator_attributes = instance.data["creator_attributes"]
- instance.data.update(creator_attributes)
-
- frame_range_source = creator_attributes.get("frame_range_source")
- instance.data["frame_range_source"] = frame_range_source
-
- # get folder frame ranges to all instances
- # render product type instances `current_folder` render target
- start = context.data["frameStart"]
- end = context.data["frameEnd"]
- handle_start = context.data["handleStart"]
- handle_end = context.data["handleEnd"]
- start_with_handle = start - handle_start
- end_with_handle = end + handle_end
-
- # conditions for render product type instances
- if frame_range_source == "render_range":
- # set comp render frame ranges
- start = context.data["renderFrameStart"]
- end = context.data["renderFrameEnd"]
- handle_start = 0
- handle_end = 0
- start_with_handle = start
- end_with_handle = end
-
- if frame_range_source == "comp_range":
- comp_start = context.data["compFrameStart"]
- comp_end = context.data["compFrameEnd"]
- render_start = context.data["renderFrameStart"]
- render_end = context.data["renderFrameEnd"]
- # set comp frame ranges
- start = render_start
- end = render_end
- handle_start = render_start - comp_start
- handle_end = comp_end - render_end
- start_with_handle = comp_start
- end_with_handle = comp_end
-
- if frame_range_source == "custom_range":
- start = int(instance.data["custom_frameStart"])
- end = int(instance.data["custom_frameEnd"])
- handle_start = int(instance.data["custom_handleStart"])
- handle_end = int(instance.data["custom_handleEnd"])
- start_with_handle = start - handle_start
- end_with_handle = end + handle_end
-
- frame = instance.data["creator_attributes"].get("frame")
- # explicitly publishing only single frame
- if frame is not None:
- frame = int(frame)
-
- start = frame
- end = frame
- handle_start = 0
- handle_end = 0
- start_with_handle = frame
- end_with_handle = frame
-
- # Include start and end render frame in label
- product_name = instance.data["productName"]
- label = (
- "{product_name} ({start}-{end}) [{handle_start}-{handle_end}]"
- ).format(
- product_name=product_name,
- start=int(start),
- end=int(end),
- handle_start=int(handle_start),
- handle_end=int(handle_end)
- )
-
- instance.data.update({
- "label": label,
-
- # todo: Allow custom frame range per instance
- "frameStart": start,
- "frameEnd": end,
- "frameStartHandle": start_with_handle,
- "frameEndHandle": end_with_handle,
- "handleStart": handle_start,
- "handleEnd": handle_end,
- "fps": context.data["fps"],
- })
-
- # Add review family if the instance is marked as 'review'
- # This could be done through a 'review' Creator attribute.
- if instance.data.get("review", False):
- self.log.debug("Adding review family..")
- instance.data["families"].append("review")
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_render.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_render.py
deleted file mode 100644
index af52aee861..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_render.py
+++ /dev/null
@@ -1,208 +0,0 @@
-import os
-import attr
-import pyblish.api
-
-from ayon_core.pipeline import publish
-from ayon_core.pipeline.publish import RenderInstance
-from ayon_fusion.api.lib import get_frame_path
-
-
-@attr.s
-class FusionRenderInstance(RenderInstance):
- # extend generic, composition name is needed
- fps = attr.ib(default=None)
- projectEntity = attr.ib(default=None)
- stagingDir = attr.ib(default=None)
- app_version = attr.ib(default=None)
- tool = attr.ib(default=None)
- workfileComp = attr.ib(default=None)
- publish_attributes = attr.ib(default={})
- frameStartHandle = attr.ib(default=None)
- frameEndHandle = attr.ib(default=None)
-
-
-class CollectFusionRender(
- publish.AbstractCollectRender,
- publish.ColormanagedPyblishPluginMixin
-):
-
- order = pyblish.api.CollectorOrder + 0.09
- label = "Collect Fusion Render"
- hosts = ["fusion"]
-
- def get_instances(self, context):
-
- comp = context.data.get("currentComp")
- comp_frame_format_prefs = comp.GetPrefs("Comp.FrameFormat")
- aspect_x = comp_frame_format_prefs["AspectX"]
- aspect_y = comp_frame_format_prefs["AspectY"]
-
-
- current_file = context.data["currentFile"]
- version = context.data["version"]
-
- project_entity = context.data["projectEntity"]
-
- instances = []
- for inst in context:
- if not inst.data.get("active", True):
- continue
-
- product_type = inst.data["productType"]
- if product_type not in ["render", "image"]:
- continue
-
- task_name = inst.data["task"]
- tool = inst.data["transientData"]["tool"]
-
- instance_families = inst.data.get("families", [])
- product_name = inst.data["productName"]
- instance = FusionRenderInstance(
- tool=tool,
- workfileComp=comp,
- productType=product_type,
- family=product_type,
- families=instance_families,
- version=version,
- time="",
- source=current_file,
- label=inst.data["label"],
- productName=product_name,
- folderPath=inst.data["folderPath"],
- task=task_name,
- attachTo=False,
- setMembers='',
- publish=True,
- name=product_name,
- resolutionWidth=comp_frame_format_prefs.get("Width"),
- resolutionHeight=comp_frame_format_prefs.get("Height"),
- pixelAspect=aspect_x / aspect_y,
- tileRendering=False,
- tilesX=0,
- tilesY=0,
- review="review" in instance_families,
- frameStart=inst.data["frameStart"],
- frameEnd=inst.data["frameEnd"],
- handleStart=inst.data["handleStart"],
- handleEnd=inst.data["handleEnd"],
- frameStartHandle=inst.data["frameStartHandle"],
- frameEndHandle=inst.data["frameEndHandle"],
- frameStep=1,
- fps=comp_frame_format_prefs.get("Rate"),
- app_version=comp.GetApp().Version,
- publish_attributes=inst.data.get("publish_attributes", {}),
-
- # The source instance this render instance replaces
- source_instance=inst
- )
-
- render_target = inst.data["creator_attributes"]["render_target"]
-
- # Add render target family
- render_target_family = f"render.{render_target}"
- if render_target_family not in instance.families:
- instance.families.append(render_target_family)
-
- # Add render target specific data
- if render_target in {"local", "frames"}:
- instance.projectEntity = project_entity
-
- if render_target == "farm":
- fam = "render.farm"
- if fam not in instance.families:
- instance.families.append(fam)
- instance.farm = True # to skip integrate
- if "review" in instance.families:
- # to skip ExtractReview locally
- instance.families.remove("review")
- instance.deadline = inst.data.get("deadline")
-
- instances.append(instance)
-
- return instances
-
- def post_collecting_action(self):
- for instance in self._context:
- if "render.frames" in instance.data.get("families", []):
- # adding representation data to the instance
- self._update_for_frames(instance)
-
- def get_expected_files(self, render_instance):
- """
- Returns list of rendered files that should be created by
- Deadline. These are not published directly, they are source
- for later 'submit_publish_job'.
-
- Args:
- render_instance (RenderInstance): to pull anatomy and parts used
- in url
-
- Returns:
- (list) of absolute urls to rendered file
- """
- start = render_instance.frameStart - render_instance.handleStart
- end = render_instance.frameEnd + render_instance.handleEnd
-
- comp = render_instance.workfileComp
- path = comp.MapPath(
- render_instance.tool["Clip"][
- render_instance.workfileComp.TIME_UNDEFINED
- ]
- )
- output_dir = os.path.dirname(path)
- render_instance.outputDir = output_dir
-
- basename = os.path.basename(path)
-
- head, padding, ext = get_frame_path(basename)
-
- expected_files = []
- for frame in range(start, end + 1):
- expected_files.append(
- os.path.join(
- output_dir,
- f"{head}{str(frame).zfill(padding)}{ext}"
- )
- )
-
- return expected_files
-
- def _update_for_frames(self, instance):
- """Updating instance for render.frames family
-
- Adding representation data to the instance. Also setting
- colorspaceData to the representation based on file rules.
- """
-
- expected_files = instance.data["expectedFiles"]
-
- start = instance.data["frameStart"] - instance.data["handleStart"]
-
- path = expected_files[0]
- basename = os.path.basename(path)
- staging_dir = os.path.dirname(path)
- _, padding, ext = get_frame_path(basename)
-
- repre = {
- "name": ext[1:],
- "ext": ext[1:],
- "frameStart": f"%0{padding}d" % start,
- "files": [os.path.basename(f) for f in expected_files],
- "stagingDir": staging_dir,
- }
-
- self.set_representation_colorspace(
- representation=repre,
- context=instance.context,
- )
-
- # review representation
- if instance.data.get("review", False):
- repre["tags"] = ["review"]
-
- # add the repre to the instance
- if "representations" not in instance.data:
- instance.data["representations"] = []
- instance.data["representations"].append(repre)
-
- return instance
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_workfile.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_workfile.py
deleted file mode 100644
index 4c288edb3e..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/collect_workfile.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import os
-
-import pyblish.api
-
-
-class CollectFusionWorkfile(pyblish.api.InstancePlugin):
- """Collect Fusion workfile representation."""
-
- order = pyblish.api.CollectorOrder + 0.1
- label = "Collect Workfile"
- hosts = ["fusion"]
- families = ["workfile"]
-
- def process(self, instance):
-
- current_file = instance.context.data["currentFile"]
-
- folder, file = os.path.split(current_file)
- filename, ext = os.path.splitext(file)
-
- instance.data['representations'] = [{
- 'name': ext.lstrip("."),
- 'ext': ext.lstrip("."),
- 'files': file,
- "stagingDir": folder,
- }]
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/extract_render_local.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/extract_render_local.py
deleted file mode 100644
index bbcba5366d..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/extract_render_local.py
+++ /dev/null
@@ -1,207 +0,0 @@
-import os
-import logging
-import contextlib
-import collections
-import pyblish.api
-
-from ayon_core.pipeline import publish
-from ayon_fusion.api import comp_lock_and_undo_chunk
-from ayon_fusion.api.lib import get_frame_path, maintained_comp_range
-
-log = logging.getLogger(__name__)
-
-
-@contextlib.contextmanager
-def enabled_savers(comp, savers):
- """Enable only the `savers` in Comp during the context.
-
- Any Saver tool in the passed composition that is not in the savers list
- will be set to passthrough during the context.
-
- Args:
- comp (object): Fusion composition object.
- savers (list): List of Saver tool objects.
-
- """
- passthrough_key = "TOOLB_PassThrough"
- original_states = {}
- enabled_saver_names = {saver.Name for saver in savers}
-
- all_savers = comp.GetToolList(False, "Saver").values()
- savers_by_name = {saver.Name: saver for saver in all_savers}
-
- try:
- for saver in all_savers:
- original_state = saver.GetAttrs()[passthrough_key]
- original_states[saver.Name] = original_state
-
- # The passthrough state we want to set (passthrough != enabled)
- state = saver.Name not in enabled_saver_names
- if state != original_state:
- saver.SetAttrs({passthrough_key: state})
- yield
- finally:
- for saver_name, original_state in original_states.items():
- saver = savers_by_name[saver_name]
- saver.SetAttrs({"TOOLB_PassThrough": original_state})
-
-
-class FusionRenderLocal(
- pyblish.api.InstancePlugin,
- publish.ColormanagedPyblishPluginMixin
-):
- """Render the current Fusion composition locally."""
-
- order = pyblish.api.ExtractorOrder - 0.2
- label = "Render Local"
- hosts = ["fusion"]
- families = ["render.local"]
-
- is_rendered_key = "_fusionrenderlocal_has_rendered"
-
- def process(self, instance):
-
- # Start render
- result = self.render(instance)
- if result is False:
- raise RuntimeError(f"Comp render failed for {instance}")
-
- self._add_representation(instance)
-
- # Log render status
- self.log.info(
- "Rendered '{}' for folder '{}' under the task '{}'".format(
- instance.data["name"],
- instance.data["folderPath"],
- instance.data["task"],
- )
- )
-
- def render(self, instance):
- """Render instance.
-
- We try to render the minimal amount of times by combining the instances
- that have a matching frame range in one Fusion render. Then for the
- batch of instances we store whether the render succeeded or failed.
-
- """
-
- if self.is_rendered_key in instance.data:
- # This instance was already processed in batch with another
- # instance, so we just return the render result directly
- self.log.debug(f"Instance {instance} was already rendered")
- return instance.data[self.is_rendered_key]
-
- instances_by_frame_range = self.get_render_instances_by_frame_range(
- instance.context
- )
-
- # Render matching batch of instances that share the same frame range
- frame_range = self.get_instance_render_frame_range(instance)
- render_instances = instances_by_frame_range[frame_range]
-
- # We initialize render state false to indicate it wasn't successful
- # yet to keep track of whether Fusion succeeded. This is for cases
- # where an error below this might cause the comp render result not
- # to be stored for the instances of this batch
- for render_instance in render_instances:
- render_instance.data[self.is_rendered_key] = False
-
- savers_to_render = [inst.data["tool"] for inst in render_instances]
- current_comp = instance.context.data["currentComp"]
- frame_start, frame_end = frame_range
-
- self.log.info(
- f"Starting Fusion render frame range {frame_start}-{frame_end}"
- )
- saver_names = ", ".join(saver.Name for saver in savers_to_render)
- self.log.info(f"Rendering tools: {saver_names}")
-
- with comp_lock_and_undo_chunk(current_comp):
- with maintained_comp_range(current_comp):
- with enabled_savers(current_comp, savers_to_render):
- result = current_comp.Render(
- {
- "Start": frame_start,
- "End": frame_end,
- "Wait": True,
- }
- )
-
- # Store the render state for all the rendered instances
- for render_instance in render_instances:
- render_instance.data[self.is_rendered_key] = bool(result)
-
- return result
-
- def _add_representation(self, instance):
- """Add representation to instance"""
-
- expected_files = instance.data["expectedFiles"]
-
- start = instance.data["frameStart"] - instance.data["handleStart"]
-
- path = expected_files[0]
- _, padding, ext = get_frame_path(path)
-
- staging_dir = os.path.dirname(path)
-
- files = [os.path.basename(f) for f in expected_files]
- if len(expected_files) == 1:
- files = files[0]
-
- repre = {
- "name": ext[1:],
- "ext": ext[1:],
- "frameStart": f"%0{padding}d" % start,
- "files": files,
- "stagingDir": staging_dir,
- }
-
- self.set_representation_colorspace(
- representation=repre,
- context=instance.context,
- )
-
- # review representation
- if instance.data.get("review", False):
- repre["tags"] = ["review"]
-
- # add the repre to the instance
- if "representations" not in instance.data:
- instance.data["representations"] = []
- instance.data["representations"].append(repre)
-
- return instance
-
- def get_render_instances_by_frame_range(self, context):
- """Return enabled render.local instances grouped by their frame range.
-
- Arguments:
- context (pyblish.Context): The pyblish context
-
- Returns:
- dict: (start, end): instances mapping
-
- """
-
- instances_to_render = [
- instance for instance in context if
- # Only active instances
- instance.data.get("publish", True) and
- # Only render.local instances
- "render.local" in instance.data.get("families", [])
- ]
-
- # Instances by frame ranges
- instances_by_frame_range = collections.defaultdict(list)
- for instance in instances_to_render:
- start, end = self.get_instance_render_frame_range(instance)
- instances_by_frame_range[(start, end)].append(instance)
-
- return dict(instances_by_frame_range)
-
- def get_instance_render_frame_range(self, instance):
- start = instance.data["frameStartHandle"]
- end = instance.data["frameEndHandle"]
- return start, end
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/increment_current_file.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/increment_current_file.py
deleted file mode 100644
index bcff27b988..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/increment_current_file.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import pyblish.api
-
-from ayon_core.pipeline import OptionalPyblishPluginMixin
-from ayon_core.pipeline import KnownPublishError
-
-
-class FusionIncrementCurrentFile(
- pyblish.api.ContextPlugin, OptionalPyblishPluginMixin
-):
- """Increment the current file.
-
- Saves the current file with an increased version number.
-
- """
-
- label = "Increment workfile version"
- order = pyblish.api.IntegratorOrder + 9.0
- hosts = ["fusion"]
- optional = True
-
- def process(self, context):
- if not self.is_active(context.data):
- return
-
- from ayon_core.lib import version_up
- from ayon_core.pipeline.publish import get_errored_plugins_from_context
-
- errored_plugins = get_errored_plugins_from_context(context)
- if any(
- plugin.__name__ == "FusionSubmitDeadline"
- for plugin in errored_plugins
- ):
- raise KnownPublishError(
- "Skipping incrementing current file because "
- "submission to render farm failed."
- )
-
- comp = context.data.get("currentComp")
- assert comp, "Must have comp"
-
- current_filepath = context.data["currentFile"]
- new_filepath = version_up(current_filepath)
-
- comp.Save(new_filepath)
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/save_scene.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/save_scene.py
deleted file mode 100644
index da9b6ce41f..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/save_scene.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import pyblish.api
-
-
-class FusionSaveComp(pyblish.api.ContextPlugin):
- """Save current comp"""
-
- label = "Save current file"
- order = pyblish.api.ExtractorOrder - 0.49
- hosts = ["fusion"]
- families = ["render", "image", "workfile"]
-
- def process(self, context):
-
- comp = context.data.get("currentComp")
- assert comp, "Must have comp"
-
- current = comp.GetAttrs().get("COMPS_FileName", "")
- assert context.data['currentFile'] == current
-
- self.log.info("Saving current file: {}".format(current))
- comp.Save()
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_background_depth.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_background_depth.py
deleted file mode 100644
index 90b6b110a4..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_background_depth.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import pyblish.api
-
-from ayon_core.pipeline import (
- publish,
- OptionalPyblishPluginMixin,
- PublishValidationError,
-)
-
-from ayon_fusion.api.action import SelectInvalidAction
-
-
-class ValidateBackgroundDepth(
- pyblish.api.InstancePlugin, OptionalPyblishPluginMixin
-):
- """Validate if all Background tool are set to float32 bit"""
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Background Depth 32 bit"
- hosts = ["fusion"]
- families = ["render", "image"]
- optional = True
-
- actions = [SelectInvalidAction, publish.RepairAction]
-
- @classmethod
- def get_invalid(cls, instance):
- context = instance.context
- comp = context.data.get("currentComp")
- assert comp, "Must have Comp object"
-
- backgrounds = comp.GetToolList(False, "Background").values()
- if not backgrounds:
- return []
-
- return [i for i in backgrounds if i.GetInput("Depth") != 4.0]
-
- def process(self, instance):
- if not self.is_active(instance.data):
- return
-
- invalid = self.get_invalid(instance)
- if invalid:
- raise PublishValidationError(
- "Found {} Backgrounds tools which"
- " are not set to float32".format(len(invalid)),
- title=self.label,
- )
-
- @classmethod
- def repair(cls, instance):
- comp = instance.context.data.get("currentComp")
- invalid = cls.get_invalid(instance)
- for i in invalid:
- i.SetInput("Depth", 4.0, comp.TIME_UNDEFINED)
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_comp_saved.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_comp_saved.py
deleted file mode 100644
index ba56c40b65..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_comp_saved.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import os
-
-import pyblish.api
-from ayon_core.pipeline import PublishValidationError
-
-
-class ValidateFusionCompSaved(pyblish.api.ContextPlugin):
- """Ensure current comp is saved"""
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Comp Saved"
- families = ["render", "image"]
- hosts = ["fusion"]
-
- def process(self, context):
-
- comp = context.data.get("currentComp")
- assert comp, "Must have Comp object"
- attrs = comp.GetAttrs()
-
- filename = attrs["COMPS_FileName"]
- if not filename:
- raise PublishValidationError("Comp is not saved.",
- title=self.label)
-
- if not os.path.exists(filename):
- raise PublishValidationError(
- "Comp file does not exist: %s" % filename, title=self.label)
-
- if attrs["COMPB_Modified"]:
- self.log.warning("Comp is modified. Save your comp to ensure your "
- "changes propagate correctly.")
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_create_folder_checked.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_create_folder_checked.py
deleted file mode 100644
index 1b910123f0..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_create_folder_checked.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import pyblish.api
-
-from ayon_core.pipeline.publish import RepairAction
-from ayon_core.pipeline import PublishValidationError
-
-from ayon_fusion.api.action import SelectInvalidAction
-
-
-class ValidateCreateFolderChecked(pyblish.api.InstancePlugin):
- """Valid if all savers have the input attribute CreateDir checked on
-
- This attribute ensures that the folders to which the saver will write
- will be created.
- """
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Create Folder Checked"
- families = ["render", "image"]
- hosts = ["fusion"]
- actions = [RepairAction, SelectInvalidAction]
-
- @classmethod
- def get_invalid(cls, instance):
- tool = instance.data["tool"]
- create_dir = tool.GetInput("CreateDir")
- if create_dir == 0.0:
- cls.log.error(
- "%s has Create Folder turned off" % instance[0].Name
- )
- return [tool]
-
- def process(self, instance):
- invalid = self.get_invalid(instance)
- if invalid:
- raise PublishValidationError(
- "Found Saver with Create Folder During Render checked off",
- title=self.label,
- )
-
- @classmethod
- def repair(cls, instance):
- invalid = cls.get_invalid(instance)
- for tool in invalid:
- tool.SetInput("CreateDir", 1.0)
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_expected_frames_existence.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_expected_frames_existence.py
deleted file mode 100644
index 6dc9642581..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_expected_frames_existence.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import os
-import pyblish.api
-
-from ayon_core.pipeline.publish import RepairAction
-from ayon_core.pipeline import PublishValidationError
-
-from ayon_fusion.api.action import SelectInvalidAction
-
-
-class ValidateLocalFramesExistence(pyblish.api.InstancePlugin):
- """Checks if files for savers that's set
- to publish expected frames exists
- """
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Expected Frames Exists"
- families = ["render.frames"]
- hosts = ["fusion"]
- actions = [RepairAction, SelectInvalidAction]
-
- @classmethod
- def get_invalid(cls, instance, non_existing_frames=None):
- if non_existing_frames is None:
- non_existing_frames = []
-
- tool = instance.data["tool"]
-
- expected_files = instance.data["expectedFiles"]
-
- for file in expected_files:
- if not os.path.exists(file):
- cls.log.error(
- f"Missing file: {file}"
- )
- non_existing_frames.append(file)
-
- if len(non_existing_frames) > 0:
- cls.log.error(f"Some of {tool.Name}'s files does not exist")
- return [tool]
-
- def process(self, instance):
- non_existing_frames = []
- invalid = self.get_invalid(instance, non_existing_frames)
- if invalid:
- raise PublishValidationError(
- "{} is set to publish existing frames but "
- "some frames are missing. "
- "The missing file(s) are:\n\n{}".format(
- invalid[0].Name,
- "\n\n".join(non_existing_frames),
- ),
- title=self.label,
- )
-
- @classmethod
- def repair(cls, instance):
- invalid = cls.get_invalid(instance)
- if invalid:
- tool = instance.data["tool"]
- # Change render target to local to render locally
- tool.SetData("openpype.creator_attributes.render_target", "local")
-
- cls.log.info(
- f"Reload the publisher and {tool.Name} "
- "will be set to render locally"
- )
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_filename_has_extension.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_filename_has_extension.py
deleted file mode 100644
index 471c0ca31a..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_filename_has_extension.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import os
-
-import pyblish.api
-from ayon_core.pipeline import PublishValidationError
-
-from ayon_fusion.api.action import SelectInvalidAction
-
-
-class ValidateFilenameHasExtension(pyblish.api.InstancePlugin):
- """Ensure the Saver has an extension in the filename path
-
- This disallows files written as `filename` instead of `filename.frame.ext`.
- Fusion does not always set an extension for your filename when
- changing the file format of the saver.
-
- """
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Filename Has Extension"
- families = ["render", "image"]
- hosts = ["fusion"]
- actions = [SelectInvalidAction]
-
- def process(self, instance):
- invalid = self.get_invalid(instance)
- if invalid:
- raise PublishValidationError("Found Saver without an extension",
- title=self.label)
-
- @classmethod
- def get_invalid(cls, instance):
-
- path = instance.data["expectedFiles"][0]
- fname, ext = os.path.splitext(path)
-
- if not ext:
- tool = instance.data["tool"]
- cls.log.error("%s has no extension specified" % tool.Name)
- return [tool]
-
- return []
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_image_frame.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_image_frame.py
deleted file mode 100644
index 70e5ed9279..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_image_frame.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import pyblish.api
-
-from ayon_core.pipeline import PublishValidationError
-
-
-class ValidateImageFrame(pyblish.api.InstancePlugin):
- """Validates that `image` product type contains only single frame."""
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Image Frame"
- families = ["image"]
- hosts = ["fusion"]
-
- def process(self, instance):
- render_start = instance.data["frameStartHandle"]
- render_end = instance.data["frameEndHandle"]
- too_many_frames = (isinstance(instance.data["expectedFiles"], list)
- and len(instance.data["expectedFiles"]) > 1)
-
- if render_end - render_start > 0 or too_many_frames:
- desc = ("Trying to render multiple frames. 'image' product type "
- "is meant for single frame. Please use 'render' creator.")
- raise PublishValidationError(
- title="Frame range outside of comp range",
- message=desc,
- description=desc
- )
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_instance_frame_range.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_instance_frame_range.py
deleted file mode 100644
index 0f7ef1862d..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_instance_frame_range.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import pyblish.api
-
-from ayon_core.pipeline import PublishValidationError
-
-
-class ValidateInstanceFrameRange(pyblish.api.InstancePlugin):
- """Validate instance frame range is within comp's global render range."""
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Frame Range"
- families = ["render", "image"]
- hosts = ["fusion"]
-
- def process(self, instance):
-
- context = instance.context
- global_start = context.data["compFrameStart"]
- global_end = context.data["compFrameEnd"]
-
- render_start = instance.data["frameStartHandle"]
- render_end = instance.data["frameEndHandle"]
-
- if render_start < global_start or render_end > global_end:
-
- message = (
- f"Instance {instance} render frame range "
- f"({render_start}-{render_end}) is outside of the comp's "
- f"global render range ({global_start}-{global_end}) and thus "
- f"can't be rendered. "
- )
- description = (
- f"{message}\n\n"
- f"Either update the comp's global range or the instance's "
- f"frame range to ensure the comp's frame range includes the "
- f"to render frame range for the instance."
- )
- raise PublishValidationError(
- title="Frame range outside of comp range",
- message=message,
- description=description
- )
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_instance_in_context.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_instance_in_context.py
deleted file mode 100644
index 7b8b70b2fb..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_instance_in_context.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# -*- coding: utf-8 -*-
-"""Validate if instance context is the same as publish context."""
-
-import pyblish.api
-from ayon_fusion.api.action import SelectToolAction
-from ayon_core.pipeline.publish import (
- RepairAction,
- ValidateContentsOrder,
- PublishValidationError,
- OptionalPyblishPluginMixin
-)
-
-
-class ValidateInstanceInContextFusion(pyblish.api.InstancePlugin,
- OptionalPyblishPluginMixin):
- """Validator to check if instance context matches context of publish.
-
- When working in per-shot style you always publish data in context of
- current asset (shot). This validator checks if this is so. It is optional
- so it can be disabled when needed.
- """
- # Similar to maya and houdini-equivalent `ValidateInstanceInContext`
-
- order = ValidateContentsOrder
- label = "Instance in same Context"
- optional = True
- hosts = ["fusion"]
- actions = [SelectToolAction, RepairAction]
-
- def process(self, instance):
- if not self.is_active(instance.data):
- return
-
- instance_context = self.get_context(instance.data)
- context = self.get_context(instance.context.data)
- if instance_context != context:
- context_label = "{} > {}".format(*context)
- instance_label = "{} > {}".format(*instance_context)
-
- raise PublishValidationError(
- message=(
- "Instance '{}' publishes to different asset than current "
- "context: {}. Current context: {}".format(
- instance.name, instance_label, context_label
- )
- ),
- description=(
- "## Publishing to a different asset\n"
- "There are publish instances present which are publishing "
- "into a different asset than your current context.\n\n"
- "Usually this is not what you want but there can be cases "
- "where you might want to publish into another asset or "
- "shot. If that's the case you can disable the validation "
- "on the instance to ignore it."
- )
- )
-
- @classmethod
- def repair(cls, instance):
-
- create_context = instance.context.data["create_context"]
- instance_id = instance.data.get("instance_id")
- created_instance = create_context.get_instance_by_id(
- instance_id
- )
- if created_instance is None:
- raise RuntimeError(
- f"No CreatedInstances found with id '{instance_id} "
- f"in {create_context.instances_by_id}"
- )
-
- context_asset, context_task = cls.get_context(instance.context.data)
- created_instance["folderPath"] = context_asset
- created_instance["task"] = context_task
- create_context.save_changes()
-
- @staticmethod
- def get_context(data):
- """Return asset, task from publishing context data"""
- return data["folderPath"], data["task"]
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_has_input.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_has_input.py
deleted file mode 100644
index de2cd1d862..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_has_input.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import pyblish.api
-from ayon_core.pipeline import PublishValidationError
-
-from ayon_fusion.api.action import SelectInvalidAction
-
-
-class ValidateSaverHasInput(pyblish.api.InstancePlugin):
- """Validate saver has incoming connection
-
- This ensures a Saver has at least an input connection.
-
- """
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Saver Has Input"
- families = ["render", "image"]
- hosts = ["fusion"]
- actions = [SelectInvalidAction]
-
- @classmethod
- def get_invalid(cls, instance):
-
- saver = instance.data["tool"]
- if not saver.Input.GetConnectedOutput():
- return [saver]
-
- return []
-
- def process(self, instance):
- invalid = self.get_invalid(instance)
- if invalid:
- saver_name = invalid[0].Name
- raise PublishValidationError(
- "Saver has no incoming connection: {} ({})".format(instance,
- saver_name),
- title=self.label)
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_passthrough.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_passthrough.py
deleted file mode 100644
index caa17168bc..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_passthrough.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import pyblish.api
-from ayon_core.pipeline import PublishValidationError
-
-from ayon_fusion.api.action import SelectInvalidAction
-
-
-class ValidateSaverPassthrough(pyblish.api.ContextPlugin):
- """Validate saver passthrough is similar to Pyblish publish state"""
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Saver Passthrough"
- families = ["render", "image"]
- hosts = ["fusion"]
- actions = [SelectInvalidAction]
-
- def process(self, context):
-
- # Workaround for ContextPlugin always running, even if no instance
- # is present with the family
- instances = pyblish.api.instances_by_plugin(instances=list(context),
- plugin=self)
- if not instances:
- self.log.debug("Ignoring plugin.. (bugfix)")
-
- invalid_instances = []
- for instance in instances:
- invalid = self.is_invalid(instance)
- if invalid:
- invalid_instances.append(instance)
-
- if invalid_instances:
- self.log.info("Reset pyblish to collect your current scene state, "
- "that should fix error.")
- raise PublishValidationError(
- "Invalid instances: {0}".format(invalid_instances),
- title=self.label)
-
- def is_invalid(self, instance):
-
- saver = instance.data["tool"]
- attr = saver.GetAttrs()
- active = not attr["TOOLB_PassThrough"]
-
- if active != instance.data.get("publish", True):
- self.log.info("Saver has different passthrough state than "
- "Pyblish: {} ({})".format(instance, saver.Name))
- return [saver]
-
- return []
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_resolution.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_resolution.py
deleted file mode 100644
index 15d96a9afc..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_saver_resolution.py
+++ /dev/null
@@ -1,116 +0,0 @@
-import pyblish.api
-from ayon_core.pipeline import (
- PublishValidationError,
- OptionalPyblishPluginMixin,
-)
-
-from ayon_fusion.api.action import SelectInvalidAction
-from ayon_fusion.api import comp_lock_and_undo_chunk
-
-
-class ValidateSaverResolution(
- pyblish.api.InstancePlugin, OptionalPyblishPluginMixin
-):
- """Validate that the saver input resolution matches the folder resolution"""
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Folder Resolution"
- families = ["render", "image"]
- hosts = ["fusion"]
- optional = True
- actions = [SelectInvalidAction]
-
- def process(self, instance):
- if not self.is_active(instance.data):
- return
-
- resolution = self.get_resolution(instance)
- expected_resolution = self.get_expected_resolution(instance)
- if resolution != expected_resolution:
- raise PublishValidationError(
- "The input's resolution does not match "
- "the folder's resolution {}x{}.\n\n"
- "The input's resolution is {}x{}.".format(
- expected_resolution[0], expected_resolution[1],
- resolution[0], resolution[1]
- )
- )
-
- @classmethod
- def get_invalid(cls, instance):
- saver = instance.data["tool"]
- try:
- resolution = cls.get_resolution(instance)
- except PublishValidationError:
- resolution = None
- expected_resolution = cls.get_expected_resolution(instance)
- if resolution != expected_resolution:
- return [saver]
-
- @classmethod
- def get_resolution(cls, instance):
- saver = instance.data["tool"]
- first_frame = instance.data["frameStartHandle"]
- return cls.get_tool_resolution(saver, frame=first_frame)
-
- @classmethod
- def get_expected_resolution(cls, instance):
- attributes = instance.data["folderEntity"]["attrib"]
- return attributes["resolutionWidth"], attributes["resolutionHeight"]
-
- @classmethod
- def get_tool_resolution(cls, tool, frame):
- """Return the 2D input resolution to a Fusion tool
-
- If the current tool hasn't been rendered its input resolution
- hasn't been saved. To combat this, add an expression in
- the comments field to read the resolution
-
- Args
- tool (Fusion Tool): The tool to query input resolution
- frame (int): The frame to query the resolution on.
-
- Returns:
- tuple: width, height as 2-tuple of integers
-
- """
- comp = tool.Composition
-
- # False undo removes the undo-stack from the undo list
- with comp_lock_and_undo_chunk(comp, "Read resolution", False):
- # Save old comment
- old_comment = ""
- has_expression = False
-
- if tool["Comments"][frame] not in ["", None]:
- if tool["Comments"].GetExpression() is not None:
- has_expression = True
- old_comment = tool["Comments"].GetExpression()
- tool["Comments"].SetExpression(None)
- else:
- old_comment = tool["Comments"][frame]
- tool["Comments"][frame] = ""
- # Get input width
- tool["Comments"].SetExpression("self.Input.OriginalWidth")
- if tool["Comments"][frame] is None:
- raise PublishValidationError(
- "Cannot get resolution info for frame '{}'.\n\n "
- "Please check that saver has connected input.".format(
- frame
- )
- )
-
- width = int(tool["Comments"][frame])
-
- # Get input height
- tool["Comments"].SetExpression("self.Input.OriginalHeight")
- height = int(tool["Comments"][frame])
-
- # Reset old comment
- tool["Comments"].SetExpression(None)
- if has_expression:
- tool["Comments"].SetExpression(old_comment)
- else:
- tool["Comments"][frame] = old_comment
-
- return width, height
diff --git a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_unique_subsets.py b/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_unique_subsets.py
deleted file mode 100644
index dd7df54da5..0000000000
--- a/server_addon/fusion/client/ayon_fusion/plugins/publish/validate_unique_subsets.py
+++ /dev/null
@@ -1,62 +0,0 @@
-from collections import defaultdict
-
-import pyblish.api
-from ayon_core.pipeline import PublishValidationError
-
-from ayon_fusion.api.action import SelectInvalidAction
-
-
-class ValidateUniqueSubsets(pyblish.api.ContextPlugin):
- """Ensure all instances have a unique product name"""
-
- order = pyblish.api.ValidatorOrder
- label = "Validate Unique Products"
- families = ["render", "image"]
- hosts = ["fusion"]
- actions = [SelectInvalidAction]
-
- @classmethod
- def get_invalid(cls, context):
-
- # Collect instances per product per folder
- instances_per_product_folder = defaultdict(lambda: defaultdict(list))
- for instance in context:
- folder_path = instance.data["folderPath"]
- product_name = instance.data["productName"]
- instances_per_product_folder[folder_path][product_name].append(
- instance
- )
-
- # Find which folder + subset combination has more than one instance
- # Those are considered invalid because they'd integrate to the same
- # destination.
- invalid = []
- for folder_path, instances_per_product in (
- instances_per_product_folder.items()
- ):
- for product_name, instances in instances_per_product.items():
- if len(instances) > 1:
- cls.log.warning(
- (
- "{folder_path} > {product_name} used by more than "
- "one instance: {instances}"
- ).format(
- folder_path=folder_path,
- product_name=product_name,
- instances=instances
- )
- )
- invalid.extend(instances)
-
- # Return tools for the invalid instances so they can be selected
- invalid = [instance.data["tool"] for instance in invalid]
-
- return invalid
-
- def process(self, context):
- invalid = self.get_invalid(context)
- if invalid:
- raise PublishValidationError(
- "Multiple instances are set to the same folder > product.",
- title=self.label
- )
diff --git a/server_addon/fusion/client/ayon_fusion/scripts/__init__.py b/server_addon/fusion/client/ayon_fusion/scripts/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/server_addon/fusion/client/ayon_fusion/scripts/duplicate_with_inputs.py b/server_addon/fusion/client/ayon_fusion/scripts/duplicate_with_inputs.py
deleted file mode 100644
index 78edb1b3ba..0000000000
--- a/server_addon/fusion/client/ayon_fusion/scripts/duplicate_with_inputs.py
+++ /dev/null
@@ -1,45 +0,0 @@
-from ayon_fusion.api import (
- comp_lock_and_undo_chunk,
- get_current_comp
-)
-
-
-def is_connected(input):
- """Return whether an input has incoming connection"""
- return input.GetAttrs()["INPB_Connected"]
-
-
-def duplicate_with_input_connections():
- """Duplicate selected tools with incoming connections."""
-
- comp = get_current_comp()
- original_tools = comp.GetToolList(True).values()
- if not original_tools:
- return # nothing selected
-
- with comp_lock_and_undo_chunk(
- comp, "Duplicate With Input Connections"):
-
- # Generate duplicates
- comp.Copy()
- comp.SetActiveTool()
- comp.Paste()
- duplicate_tools = comp.GetToolList(True).values()
-
- # Copy connections
- for original, new in zip(original_tools, duplicate_tools):
-
- original_inputs = original.GetInputList().values()
- new_inputs = new.GetInputList().values()
- assert len(original_inputs) == len(new_inputs)
-
- for original_input, new_input in zip(original_inputs, new_inputs):
-
- if is_connected(original_input):
-
- if is_connected(new_input):
- # Already connected if it is between the copied tools
- continue
-
- new_input.ConnectTo(original_input.GetConnectedOutput())
- assert is_connected(new_input), "Must be connected now"
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/__init__.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/__init__.py
deleted file mode 100644
index b1ce7fe248..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/__init__.py
+++ /dev/null
@@ -1,78 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-import sys
-
-from functools import partial
-
-from . import converters, exceptions, filters, setters, validators
-from ._cmp import cmp_using
-from ._config import get_run_validators, set_run_validators
-from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types
-from ._make import (
- NOTHING,
- Attribute,
- Factory,
- attrib,
- attrs,
- fields,
- fields_dict,
- make_class,
- validate,
-)
-from ._version_info import VersionInfo
-
-
-__version__ = "21.2.0"
-__version_info__ = VersionInfo._from_version_string(__version__)
-
-__title__ = "attrs"
-__description__ = "Classes Without Boilerplate"
-__url__ = "https://www.attrs.org/"
-__uri__ = __url__
-__doc__ = __description__ + " <" + __uri__ + ">"
-
-__author__ = "Hynek Schlawack"
-__email__ = "hs@ox.cx"
-
-__license__ = "MIT"
-__copyright__ = "Copyright (c) 2015 Hynek Schlawack"
-
-
-s = attributes = attrs
-ib = attr = attrib
-dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)
-
-__all__ = [
- "Attribute",
- "Factory",
- "NOTHING",
- "asdict",
- "assoc",
- "astuple",
- "attr",
- "attrib",
- "attributes",
- "attrs",
- "cmp_using",
- "converters",
- "evolve",
- "exceptions",
- "fields",
- "fields_dict",
- "filters",
- "get_run_validators",
- "has",
- "ib",
- "make_class",
- "resolve_types",
- "s",
- "set_run_validators",
- "setters",
- "validate",
- "validators",
-]
-
-if sys.version_info[:2] >= (3, 6):
- from ._next_gen import define, field, frozen, mutable
-
- __all__.extend((define, field, frozen, mutable))
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/__init__.pyi b/server_addon/fusion/client/ayon_fusion/vendor/attr/__init__.pyi
deleted file mode 100644
index 3503b073b4..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/__init__.pyi
+++ /dev/null
@@ -1,475 +0,0 @@
-import sys
-
-from typing import (
- Any,
- Callable,
- Dict,
- Generic,
- List,
- Mapping,
- Optional,
- Sequence,
- Tuple,
- Type,
- TypeVar,
- Union,
- overload,
-)
-
-# `import X as X` is required to make these public
-from . import converters as converters
-from . import exceptions as exceptions
-from . import filters as filters
-from . import setters as setters
-from . import validators as validators
-from ._version_info import VersionInfo
-
-
-__version__: str
-__version_info__: VersionInfo
-__title__: str
-__description__: str
-__url__: str
-__uri__: str
-__author__: str
-__email__: str
-__license__: str
-__copyright__: str
-
-_T = TypeVar("_T")
-_C = TypeVar("_C", bound=type)
-
-_EqOrderType = Union[bool, Callable[[Any], Any]]
-_ValidatorType = Callable[[Any, Attribute[_T], _T], Any]
-_ConverterType = Callable[[Any], Any]
-_FilterType = Callable[[Attribute[_T], _T], bool]
-_ReprType = Callable[[Any], str]
-_ReprArgType = Union[bool, _ReprType]
-_OnSetAttrType = Callable[[Any, Attribute[Any], Any], Any]
-_OnSetAttrArgType = Union[
- _OnSetAttrType, List[_OnSetAttrType], setters._NoOpType
-]
-_FieldTransformer = Callable[[type, List[Attribute[Any]]], List[Attribute[Any]]]
-# FIXME: in reality, if multiple validators are passed they must be in a list
-# or tuple, but those are invariant and so would prevent subtypes of
-# _ValidatorType from working when passed in a list or tuple.
-_ValidatorArgType = Union[_ValidatorType[_T], Sequence[_ValidatorType[_T]]]
-
-# _make --
-
-NOTHING: object
-
-# NOTE: Factory lies about its return type to make this possible:
-# `x: List[int] # = Factory(list)`
-# Work around mypy issue #4554 in the common case by using an overload.
-if sys.version_info >= (3, 8):
- from typing import Literal
-
- @overload
- def Factory(factory: Callable[[], _T]) -> _T: ...
- @overload
- def Factory(
- factory: Callable[[Any], _T],
- takes_self: Literal[True],
- ) -> _T: ...
- @overload
- def Factory(
- factory: Callable[[], _T],
- takes_self: Literal[False],
- ) -> _T: ...
-else:
- @overload
- def Factory(factory: Callable[[], _T]) -> _T: ...
- @overload
- def Factory(
- factory: Union[Callable[[Any], _T], Callable[[], _T]],
- takes_self: bool = ...,
- ) -> _T: ...
-
-# Static type inference support via __dataclass_transform__ implemented as per:
-# https://github.com/microsoft/pyright/blob/1.1.135/specs/dataclass_transforms.md
-# This annotation must be applied to all overloads of "define" and "attrs"
-#
-# NOTE: This is a typing construct and does not exist at runtime. Extensions
-# wrapping attrs decorators should declare a separate __dataclass_transform__
-# signature in the extension module using the specification linked above to
-# provide pyright support.
-def __dataclass_transform__(
- *,
- eq_default: bool = True,
- order_default: bool = False,
- kw_only_default: bool = False,
- field_descriptors: Tuple[Union[type, Callable[..., Any]], ...] = (()),
-) -> Callable[[_T], _T]: ...
-
-class Attribute(Generic[_T]):
- name: str
- default: Optional[_T]
- validator: Optional[_ValidatorType[_T]]
- repr: _ReprArgType
- cmp: _EqOrderType
- eq: _EqOrderType
- order: _EqOrderType
- hash: Optional[bool]
- init: bool
- converter: Optional[_ConverterType]
- metadata: Dict[Any, Any]
- type: Optional[Type[_T]]
- kw_only: bool
- on_setattr: _OnSetAttrType
-
- def evolve(self, **changes: Any) -> "Attribute[Any]": ...
-
-# NOTE: We had several choices for the annotation to use for type arg:
-# 1) Type[_T]
-# - Pros: Handles simple cases correctly
-# - Cons: Might produce less informative errors in the case of conflicting
-# TypeVars e.g. `attr.ib(default='bad', type=int)`
-# 2) Callable[..., _T]
-# - Pros: Better error messages than #1 for conflicting TypeVars
-# - Cons: Terrible error messages for validator checks.
-# e.g. attr.ib(type=int, validator=validate_str)
-# -> error: Cannot infer function type argument
-# 3) type (and do all of the work in the mypy plugin)
-# - Pros: Simple here, and we could customize the plugin with our own errors.
-# - Cons: Would need to write mypy plugin code to handle all the cases.
-# We chose option #1.
-
-# `attr` lies about its return type to make the following possible:
-# attr() -> Any
-# attr(8) -> int
-# attr(validator=) -> Whatever the callable expects.
-# This makes this type of assignments possible:
-# x: int = attr(8)
-#
-# This form catches explicit None or no default but with no other arguments
-# returns Any.
-@overload
-def attrib(
- default: None = ...,
- validator: None = ...,
- repr: _ReprArgType = ...,
- cmp: Optional[_EqOrderType] = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- metadata: Optional[Mapping[Any, Any]] = ...,
- type: None = ...,
- converter: None = ...,
- factory: None = ...,
- kw_only: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
-) -> Any: ...
-
-# This form catches an explicit None or no default and infers the type from the
-# other arguments.
-@overload
-def attrib(
- default: None = ...,
- validator: Optional[_ValidatorArgType[_T]] = ...,
- repr: _ReprArgType = ...,
- cmp: Optional[_EqOrderType] = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- metadata: Optional[Mapping[Any, Any]] = ...,
- type: Optional[Type[_T]] = ...,
- converter: Optional[_ConverterType] = ...,
- factory: Optional[Callable[[], _T]] = ...,
- kw_only: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
-) -> _T: ...
-
-# This form catches an explicit default argument.
-@overload
-def attrib(
- default: _T,
- validator: Optional[_ValidatorArgType[_T]] = ...,
- repr: _ReprArgType = ...,
- cmp: Optional[_EqOrderType] = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- metadata: Optional[Mapping[Any, Any]] = ...,
- type: Optional[Type[_T]] = ...,
- converter: Optional[_ConverterType] = ...,
- factory: Optional[Callable[[], _T]] = ...,
- kw_only: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
-) -> _T: ...
-
-# This form covers type=non-Type: e.g. forward references (str), Any
-@overload
-def attrib(
- default: Optional[_T] = ...,
- validator: Optional[_ValidatorArgType[_T]] = ...,
- repr: _ReprArgType = ...,
- cmp: Optional[_EqOrderType] = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- metadata: Optional[Mapping[Any, Any]] = ...,
- type: object = ...,
- converter: Optional[_ConverterType] = ...,
- factory: Optional[Callable[[], _T]] = ...,
- kw_only: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
-) -> Any: ...
-@overload
-def field(
- *,
- default: None = ...,
- validator: None = ...,
- repr: _ReprArgType = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- metadata: Optional[Mapping[Any, Any]] = ...,
- converter: None = ...,
- factory: None = ...,
- kw_only: bool = ...,
- eq: Optional[bool] = ...,
- order: Optional[bool] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
-) -> Any: ...
-
-# This form catches an explicit None or no default and infers the type from the
-# other arguments.
-@overload
-def field(
- *,
- default: None = ...,
- validator: Optional[_ValidatorArgType[_T]] = ...,
- repr: _ReprArgType = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- metadata: Optional[Mapping[Any, Any]] = ...,
- converter: Optional[_ConverterType] = ...,
- factory: Optional[Callable[[], _T]] = ...,
- kw_only: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
-) -> _T: ...
-
-# This form catches an explicit default argument.
-@overload
-def field(
- *,
- default: _T,
- validator: Optional[_ValidatorArgType[_T]] = ...,
- repr: _ReprArgType = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- metadata: Optional[Mapping[Any, Any]] = ...,
- converter: Optional[_ConverterType] = ...,
- factory: Optional[Callable[[], _T]] = ...,
- kw_only: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
-) -> _T: ...
-
-# This form covers type=non-Type: e.g. forward references (str), Any
-@overload
-def field(
- *,
- default: Optional[_T] = ...,
- validator: Optional[_ValidatorArgType[_T]] = ...,
- repr: _ReprArgType = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- metadata: Optional[Mapping[Any, Any]] = ...,
- converter: Optional[_ConverterType] = ...,
- factory: Optional[Callable[[], _T]] = ...,
- kw_only: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
-) -> Any: ...
-@overload
-@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field))
-def attrs(
- maybe_cls: _C,
- these: Optional[Dict[str, Any]] = ...,
- repr_ns: Optional[str] = ...,
- repr: bool = ...,
- cmp: Optional[_EqOrderType] = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- slots: bool = ...,
- frozen: bool = ...,
- weakref_slot: bool = ...,
- str: bool = ...,
- auto_attribs: bool = ...,
- kw_only: bool = ...,
- cache_hash: bool = ...,
- auto_exc: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- auto_detect: bool = ...,
- collect_by_mro: bool = ...,
- getstate_setstate: Optional[bool] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
- field_transformer: Optional[_FieldTransformer] = ...,
-) -> _C: ...
-@overload
-@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field))
-def attrs(
- maybe_cls: None = ...,
- these: Optional[Dict[str, Any]] = ...,
- repr_ns: Optional[str] = ...,
- repr: bool = ...,
- cmp: Optional[_EqOrderType] = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- slots: bool = ...,
- frozen: bool = ...,
- weakref_slot: bool = ...,
- str: bool = ...,
- auto_attribs: bool = ...,
- kw_only: bool = ...,
- cache_hash: bool = ...,
- auto_exc: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- auto_detect: bool = ...,
- collect_by_mro: bool = ...,
- getstate_setstate: Optional[bool] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
- field_transformer: Optional[_FieldTransformer] = ...,
-) -> Callable[[_C], _C]: ...
-@overload
-@__dataclass_transform__(field_descriptors=(attrib, field))
-def define(
- maybe_cls: _C,
- *,
- these: Optional[Dict[str, Any]] = ...,
- repr: bool = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- slots: bool = ...,
- frozen: bool = ...,
- weakref_slot: bool = ...,
- str: bool = ...,
- auto_attribs: bool = ...,
- kw_only: bool = ...,
- cache_hash: bool = ...,
- auto_exc: bool = ...,
- eq: Optional[bool] = ...,
- order: Optional[bool] = ...,
- auto_detect: bool = ...,
- getstate_setstate: Optional[bool] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
- field_transformer: Optional[_FieldTransformer] = ...,
-) -> _C: ...
-@overload
-@__dataclass_transform__(field_descriptors=(attrib, field))
-def define(
- maybe_cls: None = ...,
- *,
- these: Optional[Dict[str, Any]] = ...,
- repr: bool = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- slots: bool = ...,
- frozen: bool = ...,
- weakref_slot: bool = ...,
- str: bool = ...,
- auto_attribs: bool = ...,
- kw_only: bool = ...,
- cache_hash: bool = ...,
- auto_exc: bool = ...,
- eq: Optional[bool] = ...,
- order: Optional[bool] = ...,
- auto_detect: bool = ...,
- getstate_setstate: Optional[bool] = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
- field_transformer: Optional[_FieldTransformer] = ...,
-) -> Callable[[_C], _C]: ...
-
-mutable = define
-frozen = define # they differ only in their defaults
-
-# TODO: add support for returning NamedTuple from the mypy plugin
-class _Fields(Tuple[Attribute[Any], ...]):
- def __getattr__(self, name: str) -> Attribute[Any]: ...
-
-def fields(cls: type) -> _Fields: ...
-def fields_dict(cls: type) -> Dict[str, Attribute[Any]]: ...
-def validate(inst: Any) -> None: ...
-def resolve_types(
- cls: _C,
- globalns: Optional[Dict[str, Any]] = ...,
- localns: Optional[Dict[str, Any]] = ...,
- attribs: Optional[List[Attribute[Any]]] = ...,
-) -> _C: ...
-
-# TODO: add support for returning a proper attrs class from the mypy plugin
-# we use Any instead of _CountingAttr so that e.g. `make_class('Foo',
-# [attr.ib()])` is valid
-def make_class(
- name: str,
- attrs: Union[List[str], Tuple[str, ...], Dict[str, Any]],
- bases: Tuple[type, ...] = ...,
- repr_ns: Optional[str] = ...,
- repr: bool = ...,
- cmp: Optional[_EqOrderType] = ...,
- hash: Optional[bool] = ...,
- init: bool = ...,
- slots: bool = ...,
- frozen: bool = ...,
- weakref_slot: bool = ...,
- str: bool = ...,
- auto_attribs: bool = ...,
- kw_only: bool = ...,
- cache_hash: bool = ...,
- auto_exc: bool = ...,
- eq: Optional[_EqOrderType] = ...,
- order: Optional[_EqOrderType] = ...,
- collect_by_mro: bool = ...,
- on_setattr: Optional[_OnSetAttrArgType] = ...,
- field_transformer: Optional[_FieldTransformer] = ...,
-) -> type: ...
-
-# _funcs --
-
-# TODO: add support for returning TypedDict from the mypy plugin
-# FIXME: asdict/astuple do not honor their factory args. Waiting on one of
-# these:
-# https://github.com/python/mypy/issues/4236
-# https://github.com/python/typing/issues/253
-def asdict(
- inst: Any,
- recurse: bool = ...,
- filter: Optional[_FilterType[Any]] = ...,
- dict_factory: Type[Mapping[Any, Any]] = ...,
- retain_collection_types: bool = ...,
- value_serializer: Optional[Callable[[type, Attribute[Any], Any], Any]] = ...,
-) -> Dict[str, Any]: ...
-
-# TODO: add support for returning NamedTuple from the mypy plugin
-def astuple(
- inst: Any,
- recurse: bool = ...,
- filter: Optional[_FilterType[Any]] = ...,
- tuple_factory: Type[Sequence[Any]] = ...,
- retain_collection_types: bool = ...,
-) -> Tuple[Any, ...]: ...
-def has(cls: type) -> bool: ...
-def assoc(inst: _T, **changes: Any) -> _T: ...
-def evolve(inst: _T, **changes: Any) -> _T: ...
-
-# _config --
-
-def set_run_validators(run: bool) -> None: ...
-def get_run_validators() -> bool: ...
-
-# aliases --
-
-s = attributes = attrs
-ib = attr = attrib
-dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/_cmp.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/_cmp.py
deleted file mode 100644
index b747b603f1..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/_cmp.py
+++ /dev/null
@@ -1,152 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-import functools
-
-from ._compat import new_class
-from ._make import _make_ne
-
-
-_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="}
-
-
-def cmp_using(
- eq=None,
- lt=None,
- le=None,
- gt=None,
- ge=None,
- require_same_type=True,
- class_name="Comparable",
-):
- """
- Create a class that can be passed into `attr.ib`'s ``eq``, ``order``, and
- ``cmp`` arguments to customize field comparison.
-
- The resulting class will have a full set of ordering methods if
- at least one of ``{lt, le, gt, ge}`` and ``eq`` are provided.
-
- :param Optional[callable] eq: `callable` used to evaluate equality
- of two objects.
- :param Optional[callable] lt: `callable` used to evaluate whether
- one object is less than another object.
- :param Optional[callable] le: `callable` used to evaluate whether
- one object is less than or equal to another object.
- :param Optional[callable] gt: `callable` used to evaluate whether
- one object is greater than another object.
- :param Optional[callable] ge: `callable` used to evaluate whether
- one object is greater than or equal to another object.
-
- :param bool require_same_type: When `True`, equality and ordering methods
- will return `NotImplemented` if objects are not of the same type.
-
- :param Optional[str] class_name: Name of class. Defaults to 'Comparable'.
-
- See `comparison` for more details.
-
- .. versionadded:: 21.1.0
- """
-
- body = {
- "__slots__": ["value"],
- "__init__": _make_init(),
- "_requirements": [],
- "_is_comparable_to": _is_comparable_to,
- }
-
- # Add operations.
- num_order_functions = 0
- has_eq_function = False
-
- if eq is not None:
- has_eq_function = True
- body["__eq__"] = _make_operator("eq", eq)
- body["__ne__"] = _make_ne()
-
- if lt is not None:
- num_order_functions += 1
- body["__lt__"] = _make_operator("lt", lt)
-
- if le is not None:
- num_order_functions += 1
- body["__le__"] = _make_operator("le", le)
-
- if gt is not None:
- num_order_functions += 1
- body["__gt__"] = _make_operator("gt", gt)
-
- if ge is not None:
- num_order_functions += 1
- body["__ge__"] = _make_operator("ge", ge)
-
- type_ = new_class(class_name, (object,), {}, lambda ns: ns.update(body))
-
- # Add same type requirement.
- if require_same_type:
- type_._requirements.append(_check_same_type)
-
- # Add total ordering if at least one operation was defined.
- if 0 < num_order_functions < 4:
- if not has_eq_function:
- # functools.total_ordering requires __eq__ to be defined,
- # so raise early error here to keep a nice stack.
- raise ValueError(
- "eq must be define is order to complete ordering from "
- "lt, le, gt, ge."
- )
- type_ = functools.total_ordering(type_)
-
- return type_
-
-
-def _make_init():
- """
- Create __init__ method.
- """
-
- def __init__(self, value):
- """
- Initialize object with *value*.
- """
- self.value = value
-
- return __init__
-
-
-def _make_operator(name, func):
- """
- Create operator method.
- """
-
- def method(self, other):
- if not self._is_comparable_to(other):
- return NotImplemented
-
- result = func(self.value, other.value)
- if result is NotImplemented:
- return NotImplemented
-
- return result
-
- method.__name__ = "__%s__" % (name,)
- method.__doc__ = "Return a %s b. Computed by attrs." % (
- _operation_names[name],
- )
-
- return method
-
-
-def _is_comparable_to(self, other):
- """
- Check whether `other` is comparable to `self`.
- """
- for func in self._requirements:
- if not func(self, other):
- return False
- return True
-
-
-def _check_same_type(self, other):
- """
- Return True if *self* and *other* are of the same type, False otherwise.
- """
- return other.value.__class__ is self.value.__class__
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/_cmp.pyi b/server_addon/fusion/client/ayon_fusion/vendor/attr/_cmp.pyi
deleted file mode 100644
index 7093550f0f..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/_cmp.pyi
+++ /dev/null
@@ -1,14 +0,0 @@
-from typing import Type
-
-from . import _CompareWithType
-
-
-def cmp_using(
- eq: Optional[_CompareWithType],
- lt: Optional[_CompareWithType],
- le: Optional[_CompareWithType],
- gt: Optional[_CompareWithType],
- ge: Optional[_CompareWithType],
- require_same_type: bool,
- class_name: str,
-) -> Type: ...
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/_compat.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/_compat.py
deleted file mode 100644
index 6939f338da..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/_compat.py
+++ /dev/null
@@ -1,242 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-import platform
-import sys
-import types
-import warnings
-
-
-PY2 = sys.version_info[0] == 2
-PYPY = platform.python_implementation() == "PyPy"
-
-
-if PYPY or sys.version_info[:2] >= (3, 6):
- ordered_dict = dict
-else:
- from collections import OrderedDict
-
- ordered_dict = OrderedDict
-
-
-if PY2:
- from collections import Mapping, Sequence
-
- from UserDict import IterableUserDict
-
- # We 'bundle' isclass instead of using inspect as importing inspect is
- # fairly expensive (order of 10-15 ms for a modern machine in 2016)
- def isclass(klass):
- return isinstance(klass, (type, types.ClassType))
-
- def new_class(name, bases, kwds, exec_body):
- """
- A minimal stub of types.new_class that we need for make_class.
- """
- ns = {}
- exec_body(ns)
-
- return type(name, bases, ns)
-
- # TYPE is used in exceptions, repr(int) is different on Python 2 and 3.
- TYPE = "type"
-
- def iteritems(d):
- return d.iteritems()
-
- # Python 2 is bereft of a read-only dict proxy, so we make one!
- class ReadOnlyDict(IterableUserDict):
- """
- Best-effort read-only dict wrapper.
- """
-
- def __setitem__(self, key, val):
- # We gently pretend we're a Python 3 mappingproxy.
- raise TypeError(
- "'mappingproxy' object does not support item assignment"
- )
-
- def update(self, _):
- # We gently pretend we're a Python 3 mappingproxy.
- raise AttributeError(
- "'mappingproxy' object has no attribute 'update'"
- )
-
- def __delitem__(self, _):
- # We gently pretend we're a Python 3 mappingproxy.
- raise TypeError(
- "'mappingproxy' object does not support item deletion"
- )
-
- def clear(self):
- # We gently pretend we're a Python 3 mappingproxy.
- raise AttributeError(
- "'mappingproxy' object has no attribute 'clear'"
- )
-
- def pop(self, key, default=None):
- # We gently pretend we're a Python 3 mappingproxy.
- raise AttributeError(
- "'mappingproxy' object has no attribute 'pop'"
- )
-
- def popitem(self):
- # We gently pretend we're a Python 3 mappingproxy.
- raise AttributeError(
- "'mappingproxy' object has no attribute 'popitem'"
- )
-
- def setdefault(self, key, default=None):
- # We gently pretend we're a Python 3 mappingproxy.
- raise AttributeError(
- "'mappingproxy' object has no attribute 'setdefault'"
- )
-
- def __repr__(self):
- # Override to be identical to the Python 3 version.
- return "mappingproxy(" + repr(self.data) + ")"
-
- def metadata_proxy(d):
- res = ReadOnlyDict()
- res.data.update(d) # We blocked update, so we have to do it like this.
- return res
-
- def just_warn(*args, **kw): # pragma: no cover
- """
- We only warn on Python 3 because we are not aware of any concrete
- consequences of not setting the cell on Python 2.
- """
-
-
-else: # Python 3 and later.
- from collections.abc import Mapping, Sequence # noqa
-
- def just_warn(*args, **kw):
- """
- We only warn on Python 3 because we are not aware of any concrete
- consequences of not setting the cell on Python 2.
- """
- warnings.warn(
- "Running interpreter doesn't sufficiently support code object "
- "introspection. Some features like bare super() or accessing "
- "__class__ will not work with slotted classes.",
- RuntimeWarning,
- stacklevel=2,
- )
-
- def isclass(klass):
- return isinstance(klass, type)
-
- TYPE = "class"
-
- def iteritems(d):
- return d.items()
-
- new_class = types.new_class
-
- def metadata_proxy(d):
- return types.MappingProxyType(dict(d))
-
-
-def make_set_closure_cell():
- """Return a function of two arguments (cell, value) which sets
- the value stored in the closure cell `cell` to `value`.
- """
- # pypy makes this easy. (It also supports the logic below, but
- # why not do the easy/fast thing?)
- if PYPY:
-
- def set_closure_cell(cell, value):
- cell.__setstate__((value,))
-
- return set_closure_cell
-
- # Otherwise gotta do it the hard way.
-
- # Create a function that will set its first cellvar to `value`.
- def set_first_cellvar_to(value):
- x = value
- return
-
- # This function will be eliminated as dead code, but
- # not before its reference to `x` forces `x` to be
- # represented as a closure cell rather than a local.
- def force_x_to_be_a_cell(): # pragma: no cover
- return x
-
- try:
- # Extract the code object and make sure our assumptions about
- # the closure behavior are correct.
- if PY2:
- co = set_first_cellvar_to.func_code
- else:
- co = set_first_cellvar_to.__code__
- if co.co_cellvars != ("x",) or co.co_freevars != ():
- raise AssertionError # pragma: no cover
-
- # Convert this code object to a code object that sets the
- # function's first _freevar_ (not cellvar) to the argument.
- if sys.version_info >= (3, 8):
- # CPython 3.8+ has an incompatible CodeType signature
- # (added a posonlyargcount argument) but also added
- # CodeType.replace() to do this without counting parameters.
- set_first_freevar_code = co.replace(
- co_cellvars=co.co_freevars, co_freevars=co.co_cellvars
- )
- else:
- args = [co.co_argcount]
- if not PY2:
- args.append(co.co_kwonlyargcount)
- args.extend(
- [
- co.co_nlocals,
- co.co_stacksize,
- co.co_flags,
- co.co_code,
- co.co_consts,
- co.co_names,
- co.co_varnames,
- co.co_filename,
- co.co_name,
- co.co_firstlineno,
- co.co_lnotab,
- # These two arguments are reversed:
- co.co_cellvars,
- co.co_freevars,
- ]
- )
- set_first_freevar_code = types.CodeType(*args)
-
- def set_closure_cell(cell, value):
- # Create a function using the set_first_freevar_code,
- # whose first closure cell is `cell`. Calling it will
- # change the value of that cell.
- setter = types.FunctionType(
- set_first_freevar_code, {}, "setter", (), (cell,)
- )
- # And call it to set the cell.
- setter(value)
-
- # Make sure it works on this interpreter:
- def make_func_with_cell():
- x = None
-
- def func():
- return x # pragma: no cover
-
- return func
-
- if PY2:
- cell = make_func_with_cell().func_closure[0]
- else:
- cell = make_func_with_cell().__closure__[0]
- set_closure_cell(cell, 100)
- if cell.cell_contents != 100:
- raise AssertionError # pragma: no cover
-
- except Exception:
- return just_warn
- else:
- return set_closure_cell
-
-
-set_closure_cell = make_set_closure_cell()
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/_config.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/_config.py
deleted file mode 100644
index 8ec920962d..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/_config.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-
-__all__ = ["set_run_validators", "get_run_validators"]
-
-_run_validators = True
-
-
-def set_run_validators(run):
- """
- Set whether or not validators are run. By default, they are run.
- """
- if not isinstance(run, bool):
- raise TypeError("'run' must be bool.")
- global _run_validators
- _run_validators = run
-
-
-def get_run_validators():
- """
- Return whether or not validators are run.
- """
- return _run_validators
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/_funcs.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/_funcs.py
deleted file mode 100644
index fda508c5c4..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/_funcs.py
+++ /dev/null
@@ -1,395 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-import copy
-
-from ._compat import iteritems
-from ._make import NOTHING, _obj_setattr, fields
-from .exceptions import AttrsAttributeNotFoundError
-
-
-def asdict(
- inst,
- recurse=True,
- filter=None,
- dict_factory=dict,
- retain_collection_types=False,
- value_serializer=None,
-):
- """
- Return the ``attrs`` attribute values of *inst* as a dict.
-
- Optionally recurse into other ``attrs``-decorated classes.
-
- :param inst: Instance of an ``attrs``-decorated class.
- :param bool recurse: Recurse into classes that are also
- ``attrs``-decorated.
- :param callable filter: A callable whose return code determines whether an
- attribute or element is included (``True``) or dropped (``False``). Is
- called with the `attr.Attribute` as the first argument and the
- value as the second argument.
- :param callable dict_factory: A callable to produce dictionaries from. For
- example, to produce ordered dictionaries instead of normal Python
- dictionaries, pass in ``collections.OrderedDict``.
- :param bool retain_collection_types: Do not convert to ``list`` when
- encountering an attribute whose type is ``tuple`` or ``set``. Only
- meaningful if ``recurse`` is ``True``.
- :param Optional[callable] value_serializer: A hook that is called for every
- attribute or dict key/value. It receives the current instance, field
- and value and must return the (updated) value. The hook is run *after*
- the optional *filter* has been applied.
-
- :rtype: return type of *dict_factory*
-
- :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
- class.
-
- .. versionadded:: 16.0.0 *dict_factory*
- .. versionadded:: 16.1.0 *retain_collection_types*
- .. versionadded:: 20.3.0 *value_serializer*
- """
- attrs = fields(inst.__class__)
- rv = dict_factory()
- for a in attrs:
- v = getattr(inst, a.name)
- if filter is not None and not filter(a, v):
- continue
-
- if value_serializer is not None:
- v = value_serializer(inst, a, v)
-
- if recurse is True:
- if has(v.__class__):
- rv[a.name] = asdict(
- v,
- True,
- filter,
- dict_factory,
- retain_collection_types,
- value_serializer,
- )
- elif isinstance(v, (tuple, list, set, frozenset)):
- cf = v.__class__ if retain_collection_types is True else list
- rv[a.name] = cf(
- [
- _asdict_anything(
- i,
- filter,
- dict_factory,
- retain_collection_types,
- value_serializer,
- )
- for i in v
- ]
- )
- elif isinstance(v, dict):
- df = dict_factory
- rv[a.name] = df(
- (
- _asdict_anything(
- kk,
- filter,
- df,
- retain_collection_types,
- value_serializer,
- ),
- _asdict_anything(
- vv,
- filter,
- df,
- retain_collection_types,
- value_serializer,
- ),
- )
- for kk, vv in iteritems(v)
- )
- else:
- rv[a.name] = v
- else:
- rv[a.name] = v
- return rv
-
-
-def _asdict_anything(
- val,
- filter,
- dict_factory,
- retain_collection_types,
- value_serializer,
-):
- """
- ``asdict`` only works on attrs instances, this works on anything.
- """
- if getattr(val.__class__, "__attrs_attrs__", None) is not None:
- # Attrs class.
- rv = asdict(
- val,
- True,
- filter,
- dict_factory,
- retain_collection_types,
- value_serializer,
- )
- elif isinstance(val, (tuple, list, set, frozenset)):
- cf = val.__class__ if retain_collection_types is True else list
- rv = cf(
- [
- _asdict_anything(
- i,
- filter,
- dict_factory,
- retain_collection_types,
- value_serializer,
- )
- for i in val
- ]
- )
- elif isinstance(val, dict):
- df = dict_factory
- rv = df(
- (
- _asdict_anything(
- kk, filter, df, retain_collection_types, value_serializer
- ),
- _asdict_anything(
- vv, filter, df, retain_collection_types, value_serializer
- ),
- )
- for kk, vv in iteritems(val)
- )
- else:
- rv = val
- if value_serializer is not None:
- rv = value_serializer(None, None, rv)
-
- return rv
-
-
-def astuple(
- inst,
- recurse=True,
- filter=None,
- tuple_factory=tuple,
- retain_collection_types=False,
-):
- """
- Return the ``attrs`` attribute values of *inst* as a tuple.
-
- Optionally recurse into other ``attrs``-decorated classes.
-
- :param inst: Instance of an ``attrs``-decorated class.
- :param bool recurse: Recurse into classes that are also
- ``attrs``-decorated.
- :param callable filter: A callable whose return code determines whether an
- attribute or element is included (``True``) or dropped (``False``). Is
- called with the `attr.Attribute` as the first argument and the
- value as the second argument.
- :param callable tuple_factory: A callable to produce tuples from. For
- example, to produce lists instead of tuples.
- :param bool retain_collection_types: Do not convert to ``list``
- or ``dict`` when encountering an attribute which type is
- ``tuple``, ``dict`` or ``set``. Only meaningful if ``recurse`` is
- ``True``.
-
- :rtype: return type of *tuple_factory*
-
- :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
- class.
-
- .. versionadded:: 16.2.0
- """
- attrs = fields(inst.__class__)
- rv = []
- retain = retain_collection_types # Very long. :/
- for a in attrs:
- v = getattr(inst, a.name)
- if filter is not None and not filter(a, v):
- continue
- if recurse is True:
- if has(v.__class__):
- rv.append(
- astuple(
- v,
- recurse=True,
- filter=filter,
- tuple_factory=tuple_factory,
- retain_collection_types=retain,
- )
- )
- elif isinstance(v, (tuple, list, set, frozenset)):
- cf = v.__class__ if retain is True else list
- rv.append(
- cf(
- [
- astuple(
- j,
- recurse=True,
- filter=filter,
- tuple_factory=tuple_factory,
- retain_collection_types=retain,
- )
- if has(j.__class__)
- else j
- for j in v
- ]
- )
- )
- elif isinstance(v, dict):
- df = v.__class__ if retain is True else dict
- rv.append(
- df(
- (
- astuple(
- kk,
- tuple_factory=tuple_factory,
- retain_collection_types=retain,
- )
- if has(kk.__class__)
- else kk,
- astuple(
- vv,
- tuple_factory=tuple_factory,
- retain_collection_types=retain,
- )
- if has(vv.__class__)
- else vv,
- )
- for kk, vv in iteritems(v)
- )
- )
- else:
- rv.append(v)
- else:
- rv.append(v)
-
- return rv if tuple_factory is list else tuple_factory(rv)
-
-
-def has(cls):
- """
- Check whether *cls* is a class with ``attrs`` attributes.
-
- :param type cls: Class to introspect.
- :raise TypeError: If *cls* is not a class.
-
- :rtype: bool
- """
- return getattr(cls, "__attrs_attrs__", None) is not None
-
-
-def assoc(inst, **changes):
- """
- Copy *inst* and apply *changes*.
-
- :param inst: Instance of a class with ``attrs`` attributes.
- :param changes: Keyword changes in the new copy.
-
- :return: A copy of inst with *changes* incorporated.
-
- :raise attr.exceptions.AttrsAttributeNotFoundError: If *attr_name* couldn't
- be found on *cls*.
- :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
- class.
-
- .. deprecated:: 17.1.0
- Use `evolve` instead.
- """
- import warnings
-
- warnings.warn(
- "assoc is deprecated and will be removed after 2018/01.",
- DeprecationWarning,
- stacklevel=2,
- )
- new = copy.copy(inst)
- attrs = fields(inst.__class__)
- for k, v in iteritems(changes):
- a = getattr(attrs, k, NOTHING)
- if a is NOTHING:
- raise AttrsAttributeNotFoundError(
- "{k} is not an attrs attribute on {cl}.".format(
- k=k, cl=new.__class__
- )
- )
- _obj_setattr(new, k, v)
- return new
-
-
-def evolve(inst, **changes):
- """
- Create a new instance, based on *inst* with *changes* applied.
-
- :param inst: Instance of a class with ``attrs`` attributes.
- :param changes: Keyword changes in the new copy.
-
- :return: A copy of inst with *changes* incorporated.
-
- :raise TypeError: If *attr_name* couldn't be found in the class
- ``__init__``.
- :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
- class.
-
- .. versionadded:: 17.1.0
- """
- cls = inst.__class__
- attrs = fields(cls)
- for a in attrs:
- if not a.init:
- continue
- attr_name = a.name # To deal with private attributes.
- init_name = attr_name if attr_name[0] != "_" else attr_name[1:]
- if init_name not in changes:
- changes[init_name] = getattr(inst, attr_name)
-
- return cls(**changes)
-
-
-def resolve_types(cls, globalns=None, localns=None, attribs=None):
- """
- Resolve any strings and forward annotations in type annotations.
-
- This is only required if you need concrete types in `Attribute`'s *type*
- field. In other words, you don't need to resolve your types if you only
- use them for static type checking.
-
- With no arguments, names will be looked up in the module in which the class
- was created. If this is not what you want, e.g. if the name only exists
- inside a method, you may pass *globalns* or *localns* to specify other
- dictionaries in which to look up these names. See the docs of
- `typing.get_type_hints` for more details.
-
- :param type cls: Class to resolve.
- :param Optional[dict] globalns: Dictionary containing global variables.
- :param Optional[dict] localns: Dictionary containing local variables.
- :param Optional[list] attribs: List of attribs for the given class.
- This is necessary when calling from inside a ``field_transformer``
- since *cls* is not an ``attrs`` class yet.
-
- :raise TypeError: If *cls* is not a class.
- :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
- class and you didn't pass any attribs.
- :raise NameError: If types cannot be resolved because of missing variables.
-
- :returns: *cls* so you can use this function also as a class decorator.
- Please note that you have to apply it **after** `attr.s`. That means
- the decorator has to come in the line **before** `attr.s`.
-
- .. versionadded:: 20.1.0
- .. versionadded:: 21.1.0 *attribs*
-
- """
- try:
- # Since calling get_type_hints is expensive we cache whether we've
- # done it already.
- cls.__attrs_types_resolved__
- except AttributeError:
- import typing
-
- hints = typing.get_type_hints(cls, globalns=globalns, localns=localns)
- for field in fields(cls) if attribs is None else attribs:
- if field.name in hints:
- # Since fields have been frozen we must work around it.
- _obj_setattr(field, "type", hints[field.name])
- cls.__attrs_types_resolved__ = True
-
- # Return the class so you can use it as a decorator too.
- return cls
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/_make.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/_make.py
deleted file mode 100644
index a1912b1233..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/_make.py
+++ /dev/null
@@ -1,3052 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-import copy
-import inspect
-import linecache
-import sys
-import threading
-import uuid
-import warnings
-
-from operator import itemgetter
-
-from . import _config, setters
-from ._compat import (
- PY2,
- PYPY,
- isclass,
- iteritems,
- metadata_proxy,
- new_class,
- ordered_dict,
- set_closure_cell,
-)
-from .exceptions import (
- DefaultAlreadySetError,
- FrozenInstanceError,
- NotAnAttrsClassError,
- PythonTooOldError,
- UnannotatedAttributeError,
-)
-
-
-if not PY2:
- import typing
-
-
-# This is used at least twice, so cache it here.
-_obj_setattr = object.__setattr__
-_init_converter_pat = "__attr_converter_%s"
-_init_factory_pat = "__attr_factory_{}"
-_tuple_property_pat = (
- " {attr_name} = _attrs_property(_attrs_itemgetter({index}))"
-)
-_classvar_prefixes = (
- "typing.ClassVar",
- "t.ClassVar",
- "ClassVar",
- "typing_extensions.ClassVar",
-)
-# we don't use a double-underscore prefix because that triggers
-# name mangling when trying to create a slot for the field
-# (when slots=True)
-_hash_cache_field = "_attrs_cached_hash"
-
-_empty_metadata_singleton = metadata_proxy({})
-
-# Unique object for unequivocal getattr() defaults.
-_sentinel = object()
-
-
-class _Nothing(object):
- """
- Sentinel class to indicate the lack of a value when ``None`` is ambiguous.
-
- ``_Nothing`` is a singleton. There is only ever one of it.
-
- .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False.
- """
-
- _singleton = None
-
- def __new__(cls):
- if _Nothing._singleton is None:
- _Nothing._singleton = super(_Nothing, cls).__new__(cls)
- return _Nothing._singleton
-
- def __repr__(self):
- return "NOTHING"
-
- def __bool__(self):
- return False
-
- def __len__(self):
- return 0 # __bool__ for Python 2
-
-
-NOTHING = _Nothing()
-"""
-Sentinel to indicate the lack of a value when ``None`` is ambiguous.
-"""
-
-
-class _CacheHashWrapper(int):
- """
- An integer subclass that pickles / copies as None
-
- This is used for non-slots classes with ``cache_hash=True``, to avoid
- serializing a potentially (even likely) invalid hash value. Since ``None``
- is the default value for uncalculated hashes, whenever this is copied,
- the copy's value for the hash should automatically reset.
-
- See GH #613 for more details.
- """
-
- if PY2:
- # For some reason `type(None)` isn't callable in Python 2, but we don't
- # actually need a constructor for None objects, we just need any
- # available function that returns None.
- def __reduce__(self, _none_constructor=getattr, _args=(0, "", None)):
- return _none_constructor, _args
-
- else:
-
- def __reduce__(self, _none_constructor=type(None), _args=()):
- return _none_constructor, _args
-
-
-def attrib(
- default=NOTHING,
- validator=None,
- repr=True,
- cmp=None,
- hash=None,
- init=True,
- metadata=None,
- type=None,
- converter=None,
- factory=None,
- kw_only=False,
- eq=None,
- order=None,
- on_setattr=None,
-):
- """
- Create a new attribute on a class.
-
- .. warning::
-
- Does *not* do anything unless the class is also decorated with
- `attr.s`!
-
- :param default: A value that is used if an ``attrs``-generated ``__init__``
- is used and no value is passed while instantiating or the attribute is
- excluded using ``init=False``.
-
- If the value is an instance of `Factory`, its callable will be
- used to construct a new value (useful for mutable data types like lists
- or dicts).
-
- If a default is not set (or set manually to `attr.NOTHING`), a value
- *must* be supplied when instantiating; otherwise a `TypeError`
- will be raised.
-
- The default can also be set using decorator notation as shown below.
-
- :type default: Any value
-
- :param callable factory: Syntactic sugar for
- ``default=attr.Factory(factory)``.
-
- :param validator: `callable` that is called by ``attrs``-generated
- ``__init__`` methods after the instance has been initialized. They
- receive the initialized instance, the `Attribute`, and the
- passed value.
-
- The return value is *not* inspected so the validator has to throw an
- exception itself.
-
- If a `list` is passed, its items are treated as validators and must
- all pass.
-
- Validators can be globally disabled and re-enabled using
- `get_run_validators`.
-
- The validator can also be set using decorator notation as shown below.
-
- :type validator: `callable` or a `list` of `callable`\\ s.
-
- :param repr: Include this attribute in the generated ``__repr__``
- method. If ``True``, include the attribute; if ``False``, omit it. By
- default, the built-in ``repr()`` function is used. To override how the
- attribute value is formatted, pass a ``callable`` that takes a single
- value and returns a string. Note that the resulting string is used
- as-is, i.e. it will be used directly *instead* of calling ``repr()``
- (the default).
- :type repr: a `bool` or a `callable` to use a custom function.
-
- :param eq: If ``True`` (default), include this attribute in the
- generated ``__eq__`` and ``__ne__`` methods that check two instances
- for equality. To override how the attribute value is compared,
- pass a ``callable`` that takes a single value and returns the value
- to be compared.
- :type eq: a `bool` or a `callable`.
-
- :param order: If ``True`` (default), include this attributes in the
- generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods.
- To override how the attribute value is ordered,
- pass a ``callable`` that takes a single value and returns the value
- to be ordered.
- :type order: a `bool` or a `callable`.
-
- :param cmp: Setting *cmp* is equivalent to setting *eq* and *order* to the
- same value. Must not be mixed with *eq* or *order*.
- :type cmp: a `bool` or a `callable`.
-
- :param Optional[bool] hash: Include this attribute in the generated
- ``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This
- is the correct behavior according the Python spec. Setting this value
- to anything else than ``None`` is *discouraged*.
- :param bool init: Include this attribute in the generated ``__init__``
- method. It is possible to set this to ``False`` and set a default
- value. In that case this attributed is unconditionally initialized
- with the specified default value or factory.
- :param callable converter: `callable` that is called by
- ``attrs``-generated ``__init__`` methods to convert attribute's value
- to the desired format. It is given the passed-in value, and the
- returned value will be used as the new value of the attribute. The
- value is converted before being passed to the validator, if any.
- :param metadata: An arbitrary mapping, to be used by third-party
- components. See `extending_metadata`.
- :param type: The type of the attribute. In Python 3.6 or greater, the
- preferred method to specify the type is using a variable annotation
- (see `PEP 526 `_).
- This argument is provided for backward compatibility.
- Regardless of the approach used, the type will be stored on
- ``Attribute.type``.
-
- Please note that ``attrs`` doesn't do anything with this metadata by
- itself. You can use it as part of your own code or for
- `static type checking `.
- :param kw_only: Make this attribute keyword-only (Python 3+)
- in the generated ``__init__`` (if ``init`` is ``False``, this
- parameter is ignored).
- :param on_setattr: Allows to overwrite the *on_setattr* setting from
- `attr.s`. If left `None`, the *on_setattr* value from `attr.s` is used.
- Set to `attr.setters.NO_OP` to run **no** `setattr` hooks for this
- attribute -- regardless of the setting in `attr.s`.
- :type on_setattr: `callable`, or a list of callables, or `None`, or
- `attr.setters.NO_OP`
-
- .. versionadded:: 15.2.0 *convert*
- .. versionadded:: 16.3.0 *metadata*
- .. versionchanged:: 17.1.0 *validator* can be a ``list`` now.
- .. versionchanged:: 17.1.0
- *hash* is ``None`` and therefore mirrors *eq* by default.
- .. versionadded:: 17.3.0 *type*
- .. deprecated:: 17.4.0 *convert*
- .. versionadded:: 17.4.0 *converter* as a replacement for the deprecated
- *convert* to achieve consistency with other noun-based arguments.
- .. versionadded:: 18.1.0
- ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``.
- .. versionadded:: 18.2.0 *kw_only*
- .. versionchanged:: 19.2.0 *convert* keyword argument removed.
- .. versionchanged:: 19.2.0 *repr* also accepts a custom callable.
- .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.
- .. versionadded:: 19.2.0 *eq* and *order*
- .. versionadded:: 20.1.0 *on_setattr*
- .. versionchanged:: 20.3.0 *kw_only* backported to Python 2
- .. versionchanged:: 21.1.0
- *eq*, *order*, and *cmp* also accept a custom callable
- .. versionchanged:: 21.1.0 *cmp* undeprecated
- """
- eq, eq_key, order, order_key = _determine_attrib_eq_order(
- cmp, eq, order, True
- )
-
- if hash is not None and hash is not True and hash is not False:
- raise TypeError(
- "Invalid value for hash. Must be True, False, or None."
- )
-
- if factory is not None:
- if default is not NOTHING:
- raise ValueError(
- "The `default` and `factory` arguments are mutually "
- "exclusive."
- )
- if not callable(factory):
- raise ValueError("The `factory` argument must be a callable.")
- default = Factory(factory)
-
- if metadata is None:
- metadata = {}
-
- # Apply syntactic sugar by auto-wrapping.
- if isinstance(on_setattr, (list, tuple)):
- on_setattr = setters.pipe(*on_setattr)
-
- if validator and isinstance(validator, (list, tuple)):
- validator = and_(*validator)
-
- if converter and isinstance(converter, (list, tuple)):
- converter = pipe(*converter)
-
- return _CountingAttr(
- default=default,
- validator=validator,
- repr=repr,
- cmp=None,
- hash=hash,
- init=init,
- converter=converter,
- metadata=metadata,
- type=type,
- kw_only=kw_only,
- eq=eq,
- eq_key=eq_key,
- order=order,
- order_key=order_key,
- on_setattr=on_setattr,
- )
-
-
-def _compile_and_eval(script, globs, locs=None, filename=""):
- """
- "Exec" the script with the given global (globs) and local (locs) variables.
- """
- bytecode = compile(script, filename, "exec")
- eval(bytecode, globs, locs)
-
-
-def _make_method(name, script, filename, globs=None):
- """
- Create the method with the script given and return the method object.
- """
- locs = {}
- if globs is None:
- globs = {}
-
- _compile_and_eval(script, globs, locs, filename)
-
- # In order of debuggers like PDB being able to step through the code,
- # we add a fake linecache entry.
- linecache.cache[filename] = (
- len(script),
- None,
- script.splitlines(True),
- filename,
- )
-
- return locs[name]
-
-
-def _make_attr_tuple_class(cls_name, attr_names):
- """
- Create a tuple subclass to hold `Attribute`s for an `attrs` class.
-
- The subclass is a bare tuple with properties for names.
-
- class MyClassAttributes(tuple):
- __slots__ = ()
- x = property(itemgetter(0))
- """
- attr_class_name = "{}Attributes".format(cls_name)
- attr_class_template = [
- "class {}(tuple):".format(attr_class_name),
- " __slots__ = ()",
- ]
- if attr_names:
- for i, attr_name in enumerate(attr_names):
- attr_class_template.append(
- _tuple_property_pat.format(index=i, attr_name=attr_name)
- )
- else:
- attr_class_template.append(" pass")
- globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property}
- _compile_and_eval("\n".join(attr_class_template), globs)
- return globs[attr_class_name]
-
-
-# Tuple class for extracted attributes from a class definition.
-# `base_attrs` is a subset of `attrs`.
-_Attributes = _make_attr_tuple_class(
- "_Attributes",
- [
- # all attributes to build dunder methods for
- "attrs",
- # attributes that have been inherited
- "base_attrs",
- # map inherited attributes to their originating classes
- "base_attrs_map",
- ],
-)
-
-
-def _is_class_var(annot):
- """
- Check whether *annot* is a typing.ClassVar.
-
- The string comparison hack is used to avoid evaluating all string
- annotations which would put attrs-based classes at a performance
- disadvantage compared to plain old classes.
- """
- annot = str(annot)
-
- # Annotation can be quoted.
- if annot.startswith(("'", '"')) and annot.endswith(("'", '"')):
- annot = annot[1:-1]
-
- return annot.startswith(_classvar_prefixes)
-
-
-def _has_own_attribute(cls, attrib_name):
- """
- Check whether *cls* defines *attrib_name* (and doesn't just inherit it).
-
- Requires Python 3.
- """
- attr = getattr(cls, attrib_name, _sentinel)
- if attr is _sentinel:
- return False
-
- for base_cls in cls.__mro__[1:]:
- a = getattr(base_cls, attrib_name, None)
- if attr is a:
- return False
-
- return True
-
-
-def _get_annotations(cls):
- """
- Get annotations for *cls*.
- """
- if _has_own_attribute(cls, "__annotations__"):
- return cls.__annotations__
-
- return {}
-
-
-def _counter_getter(e):
- """
- Key function for sorting to avoid re-creating a lambda for every class.
- """
- return e[1].counter
-
-
-def _collect_base_attrs(cls, taken_attr_names):
- """
- Collect attr.ibs from base classes of *cls*, except *taken_attr_names*.
- """
- base_attrs = []
- base_attr_map = {} # A dictionary of base attrs to their classes.
-
- # Traverse the MRO and collect attributes.
- for base_cls in reversed(cls.__mro__[1:-1]):
- for a in getattr(base_cls, "__attrs_attrs__", []):
- if a.inherited or a.name in taken_attr_names:
- continue
-
- a = a.evolve(inherited=True)
- base_attrs.append(a)
- base_attr_map[a.name] = base_cls
-
- # For each name, only keep the freshest definition i.e. the furthest at the
- # back. base_attr_map is fine because it gets overwritten with every new
- # instance.
- filtered = []
- seen = set()
- for a in reversed(base_attrs):
- if a.name in seen:
- continue
- filtered.insert(0, a)
- seen.add(a.name)
-
- return filtered, base_attr_map
-
-
-def _collect_base_attrs_broken(cls, taken_attr_names):
- """
- Collect attr.ibs from base classes of *cls*, except *taken_attr_names*.
-
- N.B. *taken_attr_names* will be mutated.
-
- Adhere to the old incorrect behavior.
-
- Notably it collects from the front and considers inherited attributes which
- leads to the buggy behavior reported in #428.
- """
- base_attrs = []
- base_attr_map = {} # A dictionary of base attrs to their classes.
-
- # Traverse the MRO and collect attributes.
- for base_cls in cls.__mro__[1:-1]:
- for a in getattr(base_cls, "__attrs_attrs__", []):
- if a.name in taken_attr_names:
- continue
-
- a = a.evolve(inherited=True)
- taken_attr_names.add(a.name)
- base_attrs.append(a)
- base_attr_map[a.name] = base_cls
-
- return base_attrs, base_attr_map
-
-
-def _transform_attrs(
- cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer
-):
- """
- Transform all `_CountingAttr`s on a class into `Attribute`s.
-
- If *these* is passed, use that and don't look for them on the class.
-
- *collect_by_mro* is True, collect them in the correct MRO order, otherwise
- use the old -- incorrect -- order. See #428.
-
- Return an `_Attributes`.
- """
- cd = cls.__dict__
- anns = _get_annotations(cls)
-
- if these is not None:
- ca_list = [(name, ca) for name, ca in iteritems(these)]
-
- if not isinstance(these, ordered_dict):
- ca_list.sort(key=_counter_getter)
- elif auto_attribs is True:
- ca_names = {
- name
- for name, attr in cd.items()
- if isinstance(attr, _CountingAttr)
- }
- ca_list = []
- annot_names = set()
- for attr_name, type in anns.items():
- if _is_class_var(type):
- continue
- annot_names.add(attr_name)
- a = cd.get(attr_name, NOTHING)
-
- if not isinstance(a, _CountingAttr):
- if a is NOTHING:
- a = attrib()
- else:
- a = attrib(default=a)
- ca_list.append((attr_name, a))
-
- unannotated = ca_names - annot_names
- if len(unannotated) > 0:
- raise UnannotatedAttributeError(
- "The following `attr.ib`s lack a type annotation: "
- + ", ".join(
- sorted(unannotated, key=lambda n: cd.get(n).counter)
- )
- + "."
- )
- else:
- ca_list = sorted(
- (
- (name, attr)
- for name, attr in cd.items()
- if isinstance(attr, _CountingAttr)
- ),
- key=lambda e: e[1].counter,
- )
-
- own_attrs = [
- Attribute.from_counting_attr(
- name=attr_name, ca=ca, type=anns.get(attr_name)
- )
- for attr_name, ca in ca_list
- ]
-
- if collect_by_mro:
- base_attrs, base_attr_map = _collect_base_attrs(
- cls, {a.name for a in own_attrs}
- )
- else:
- base_attrs, base_attr_map = _collect_base_attrs_broken(
- cls, {a.name for a in own_attrs}
- )
-
- attr_names = [a.name for a in base_attrs + own_attrs]
-
- AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
-
- if kw_only:
- own_attrs = [a.evolve(kw_only=True) for a in own_attrs]
- base_attrs = [a.evolve(kw_only=True) for a in base_attrs]
-
- attrs = AttrsClass(base_attrs + own_attrs)
-
- # Mandatory vs non-mandatory attr order only matters when they are part of
- # the __init__ signature and when they aren't kw_only (which are moved to
- # the end and can be mandatory or non-mandatory in any order, as they will
- # be specified as keyword args anyway). Check the order of those attrs:
- had_default = False
- for a in (a for a in attrs if a.init is not False and a.kw_only is False):
- if had_default is True and a.default is NOTHING:
- raise ValueError(
- "No mandatory attributes allowed after an attribute with a "
- "default value or factory. Attribute in question: %r" % (a,)
- )
-
- if had_default is False and a.default is not NOTHING:
- had_default = True
-
- if field_transformer is not None:
- attrs = field_transformer(cls, attrs)
- return _Attributes((attrs, base_attrs, base_attr_map))
-
-
-if PYPY:
-
- def _frozen_setattrs(self, name, value):
- """
- Attached to frozen classes as __setattr__.
- """
- if isinstance(self, BaseException) and name in (
- "__cause__",
- "__context__",
- ):
- BaseException.__setattr__(self, name, value)
- return
-
- raise FrozenInstanceError()
-
-
-else:
-
- def _frozen_setattrs(self, name, value):
- """
- Attached to frozen classes as __setattr__.
- """
- raise FrozenInstanceError()
-
-
-def _frozen_delattrs(self, name):
- """
- Attached to frozen classes as __delattr__.
- """
- raise FrozenInstanceError()
-
-
-class _ClassBuilder(object):
- """
- Iteratively build *one* class.
- """
-
- __slots__ = (
- "_attr_names",
- "_attrs",
- "_base_attr_map",
- "_base_names",
- "_cache_hash",
- "_cls",
- "_cls_dict",
- "_delete_attribs",
- "_frozen",
- "_has_pre_init",
- "_has_post_init",
- "_is_exc",
- "_on_setattr",
- "_slots",
- "_weakref_slot",
- "_has_own_setattr",
- "_has_custom_setattr",
- )
-
- def __init__(
- self,
- cls,
- these,
- slots,
- frozen,
- weakref_slot,
- getstate_setstate,
- auto_attribs,
- kw_only,
- cache_hash,
- is_exc,
- collect_by_mro,
- on_setattr,
- has_custom_setattr,
- field_transformer,
- ):
- attrs, base_attrs, base_map = _transform_attrs(
- cls,
- these,
- auto_attribs,
- kw_only,
- collect_by_mro,
- field_transformer,
- )
-
- self._cls = cls
- self._cls_dict = dict(cls.__dict__) if slots else {}
- self._attrs = attrs
- self._base_names = set(a.name for a in base_attrs)
- self._base_attr_map = base_map
- self._attr_names = tuple(a.name for a in attrs)
- self._slots = slots
- self._frozen = frozen
- self._weakref_slot = weakref_slot
- self._cache_hash = cache_hash
- self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False))
- self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))
- self._delete_attribs = not bool(these)
- self._is_exc = is_exc
- self._on_setattr = on_setattr
-
- self._has_custom_setattr = has_custom_setattr
- self._has_own_setattr = False
-
- self._cls_dict["__attrs_attrs__"] = self._attrs
-
- if frozen:
- self._cls_dict["__setattr__"] = _frozen_setattrs
- self._cls_dict["__delattr__"] = _frozen_delattrs
-
- self._has_own_setattr = True
-
- if getstate_setstate:
- (
- self._cls_dict["__getstate__"],
- self._cls_dict["__setstate__"],
- ) = self._make_getstate_setstate()
-
- def __repr__(self):
- return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__)
-
- def build_class(self):
- """
- Finalize class based on the accumulated configuration.
-
- Builder cannot be used after calling this method.
- """
- if self._slots is True:
- return self._create_slots_class()
- else:
- return self._patch_original_class()
-
- def _patch_original_class(self):
- """
- Apply accumulated methods and return the class.
- """
- cls = self._cls
- base_names = self._base_names
-
- # Clean class of attribute definitions (`attr.ib()`s).
- if self._delete_attribs:
- for name in self._attr_names:
- if (
- name not in base_names
- and getattr(cls, name, _sentinel) is not _sentinel
- ):
- try:
- delattr(cls, name)
- except AttributeError:
- # This can happen if a base class defines a class
- # variable and we want to set an attribute with the
- # same name by using only a type annotation.
- pass
-
- # Attach our dunder methods.
- for name, value in self._cls_dict.items():
- setattr(cls, name, value)
-
- # If we've inherited an attrs __setattr__ and don't write our own,
- # reset it to object's.
- if not self._has_own_setattr and getattr(
- cls, "__attrs_own_setattr__", False
- ):
- cls.__attrs_own_setattr__ = False
-
- if not self._has_custom_setattr:
- cls.__setattr__ = object.__setattr__
-
- return cls
-
- def _create_slots_class(self):
- """
- Build and return a new class with a `__slots__` attribute.
- """
- cd = {
- k: v
- for k, v in iteritems(self._cls_dict)
- if k not in tuple(self._attr_names) + ("__dict__", "__weakref__")
- }
-
- # If our class doesn't have its own implementation of __setattr__
- # (either from the user or by us), check the bases, if one of them has
- # an attrs-made __setattr__, that needs to be reset. We don't walk the
- # MRO because we only care about our immediate base classes.
- # XXX: This can be confused by subclassing a slotted attrs class with
- # XXX: a non-attrs class and subclass the resulting class with an attrs
- # XXX: class. See `test_slotted_confused` for details. For now that's
- # XXX: OK with us.
- if not self._has_own_setattr:
- cd["__attrs_own_setattr__"] = False
-
- if not self._has_custom_setattr:
- for base_cls in self._cls.__bases__:
- if base_cls.__dict__.get("__attrs_own_setattr__", False):
- cd["__setattr__"] = object.__setattr__
- break
-
- # Traverse the MRO to collect existing slots
- # and check for an existing __weakref__.
- existing_slots = dict()
- weakref_inherited = False
- for base_cls in self._cls.__mro__[1:-1]:
- if base_cls.__dict__.get("__weakref__", None) is not None:
- weakref_inherited = True
- existing_slots.update(
- {
- name: getattr(base_cls, name)
- for name in getattr(base_cls, "__slots__", [])
- }
- )
-
- base_names = set(self._base_names)
-
- names = self._attr_names
- if (
- self._weakref_slot
- and "__weakref__" not in getattr(self._cls, "__slots__", ())
- and "__weakref__" not in names
- and not weakref_inherited
- ):
- names += ("__weakref__",)
-
- # We only add the names of attributes that aren't inherited.
- # Setting __slots__ to inherited attributes wastes memory.
- slot_names = [name for name in names if name not in base_names]
- # There are slots for attributes from current class
- # that are defined in parent classes.
- # As their descriptors may be overriden by a child class,
- # we collect them here and update the class dict
- reused_slots = {
- slot: slot_descriptor
- for slot, slot_descriptor in iteritems(existing_slots)
- if slot in slot_names
- }
- slot_names = [name for name in slot_names if name not in reused_slots]
- cd.update(reused_slots)
- if self._cache_hash:
- slot_names.append(_hash_cache_field)
- cd["__slots__"] = tuple(slot_names)
-
- qualname = getattr(self._cls, "__qualname__", None)
- if qualname is not None:
- cd["__qualname__"] = qualname
-
- # Create new class based on old class and our methods.
- cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd)
-
- # The following is a fix for
- # https://github.com/python-attrs/attrs/issues/102. On Python 3,
- # if a method mentions `__class__` or uses the no-arg super(), the
- # compiler will bake a reference to the class in the method itself
- # as `method.__closure__`. Since we replace the class with a
- # clone, we rewrite these references so it keeps working.
- for item in cls.__dict__.values():
- if isinstance(item, (classmethod, staticmethod)):
- # Class- and staticmethods hide their functions inside.
- # These might need to be rewritten as well.
- closure_cells = getattr(item.__func__, "__closure__", None)
- elif isinstance(item, property):
- # Workaround for property `super()` shortcut (PY3-only).
- # There is no universal way for other descriptors.
- closure_cells = getattr(item.fget, "__closure__", None)
- else:
- closure_cells = getattr(item, "__closure__", None)
-
- if not closure_cells: # Catch None or the empty list.
- continue
- for cell in closure_cells:
- try:
- match = cell.cell_contents is self._cls
- except ValueError: # ValueError: Cell is empty
- pass
- else:
- if match:
- set_closure_cell(cell, cls)
-
- return cls
-
- def add_repr(self, ns):
- self._cls_dict["__repr__"] = self._add_method_dunders(
- _make_repr(self._attrs, ns=ns)
- )
- return self
-
- def add_str(self):
- repr = self._cls_dict.get("__repr__")
- if repr is None:
- raise ValueError(
- "__str__ can only be generated if a __repr__ exists."
- )
-
- def __str__(self):
- return self.__repr__()
-
- self._cls_dict["__str__"] = self._add_method_dunders(__str__)
- return self
-
- def _make_getstate_setstate(self):
- """
- Create custom __setstate__ and __getstate__ methods.
- """
- # __weakref__ is not writable.
- state_attr_names = tuple(
- an for an in self._attr_names if an != "__weakref__"
- )
-
- def slots_getstate(self):
- """
- Automatically created by attrs.
- """
- return tuple(getattr(self, name) for name in state_attr_names)
-
- hash_caching_enabled = self._cache_hash
-
- def slots_setstate(self, state):
- """
- Automatically created by attrs.
- """
- __bound_setattr = _obj_setattr.__get__(self, Attribute)
- for name, value in zip(state_attr_names, state):
- __bound_setattr(name, value)
-
- # The hash code cache is not included when the object is
- # serialized, but it still needs to be initialized to None to
- # indicate that the first call to __hash__ should be a cache
- # miss.
- if hash_caching_enabled:
- __bound_setattr(_hash_cache_field, None)
-
- return slots_getstate, slots_setstate
-
- def make_unhashable(self):
- self._cls_dict["__hash__"] = None
- return self
-
- def add_hash(self):
- self._cls_dict["__hash__"] = self._add_method_dunders(
- _make_hash(
- self._cls,
- self._attrs,
- frozen=self._frozen,
- cache_hash=self._cache_hash,
- )
- )
-
- return self
-
- def add_init(self):
- self._cls_dict["__init__"] = self._add_method_dunders(
- _make_init(
- self._cls,
- self._attrs,
- self._has_pre_init,
- self._has_post_init,
- self._frozen,
- self._slots,
- self._cache_hash,
- self._base_attr_map,
- self._is_exc,
- self._on_setattr is not None
- and self._on_setattr is not setters.NO_OP,
- attrs_init=False,
- )
- )
-
- return self
-
- def add_attrs_init(self):
- self._cls_dict["__attrs_init__"] = self._add_method_dunders(
- _make_init(
- self._cls,
- self._attrs,
- self._has_pre_init,
- self._has_post_init,
- self._frozen,
- self._slots,
- self._cache_hash,
- self._base_attr_map,
- self._is_exc,
- self._on_setattr is not None
- and self._on_setattr is not setters.NO_OP,
- attrs_init=True,
- )
- )
-
- return self
-
- def add_eq(self):
- cd = self._cls_dict
-
- cd["__eq__"] = self._add_method_dunders(
- _make_eq(self._cls, self._attrs)
- )
- cd["__ne__"] = self._add_method_dunders(_make_ne())
-
- return self
-
- def add_order(self):
- cd = self._cls_dict
-
- cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = (
- self._add_method_dunders(meth)
- for meth in _make_order(self._cls, self._attrs)
- )
-
- return self
-
- def add_setattr(self):
- if self._frozen:
- return self
-
- sa_attrs = {}
- for a in self._attrs:
- on_setattr = a.on_setattr or self._on_setattr
- if on_setattr and on_setattr is not setters.NO_OP:
- sa_attrs[a.name] = a, on_setattr
-
- if not sa_attrs:
- return self
-
- if self._has_custom_setattr:
- # We need to write a __setattr__ but there already is one!
- raise ValueError(
- "Can't combine custom __setattr__ with on_setattr hooks."
- )
-
- # docstring comes from _add_method_dunders
- def __setattr__(self, name, val):
- try:
- a, hook = sa_attrs[name]
- except KeyError:
- nval = val
- else:
- nval = hook(self, a, val)
-
- _obj_setattr(self, name, nval)
-
- self._cls_dict["__attrs_own_setattr__"] = True
- self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__)
- self._has_own_setattr = True
-
- return self
-
- def _add_method_dunders(self, method):
- """
- Add __module__ and __qualname__ to a *method* if possible.
- """
- try:
- method.__module__ = self._cls.__module__
- except AttributeError:
- pass
-
- try:
- method.__qualname__ = ".".join(
- (self._cls.__qualname__, method.__name__)
- )
- except AttributeError:
- pass
-
- try:
- method.__doc__ = "Method generated by attrs for class %s." % (
- self._cls.__qualname__,
- )
- except AttributeError:
- pass
-
- return method
-
-
-_CMP_DEPRECATION = (
- "The usage of `cmp` is deprecated and will be removed on or after "
- "2021-06-01. Please use `eq` and `order` instead."
-)
-
-
-def _determine_attrs_eq_order(cmp, eq, order, default_eq):
- """
- Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
- values of eq and order. If *eq* is None, set it to *default_eq*.
- """
- if cmp is not None and any((eq is not None, order is not None)):
- raise ValueError("Don't mix `cmp` with `eq' and `order`.")
-
- # cmp takes precedence due to bw-compatibility.
- if cmp is not None:
- return cmp, cmp
-
- # If left None, equality is set to the specified default and ordering
- # mirrors equality.
- if eq is None:
- eq = default_eq
-
- if order is None:
- order = eq
-
- if eq is False and order is True:
- raise ValueError("`order` can only be True if `eq` is True too.")
-
- return eq, order
-
-
-def _determine_attrib_eq_order(cmp, eq, order, default_eq):
- """
- Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
- values of eq and order. If *eq* is None, set it to *default_eq*.
- """
- if cmp is not None and any((eq is not None, order is not None)):
- raise ValueError("Don't mix `cmp` with `eq' and `order`.")
-
- def decide_callable_or_boolean(value):
- """
- Decide whether a key function is used.
- """
- if callable(value):
- value, key = True, value
- else:
- key = None
- return value, key
-
- # cmp takes precedence due to bw-compatibility.
- if cmp is not None:
- cmp, cmp_key = decide_callable_or_boolean(cmp)
- return cmp, cmp_key, cmp, cmp_key
-
- # If left None, equality is set to the specified default and ordering
- # mirrors equality.
- if eq is None:
- eq, eq_key = default_eq, None
- else:
- eq, eq_key = decide_callable_or_boolean(eq)
-
- if order is None:
- order, order_key = eq, eq_key
- else:
- order, order_key = decide_callable_or_boolean(order)
-
- if eq is False and order is True:
- raise ValueError("`order` can only be True if `eq` is True too.")
-
- return eq, eq_key, order, order_key
-
-
-def _determine_whether_to_implement(
- cls, flag, auto_detect, dunders, default=True
-):
- """
- Check whether we should implement a set of methods for *cls*.
-
- *flag* is the argument passed into @attr.s like 'init', *auto_detect* the
- same as passed into @attr.s and *dunders* is a tuple of attribute names
- whose presence signal that the user has implemented it themselves.
-
- Return *default* if no reason for either for or against is found.
-
- auto_detect must be False on Python 2.
- """
- if flag is True or flag is False:
- return flag
-
- if flag is None and auto_detect is False:
- return default
-
- # Logically, flag is None and auto_detect is True here.
- for dunder in dunders:
- if _has_own_attribute(cls, dunder):
- return False
-
- return default
-
-
-def attrs(
- maybe_cls=None,
- these=None,
- repr_ns=None,
- repr=None,
- cmp=None,
- hash=None,
- init=None,
- slots=False,
- frozen=False,
- weakref_slot=True,
- str=False,
- auto_attribs=False,
- kw_only=False,
- cache_hash=False,
- auto_exc=False,
- eq=None,
- order=None,
- auto_detect=False,
- collect_by_mro=False,
- getstate_setstate=None,
- on_setattr=None,
- field_transformer=None,
-):
- r"""
- A class decorator that adds `dunder
- `_\ -methods according to the
- specified attributes using `attr.ib` or the *these* argument.
-
- :param these: A dictionary of name to `attr.ib` mappings. This is
- useful to avoid the definition of your attributes within the class body
- because you can't (e.g. if you want to add ``__repr__`` methods to
- Django models) or don't want to.
-
- If *these* is not ``None``, ``attrs`` will *not* search the class body
- for attributes and will *not* remove any attributes from it.
-
- If *these* is an ordered dict (`dict` on Python 3.6+,
- `collections.OrderedDict` otherwise), the order is deduced from
- the order of the attributes inside *these*. Otherwise the order
- of the definition of the attributes is used.
-
- :type these: `dict` of `str` to `attr.ib`
-
- :param str repr_ns: When using nested classes, there's no way in Python 2
- to automatically detect that. Therefore it's possible to set the
- namespace explicitly for a more meaningful ``repr`` output.
- :param bool auto_detect: Instead of setting the *init*, *repr*, *eq*,
- *order*, and *hash* arguments explicitly, assume they are set to
- ``True`` **unless any** of the involved methods for one of the
- arguments is implemented in the *current* class (i.e. it is *not*
- inherited from some base class).
-
- So for example by implementing ``__eq__`` on a class yourself,
- ``attrs`` will deduce ``eq=False`` and will create *neither*
- ``__eq__`` *nor* ``__ne__`` (but Python classes come with a sensible
- ``__ne__`` by default, so it *should* be enough to only implement
- ``__eq__`` in most cases).
-
- .. warning::
-
- If you prevent ``attrs`` from creating the ordering methods for you
- (``order=False``, e.g. by implementing ``__le__``), it becomes
- *your* responsibility to make sure its ordering is sound. The best
- way is to use the `functools.total_ordering` decorator.
-
-
- Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*,
- *cmp*, or *hash* overrides whatever *auto_detect* would determine.
-
- *auto_detect* requires Python 3. Setting it ``True`` on Python 2 raises
- a `PythonTooOldError`.
-
- :param bool repr: Create a ``__repr__`` method with a human readable
- representation of ``attrs`` attributes..
- :param bool str: Create a ``__str__`` method that is identical to
- ``__repr__``. This is usually not necessary except for
- `Exception`\ s.
- :param Optional[bool] eq: If ``True`` or ``None`` (default), add ``__eq__``
- and ``__ne__`` methods that check two instances for equality.
-
- They compare the instances as if they were tuples of their ``attrs``
- attributes if and only if the types of both classes are *identical*!
- :param Optional[bool] order: If ``True``, add ``__lt__``, ``__le__``,
- ``__gt__``, and ``__ge__`` methods that behave like *eq* above and
- allow instances to be ordered. If ``None`` (default) mirror value of
- *eq*.
- :param Optional[bool] cmp: Setting *cmp* is equivalent to setting *eq*
- and *order* to the same value. Must not be mixed with *eq* or *order*.
- :param Optional[bool] hash: If ``None`` (default), the ``__hash__`` method
- is generated according how *eq* and *frozen* are set.
-
- 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you.
- 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set to
- None, marking it unhashable (which it is).
- 3. If *eq* is False, ``__hash__`` will be left untouched meaning the
- ``__hash__`` method of the base class will be used (if base class is
- ``object``, this means it will fall back to id-based hashing.).
-
- Although not recommended, you can decide for yourself and force
- ``attrs`` to create one (e.g. if the class is immutable even though you
- didn't freeze it programmatically) by passing ``True`` or not. Both of
- these cases are rather special and should be used carefully.
-
- See our documentation on `hashing`, Python's documentation on
- `object.__hash__`, and the `GitHub issue that led to the default \
- behavior `_ for more
- details.
- :param bool init: Create a ``__init__`` method that initializes the
- ``attrs`` attributes. Leading underscores are stripped for the argument
- name. If a ``__attrs_pre_init__`` method exists on the class, it will
- be called before the class is initialized. If a ``__attrs_post_init__``
- method exists on the class, it will be called after the class is fully
- initialized.
-
- If ``init`` is ``False``, an ``__attrs_init__`` method will be
- injected instead. This allows you to define a custom ``__init__``
- method that can do pre-init work such as ``super().__init__()``,
- and then call ``__attrs_init__()`` and ``__attrs_post_init__()``.
- :param bool slots: Create a `slotted class ` that's more
- memory-efficient. Slotted classes are generally superior to the default
- dict classes, but have some gotchas you should know about, so we
- encourage you to read the `glossary entry `.
- :param bool frozen: Make instances immutable after initialization. If
- someone attempts to modify a frozen instance,
- `attr.exceptions.FrozenInstanceError` is raised.
-
- .. note::
-
- 1. This is achieved by installing a custom ``__setattr__`` method
- on your class, so you can't implement your own.
-
- 2. True immutability is impossible in Python.
-
- 3. This *does* have a minor a runtime performance `impact
- ` when initializing new instances. In other words:
- ``__init__`` is slightly slower with ``frozen=True``.
-
- 4. If a class is frozen, you cannot modify ``self`` in
- ``__attrs_post_init__`` or a self-written ``__init__``. You can
- circumvent that limitation by using
- ``object.__setattr__(self, "attribute_name", value)``.
-
- 5. Subclasses of a frozen class are frozen too.
-
- :param bool weakref_slot: Make instances weak-referenceable. This has no
- effect unless ``slots`` is also enabled.
- :param bool auto_attribs: If ``True``, collect `PEP 526`_-annotated
- attributes (Python 3.6 and later only) from the class body.
-
- In this case, you **must** annotate every field. If ``attrs``
- encounters a field that is set to an `attr.ib` but lacks a type
- annotation, an `attr.exceptions.UnannotatedAttributeError` is
- raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't
- want to set a type.
-
- If you assign a value to those attributes (e.g. ``x: int = 42``), that
- value becomes the default value like if it were passed using
- ``attr.ib(default=42)``. Passing an instance of `Factory` also
- works as expected in most cases (see warning below).
-
- Attributes annotated as `typing.ClassVar`, and attributes that are
- neither annotated nor set to an `attr.ib` are **ignored**.
-
- .. warning::
- For features that use the attribute name to create decorators (e.g.
- `validators `), you still *must* assign `attr.ib` to
- them. Otherwise Python will either not find the name or try to use
- the default value to call e.g. ``validator`` on it.
-
- These errors can be quite confusing and probably the most common bug
- report on our bug tracker.
-
- .. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/
- :param bool kw_only: Make all attributes keyword-only (Python 3+)
- in the generated ``__init__`` (if ``init`` is ``False``, this
- parameter is ignored).
- :param bool cache_hash: Ensure that the object's hash code is computed
- only once and stored on the object. If this is set to ``True``,
- hashing must be either explicitly or implicitly enabled for this
- class. If the hash code is cached, avoid any reassignments of
- fields involved in hash code computation or mutations of the objects
- those fields point to after object creation. If such changes occur,
- the behavior of the object's hash code is undefined.
- :param bool auto_exc: If the class subclasses `BaseException`
- (which implicitly includes any subclass of any exception), the
- following happens to behave like a well-behaved Python exceptions
- class:
-
- - the values for *eq*, *order*, and *hash* are ignored and the
- instances compare and hash by the instance's ids (N.B. ``attrs`` will
- *not* remove existing implementations of ``__hash__`` or the equality
- methods. It just won't add own ones.),
- - all attributes that are either passed into ``__init__`` or have a
- default value are additionally available as a tuple in the ``args``
- attribute,
- - the value of *str* is ignored leaving ``__str__`` to base classes.
- :param bool collect_by_mro: Setting this to `True` fixes the way ``attrs``
- collects attributes from base classes. The default behavior is
- incorrect in certain cases of multiple inheritance. It should be on by
- default but is kept off for backward-compatability.
-
- See issue `#428 `_ for
- more details.
-
- :param Optional[bool] getstate_setstate:
- .. note::
- This is usually only interesting for slotted classes and you should
- probably just set *auto_detect* to `True`.
-
- If `True`, ``__getstate__`` and
- ``__setstate__`` are generated and attached to the class. This is
- necessary for slotted classes to be pickleable. If left `None`, it's
- `True` by default for slotted classes and ``False`` for dict classes.
-
- If *auto_detect* is `True`, and *getstate_setstate* is left `None`,
- and **either** ``__getstate__`` or ``__setstate__`` is detected directly
- on the class (i.e. not inherited), it is set to `False` (this is usually
- what you want).
-
- :param on_setattr: A callable that is run whenever the user attempts to set
- an attribute (either by assignment like ``i.x = 42`` or by using
- `setattr` like ``setattr(i, "x", 42)``). It receives the same arguments
- as validators: the instance, the attribute that is being modified, and
- the new value.
-
- If no exception is raised, the attribute is set to the return value of
- the callable.
-
- If a list of callables is passed, they're automatically wrapped in an
- `attr.setters.pipe`.
-
- :param Optional[callable] field_transformer:
- A function that is called with the original class object and all
- fields right before ``attrs`` finalizes the class. You can use
- this, e.g., to automatically add converters or validators to
- fields based on their types. See `transform-fields` for more details.
-
- .. versionadded:: 16.0.0 *slots*
- .. versionadded:: 16.1.0 *frozen*
- .. versionadded:: 16.3.0 *str*
- .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``.
- .. versionchanged:: 17.1.0
- *hash* supports ``None`` as value which is also the default now.
- .. versionadded:: 17.3.0 *auto_attribs*
- .. versionchanged:: 18.1.0
- If *these* is passed, no attributes are deleted from the class body.
- .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained.
- .. versionadded:: 18.2.0 *weakref_slot*
- .. deprecated:: 18.2.0
- ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a
- `DeprecationWarning` if the classes compared are subclasses of
- each other. ``__eq`` and ``__ne__`` never tried to compared subclasses
- to each other.
- .. versionchanged:: 19.2.0
- ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider
- subclasses comparable anymore.
- .. versionadded:: 18.2.0 *kw_only*
- .. versionadded:: 18.2.0 *cache_hash*
- .. versionadded:: 19.1.0 *auto_exc*
- .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.
- .. versionadded:: 19.2.0 *eq* and *order*
- .. versionadded:: 20.1.0 *auto_detect*
- .. versionadded:: 20.1.0 *collect_by_mro*
- .. versionadded:: 20.1.0 *getstate_setstate*
- .. versionadded:: 20.1.0 *on_setattr*
- .. versionadded:: 20.3.0 *field_transformer*
- .. versionchanged:: 21.1.0
- ``init=False`` injects ``__attrs_init__``
- .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__``
- .. versionchanged:: 21.1.0 *cmp* undeprecated
- """
- if auto_detect and PY2:
- raise PythonTooOldError(
- "auto_detect only works on Python 3 and later."
- )
-
- eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None)
- hash_ = hash # work around the lack of nonlocal
-
- if isinstance(on_setattr, (list, tuple)):
- on_setattr = setters.pipe(*on_setattr)
-
- def wrap(cls):
-
- if getattr(cls, "__class__", None) is None:
- raise TypeError("attrs only works with new-style classes.")
-
- is_frozen = frozen or _has_frozen_base_class(cls)
- is_exc = auto_exc is True and issubclass(cls, BaseException)
- has_own_setattr = auto_detect and _has_own_attribute(
- cls, "__setattr__"
- )
-
- if has_own_setattr and is_frozen:
- raise ValueError("Can't freeze a class with a custom __setattr__.")
-
- builder = _ClassBuilder(
- cls,
- these,
- slots,
- is_frozen,
- weakref_slot,
- _determine_whether_to_implement(
- cls,
- getstate_setstate,
- auto_detect,
- ("__getstate__", "__setstate__"),
- default=slots,
- ),
- auto_attribs,
- kw_only,
- cache_hash,
- is_exc,
- collect_by_mro,
- on_setattr,
- has_own_setattr,
- field_transformer,
- )
- if _determine_whether_to_implement(
- cls, repr, auto_detect, ("__repr__",)
- ):
- builder.add_repr(repr_ns)
- if str is True:
- builder.add_str()
-
- eq = _determine_whether_to_implement(
- cls, eq_, auto_detect, ("__eq__", "__ne__")
- )
- if not is_exc and eq is True:
- builder.add_eq()
- if not is_exc and _determine_whether_to_implement(
- cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__")
- ):
- builder.add_order()
-
- builder.add_setattr()
-
- if (
- hash_ is None
- and auto_detect is True
- and _has_own_attribute(cls, "__hash__")
- ):
- hash = False
- else:
- hash = hash_
- if hash is not True and hash is not False and hash is not None:
- # Can't use `hash in` because 1 == True for example.
- raise TypeError(
- "Invalid value for hash. Must be True, False, or None."
- )
- elif hash is False or (hash is None and eq is False) or is_exc:
- # Don't do anything. Should fall back to __object__'s __hash__
- # which is by id.
- if cache_hash:
- raise TypeError(
- "Invalid value for cache_hash. To use hash caching,"
- " hashing must be either explicitly or implicitly "
- "enabled."
- )
- elif hash is True or (
- hash is None and eq is True and is_frozen is True
- ):
- # Build a __hash__ if told so, or if it's safe.
- builder.add_hash()
- else:
- # Raise TypeError on attempts to hash.
- if cache_hash:
- raise TypeError(
- "Invalid value for cache_hash. To use hash caching,"
- " hashing must be either explicitly or implicitly "
- "enabled."
- )
- builder.make_unhashable()
-
- if _determine_whether_to_implement(
- cls, init, auto_detect, ("__init__",)
- ):
- builder.add_init()
- else:
- builder.add_attrs_init()
- if cache_hash:
- raise TypeError(
- "Invalid value for cache_hash. To use hash caching,"
- " init must be True."
- )
-
- return builder.build_class()
-
- # maybe_cls's type depends on the usage of the decorator. It's a class
- # if it's used as `@attrs` but ``None`` if used as `@attrs()`.
- if maybe_cls is None:
- return wrap
- else:
- return wrap(maybe_cls)
-
-
-_attrs = attrs
-"""
-Internal alias so we can use it in functions that take an argument called
-*attrs*.
-"""
-
-
-if PY2:
-
- def _has_frozen_base_class(cls):
- """
- Check whether *cls* has a frozen ancestor by looking at its
- __setattr__.
- """
- return (
- getattr(cls.__setattr__, "__module__", None)
- == _frozen_setattrs.__module__
- and cls.__setattr__.__name__ == _frozen_setattrs.__name__
- )
-
-
-else:
-
- def _has_frozen_base_class(cls):
- """
- Check whether *cls* has a frozen ancestor by looking at its
- __setattr__.
- """
- return cls.__setattr__ == _frozen_setattrs
-
-
-def _generate_unique_filename(cls, func_name):
- """
- Create a "filename" suitable for a function being generated.
- """
- unique_id = uuid.uuid4()
- extra = ""
- count = 1
-
- while True:
- unique_filename = "".format(
- func_name,
- cls.__module__,
- getattr(cls, "__qualname__", cls.__name__),
- extra,
- )
- # To handle concurrency we essentially "reserve" our spot in
- # the linecache with a dummy line. The caller can then
- # set this value correctly.
- cache_line = (1, None, (str(unique_id),), unique_filename)
- if (
- linecache.cache.setdefault(unique_filename, cache_line)
- == cache_line
- ):
- return unique_filename
-
- # Looks like this spot is taken. Try again.
- count += 1
- extra = "-{0}".format(count)
-
-
-def _make_hash(cls, attrs, frozen, cache_hash):
- attrs = tuple(
- a for a in attrs if a.hash is True or (a.hash is None and a.eq is True)
- )
-
- tab = " "
-
- unique_filename = _generate_unique_filename(cls, "hash")
- type_hash = hash(unique_filename)
-
- hash_def = "def __hash__(self"
- hash_func = "hash(("
- closing_braces = "))"
- if not cache_hash:
- hash_def += "):"
- else:
- if not PY2:
- hash_def += ", *"
-
- hash_def += (
- ", _cache_wrapper="
- + "__import__('attr._make')._make._CacheHashWrapper):"
- )
- hash_func = "_cache_wrapper(" + hash_func
- closing_braces += ")"
-
- method_lines = [hash_def]
-
- def append_hash_computation_lines(prefix, indent):
- """
- Generate the code for actually computing the hash code.
- Below this will either be returned directly or used to compute
- a value which is then cached, depending on the value of cache_hash
- """
-
- method_lines.extend(
- [
- indent + prefix + hash_func,
- indent + " %d," % (type_hash,),
- ]
- )
-
- for a in attrs:
- method_lines.append(indent + " self.%s," % a.name)
-
- method_lines.append(indent + " " + closing_braces)
-
- if cache_hash:
- method_lines.append(tab + "if self.%s is None:" % _hash_cache_field)
- if frozen:
- append_hash_computation_lines(
- "object.__setattr__(self, '%s', " % _hash_cache_field, tab * 2
- )
- method_lines.append(tab * 2 + ")") # close __setattr__
- else:
- append_hash_computation_lines(
- "self.%s = " % _hash_cache_field, tab * 2
- )
- method_lines.append(tab + "return self.%s" % _hash_cache_field)
- else:
- append_hash_computation_lines("return ", tab)
-
- script = "\n".join(method_lines)
- return _make_method("__hash__", script, unique_filename)
-
-
-def _add_hash(cls, attrs):
- """
- Add a hash method to *cls*.
- """
- cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False)
- return cls
-
-
-def _make_ne():
- """
- Create __ne__ method.
- """
-
- def __ne__(self, other):
- """
- Check equality and either forward a NotImplemented or
- return the result negated.
- """
- result = self.__eq__(other)
- if result is NotImplemented:
- return NotImplemented
-
- return not result
-
- return __ne__
-
-
-def _make_eq(cls, attrs):
- """
- Create __eq__ method for *cls* with *attrs*.
- """
- attrs = [a for a in attrs if a.eq]
-
- unique_filename = _generate_unique_filename(cls, "eq")
- lines = [
- "def __eq__(self, other):",
- " if other.__class__ is not self.__class__:",
- " return NotImplemented",
- ]
-
- # We can't just do a big self.x = other.x and... clause due to
- # irregularities like nan == nan is false but (nan,) == (nan,) is true.
- globs = {}
- if attrs:
- lines.append(" return (")
- others = [" ) == ("]
- for a in attrs:
- if a.eq_key:
- cmp_name = "_%s_key" % (a.name,)
- # Add the key function to the global namespace
- # of the evaluated function.
- globs[cmp_name] = a.eq_key
- lines.append(
- " %s(self.%s),"
- % (
- cmp_name,
- a.name,
- )
- )
- others.append(
- " %s(other.%s),"
- % (
- cmp_name,
- a.name,
- )
- )
- else:
- lines.append(" self.%s," % (a.name,))
- others.append(" other.%s," % (a.name,))
-
- lines += others + [" )"]
- else:
- lines.append(" return True")
-
- script = "\n".join(lines)
-
- return _make_method("__eq__", script, unique_filename, globs)
-
-
-def _make_order(cls, attrs):
- """
- Create ordering methods for *cls* with *attrs*.
- """
- attrs = [a for a in attrs if a.order]
-
- def attrs_to_tuple(obj):
- """
- Save us some typing.
- """
- return tuple(
- key(value) if key else value
- for value, key in (
- (getattr(obj, a.name), a.order_key) for a in attrs
- )
- )
-
- def __lt__(self, other):
- """
- Automatically created by attrs.
- """
- if other.__class__ is self.__class__:
- return attrs_to_tuple(self) < attrs_to_tuple(other)
-
- return NotImplemented
-
- def __le__(self, other):
- """
- Automatically created by attrs.
- """
- if other.__class__ is self.__class__:
- return attrs_to_tuple(self) <= attrs_to_tuple(other)
-
- return NotImplemented
-
- def __gt__(self, other):
- """
- Automatically created by attrs.
- """
- if other.__class__ is self.__class__:
- return attrs_to_tuple(self) > attrs_to_tuple(other)
-
- return NotImplemented
-
- def __ge__(self, other):
- """
- Automatically created by attrs.
- """
- if other.__class__ is self.__class__:
- return attrs_to_tuple(self) >= attrs_to_tuple(other)
-
- return NotImplemented
-
- return __lt__, __le__, __gt__, __ge__
-
-
-def _add_eq(cls, attrs=None):
- """
- Add equality methods to *cls* with *attrs*.
- """
- if attrs is None:
- attrs = cls.__attrs_attrs__
-
- cls.__eq__ = _make_eq(cls, attrs)
- cls.__ne__ = _make_ne()
-
- return cls
-
-
-_already_repring = threading.local()
-
-
-def _make_repr(attrs, ns):
- """
- Make a repr method that includes relevant *attrs*, adding *ns* to the full
- name.
- """
-
- # Figure out which attributes to include, and which function to use to
- # format them. The a.repr value can be either bool or a custom callable.
- attr_names_with_reprs = tuple(
- (a.name, repr if a.repr is True else a.repr)
- for a in attrs
- if a.repr is not False
- )
-
- def __repr__(self):
- """
- Automatically created by attrs.
- """
- try:
- working_set = _already_repring.working_set
- except AttributeError:
- working_set = set()
- _already_repring.working_set = working_set
-
- if id(self) in working_set:
- return "..."
- real_cls = self.__class__
- if ns is None:
- qualname = getattr(real_cls, "__qualname__", None)
- if qualname is not None:
- class_name = qualname.rsplit(">.", 1)[-1]
- else:
- class_name = real_cls.__name__
- else:
- class_name = ns + "." + real_cls.__name__
-
- # Since 'self' remains on the stack (i.e.: strongly referenced) for the
- # duration of this call, it's safe to depend on id(...) stability, and
- # not need to track the instance and therefore worry about properties
- # like weakref- or hash-ability.
- working_set.add(id(self))
- try:
- result = [class_name, "("]
- first = True
- for name, attr_repr in attr_names_with_reprs:
- if first:
- first = False
- else:
- result.append(", ")
- result.extend(
- (name, "=", attr_repr(getattr(self, name, NOTHING)))
- )
- return "".join(result) + ")"
- finally:
- working_set.remove(id(self))
-
- return __repr__
-
-
-def _add_repr(cls, ns=None, attrs=None):
- """
- Add a repr method to *cls*.
- """
- if attrs is None:
- attrs = cls.__attrs_attrs__
-
- cls.__repr__ = _make_repr(attrs, ns)
- return cls
-
-
-def fields(cls):
- """
- Return the tuple of ``attrs`` attributes for a class.
-
- The tuple also allows accessing the fields by their names (see below for
- examples).
-
- :param type cls: Class to introspect.
-
- :raise TypeError: If *cls* is not a class.
- :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
- class.
-
- :rtype: tuple (with name accessors) of `attr.Attribute`
-
- .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields
- by name.
- """
- if not isclass(cls):
- raise TypeError("Passed object must be a class.")
- attrs = getattr(cls, "__attrs_attrs__", None)
- if attrs is None:
- raise NotAnAttrsClassError(
- "{cls!r} is not an attrs-decorated class.".format(cls=cls)
- )
- return attrs
-
-
-def fields_dict(cls):
- """
- Return an ordered dictionary of ``attrs`` attributes for a class, whose
- keys are the attribute names.
-
- :param type cls: Class to introspect.
-
- :raise TypeError: If *cls* is not a class.
- :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
- class.
-
- :rtype: an ordered dict where keys are attribute names and values are
- `attr.Attribute`\\ s. This will be a `dict` if it's
- naturally ordered like on Python 3.6+ or an
- :class:`~collections.OrderedDict` otherwise.
-
- .. versionadded:: 18.1.0
- """
- if not isclass(cls):
- raise TypeError("Passed object must be a class.")
- attrs = getattr(cls, "__attrs_attrs__", None)
- if attrs is None:
- raise NotAnAttrsClassError(
- "{cls!r} is not an attrs-decorated class.".format(cls=cls)
- )
- return ordered_dict(((a.name, a) for a in attrs))
-
-
-def validate(inst):
- """
- Validate all attributes on *inst* that have a validator.
-
- Leaves all exceptions through.
-
- :param inst: Instance of a class with ``attrs`` attributes.
- """
- if _config._run_validators is False:
- return
-
- for a in fields(inst.__class__):
- v = a.validator
- if v is not None:
- v(inst, a, getattr(inst, a.name))
-
-
-def _is_slot_cls(cls):
- return "__slots__" in cls.__dict__
-
-
-def _is_slot_attr(a_name, base_attr_map):
- """
- Check if the attribute name comes from a slot class.
- """
- return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name])
-
-
-def _make_init(
- cls,
- attrs,
- pre_init,
- post_init,
- frozen,
- slots,
- cache_hash,
- base_attr_map,
- is_exc,
- has_global_on_setattr,
- attrs_init,
-):
- if frozen and has_global_on_setattr:
- raise ValueError("Frozen classes can't use on_setattr.")
-
- needs_cached_setattr = cache_hash or frozen
- filtered_attrs = []
- attr_dict = {}
- for a in attrs:
- if not a.init and a.default is NOTHING:
- continue
-
- filtered_attrs.append(a)
- attr_dict[a.name] = a
-
- if a.on_setattr is not None:
- if frozen is True:
- raise ValueError("Frozen classes can't use on_setattr.")
-
- needs_cached_setattr = True
- elif (
- has_global_on_setattr and a.on_setattr is not setters.NO_OP
- ) or _is_slot_attr(a.name, base_attr_map):
- needs_cached_setattr = True
-
- unique_filename = _generate_unique_filename(cls, "init")
-
- script, globs, annotations = _attrs_to_init_script(
- filtered_attrs,
- frozen,
- slots,
- pre_init,
- post_init,
- cache_hash,
- base_attr_map,
- is_exc,
- needs_cached_setattr,
- has_global_on_setattr,
- attrs_init,
- )
- if cls.__module__ in sys.modules:
- # This makes typing.get_type_hints(CLS.__init__) resolve string types.
- globs.update(sys.modules[cls.__module__].__dict__)
-
- globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict})
-
- if needs_cached_setattr:
- # Save the lookup overhead in __init__ if we need to circumvent
- # setattr hooks.
- globs["_cached_setattr"] = _obj_setattr
-
- init = _make_method(
- "__attrs_init__" if attrs_init else "__init__",
- script,
- unique_filename,
- globs,
- )
- init.__annotations__ = annotations
-
- return init
-
-
-def _setattr(attr_name, value_var, has_on_setattr):
- """
- Use the cached object.setattr to set *attr_name* to *value_var*.
- """
- return "_setattr('%s', %s)" % (attr_name, value_var)
-
-
-def _setattr_with_converter(attr_name, value_var, has_on_setattr):
- """
- Use the cached object.setattr to set *attr_name* to *value_var*, but run
- its converter first.
- """
- return "_setattr('%s', %s(%s))" % (
- attr_name,
- _init_converter_pat % (attr_name,),
- value_var,
- )
-
-
-def _assign(attr_name, value, has_on_setattr):
- """
- Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise
- relegate to _setattr.
- """
- if has_on_setattr:
- return _setattr(attr_name, value, True)
-
- return "self.%s = %s" % (attr_name, value)
-
-
-def _assign_with_converter(attr_name, value_var, has_on_setattr):
- """
- Unless *attr_name* has an on_setattr hook, use normal assignment after
- conversion. Otherwise relegate to _setattr_with_converter.
- """
- if has_on_setattr:
- return _setattr_with_converter(attr_name, value_var, True)
-
- return "self.%s = %s(%s)" % (
- attr_name,
- _init_converter_pat % (attr_name,),
- value_var,
- )
-
-
-if PY2:
-
- def _unpack_kw_only_py2(attr_name, default=None):
- """
- Unpack *attr_name* from _kw_only dict.
- """
- if default is not None:
- arg_default = ", %s" % default
- else:
- arg_default = ""
- return "%s = _kw_only.pop('%s'%s)" % (
- attr_name,
- attr_name,
- arg_default,
- )
-
- def _unpack_kw_only_lines_py2(kw_only_args):
- """
- Unpack all *kw_only_args* from _kw_only dict and handle errors.
-
- Given a list of strings "{attr_name}" and "{attr_name}={default}"
- generates list of lines of code that pop attrs from _kw_only dict and
- raise TypeError similar to builtin if required attr is missing or
- extra key is passed.
-
- >>> print("\n".join(_unpack_kw_only_lines_py2(["a", "b=42"])))
- try:
- a = _kw_only.pop('a')
- b = _kw_only.pop('b', 42)
- except KeyError as _key_error:
- raise TypeError(
- ...
- if _kw_only:
- raise TypeError(
- ...
- """
- lines = ["try:"]
- lines.extend(
- " " + _unpack_kw_only_py2(*arg.split("="))
- for arg in kw_only_args
- )
- lines += """\
-except KeyError as _key_error:
- raise TypeError(
- '__init__() missing required keyword-only argument: %s' % _key_error
- )
-if _kw_only:
- raise TypeError(
- '__init__() got an unexpected keyword argument %r'
- % next(iter(_kw_only))
- )
-""".split(
- "\n"
- )
- return lines
-
-
-def _attrs_to_init_script(
- attrs,
- frozen,
- slots,
- pre_init,
- post_init,
- cache_hash,
- base_attr_map,
- is_exc,
- needs_cached_setattr,
- has_global_on_setattr,
- attrs_init,
-):
- """
- Return a script of an initializer for *attrs* and a dict of globals.
-
- The globals are expected by the generated script.
-
- If *frozen* is True, we cannot set the attributes directly so we use
- a cached ``object.__setattr__``.
- """
- lines = []
- if pre_init:
- lines.append("self.__attrs_pre_init__()")
-
- if needs_cached_setattr:
- lines.append(
- # Circumvent the __setattr__ descriptor to save one lookup per
- # assignment.
- # Note _setattr will be used again below if cache_hash is True
- "_setattr = _cached_setattr.__get__(self, self.__class__)"
- )
-
- if frozen is True:
- if slots is True:
- fmt_setter = _setattr
- fmt_setter_with_converter = _setattr_with_converter
- else:
- # Dict frozen classes assign directly to __dict__.
- # But only if the attribute doesn't come from an ancestor slot
- # class.
- # Note _inst_dict will be used again below if cache_hash is True
- lines.append("_inst_dict = self.__dict__")
-
- def fmt_setter(attr_name, value_var, has_on_setattr):
- if _is_slot_attr(attr_name, base_attr_map):
- return _setattr(attr_name, value_var, has_on_setattr)
-
- return "_inst_dict['%s'] = %s" % (attr_name, value_var)
-
- def fmt_setter_with_converter(
- attr_name, value_var, has_on_setattr
- ):
- if has_on_setattr or _is_slot_attr(attr_name, base_attr_map):
- return _setattr_with_converter(
- attr_name, value_var, has_on_setattr
- )
-
- return "_inst_dict['%s'] = %s(%s)" % (
- attr_name,
- _init_converter_pat % (attr_name,),
- value_var,
- )
-
- else:
- # Not frozen.
- fmt_setter = _assign
- fmt_setter_with_converter = _assign_with_converter
-
- args = []
- kw_only_args = []
- attrs_to_validate = []
-
- # This is a dictionary of names to validator and converter callables.
- # Injecting this into __init__ globals lets us avoid lookups.
- names_for_globals = {}
- annotations = {"return": None}
-
- for a in attrs:
- if a.validator:
- attrs_to_validate.append(a)
-
- attr_name = a.name
- has_on_setattr = a.on_setattr is not None or (
- a.on_setattr is not setters.NO_OP and has_global_on_setattr
- )
- arg_name = a.name.lstrip("_")
-
- has_factory = isinstance(a.default, Factory)
- if has_factory and a.default.takes_self:
- maybe_self = "self"
- else:
- maybe_self = ""
-
- if a.init is False:
- if has_factory:
- init_factory_name = _init_factory_pat.format(a.name)
- if a.converter is not None:
- lines.append(
- fmt_setter_with_converter(
- attr_name,
- init_factory_name + "(%s)" % (maybe_self,),
- has_on_setattr,
- )
- )
- conv_name = _init_converter_pat % (a.name,)
- names_for_globals[conv_name] = a.converter
- else:
- lines.append(
- fmt_setter(
- attr_name,
- init_factory_name + "(%s)" % (maybe_self,),
- has_on_setattr,
- )
- )
- names_for_globals[init_factory_name] = a.default.factory
- else:
- if a.converter is not None:
- lines.append(
- fmt_setter_with_converter(
- attr_name,
- "attr_dict['%s'].default" % (attr_name,),
- has_on_setattr,
- )
- )
- conv_name = _init_converter_pat % (a.name,)
- names_for_globals[conv_name] = a.converter
- else:
- lines.append(
- fmt_setter(
- attr_name,
- "attr_dict['%s'].default" % (attr_name,),
- has_on_setattr,
- )
- )
- elif a.default is not NOTHING and not has_factory:
- arg = "%s=attr_dict['%s'].default" % (arg_name, attr_name)
- if a.kw_only:
- kw_only_args.append(arg)
- else:
- args.append(arg)
-
- if a.converter is not None:
- lines.append(
- fmt_setter_with_converter(
- attr_name, arg_name, has_on_setattr
- )
- )
- names_for_globals[
- _init_converter_pat % (a.name,)
- ] = a.converter
- else:
- lines.append(fmt_setter(attr_name, arg_name, has_on_setattr))
-
- elif has_factory:
- arg = "%s=NOTHING" % (arg_name,)
- if a.kw_only:
- kw_only_args.append(arg)
- else:
- args.append(arg)
- lines.append("if %s is not NOTHING:" % (arg_name,))
-
- init_factory_name = _init_factory_pat.format(a.name)
- if a.converter is not None:
- lines.append(
- " "
- + fmt_setter_with_converter(
- attr_name, arg_name, has_on_setattr
- )
- )
- lines.append("else:")
- lines.append(
- " "
- + fmt_setter_with_converter(
- attr_name,
- init_factory_name + "(" + maybe_self + ")",
- has_on_setattr,
- )
- )
- names_for_globals[
- _init_converter_pat % (a.name,)
- ] = a.converter
- else:
- lines.append(
- " " + fmt_setter(attr_name, arg_name, has_on_setattr)
- )
- lines.append("else:")
- lines.append(
- " "
- + fmt_setter(
- attr_name,
- init_factory_name + "(" + maybe_self + ")",
- has_on_setattr,
- )
- )
- names_for_globals[init_factory_name] = a.default.factory
- else:
- if a.kw_only:
- kw_only_args.append(arg_name)
- else:
- args.append(arg_name)
-
- if a.converter is not None:
- lines.append(
- fmt_setter_with_converter(
- attr_name, arg_name, has_on_setattr
- )
- )
- names_for_globals[
- _init_converter_pat % (a.name,)
- ] = a.converter
- else:
- lines.append(fmt_setter(attr_name, arg_name, has_on_setattr))
-
- if a.init is True:
- if a.type is not None and a.converter is None:
- annotations[arg_name] = a.type
- elif a.converter is not None and not PY2:
- # Try to get the type from the converter.
- sig = None
- try:
- sig = inspect.signature(a.converter)
- except (ValueError, TypeError): # inspect failed
- pass
- if sig:
- sig_params = list(sig.parameters.values())
- if (
- sig_params
- and sig_params[0].annotation
- is not inspect.Parameter.empty
- ):
- annotations[arg_name] = sig_params[0].annotation
-
- if attrs_to_validate: # we can skip this if there are no validators.
- names_for_globals["_config"] = _config
- lines.append("if _config._run_validators is True:")
- for a in attrs_to_validate:
- val_name = "__attr_validator_" + a.name
- attr_name = "__attr_" + a.name
- lines.append(
- " %s(self, %s, self.%s)" % (val_name, attr_name, a.name)
- )
- names_for_globals[val_name] = a.validator
- names_for_globals[attr_name] = a
-
- if post_init:
- lines.append("self.__attrs_post_init__()")
-
- # because this is set only after __attrs_post_init is called, a crash
- # will result if post-init tries to access the hash code. This seemed
- # preferable to setting this beforehand, in which case alteration to
- # field values during post-init combined with post-init accessing the
- # hash code would result in silent bugs.
- if cache_hash:
- if frozen:
- if slots:
- # if frozen and slots, then _setattr defined above
- init_hash_cache = "_setattr('%s', %s)"
- else:
- # if frozen and not slots, then _inst_dict defined above
- init_hash_cache = "_inst_dict['%s'] = %s"
- else:
- init_hash_cache = "self.%s = %s"
- lines.append(init_hash_cache % (_hash_cache_field, "None"))
-
- # For exceptions we rely on BaseException.__init__ for proper
- # initialization.
- if is_exc:
- vals = ",".join("self." + a.name for a in attrs if a.init)
-
- lines.append("BaseException.__init__(self, %s)" % (vals,))
-
- args = ", ".join(args)
- if kw_only_args:
- if PY2:
- lines = _unpack_kw_only_lines_py2(kw_only_args) + lines
-
- args += "%s**_kw_only" % (", " if args else "",) # leading comma
- else:
- args += "%s*, %s" % (
- ", " if args else "", # leading comma
- ", ".join(kw_only_args), # kw_only args
- )
- return (
- """\
-def {init_name}(self, {args}):
- {lines}
-""".format(
- init_name=("__attrs_init__" if attrs_init else "__init__"),
- args=args,
- lines="\n ".join(lines) if lines else "pass",
- ),
- names_for_globals,
- annotations,
- )
-
-
-class Attribute(object):
- """
- *Read-only* representation of an attribute.
-
- Instances of this class are frequently used for introspection purposes
- like:
-
- - `fields` returns a tuple of them.
- - Validators get them passed as the first argument.
- - The *field transformer* hook receives a list of them.
-
- :attribute name: The name of the attribute.
- :attribute inherited: Whether or not that attribute has been inherited from
- a base class.
-
- Plus *all* arguments of `attr.ib` (except for ``factory``
- which is only syntactic sugar for ``default=Factory(...)``.
-
- .. versionadded:: 20.1.0 *inherited*
- .. versionadded:: 20.1.0 *on_setattr*
- .. versionchanged:: 20.2.0 *inherited* is not taken into account for
- equality checks and hashing anymore.
- .. versionadded:: 21.1.0 *eq_key* and *order_key*
-
- For the full version history of the fields, see `attr.ib`.
- """
-
- __slots__ = (
- "name",
- "default",
- "validator",
- "repr",
- "eq",
- "eq_key",
- "order",
- "order_key",
- "hash",
- "init",
- "metadata",
- "type",
- "converter",
- "kw_only",
- "inherited",
- "on_setattr",
- )
-
- def __init__(
- self,
- name,
- default,
- validator,
- repr,
- cmp, # XXX: unused, remove along with other cmp code.
- hash,
- init,
- inherited,
- metadata=None,
- type=None,
- converter=None,
- kw_only=False,
- eq=None,
- eq_key=None,
- order=None,
- order_key=None,
- on_setattr=None,
- ):
- eq, eq_key, order, order_key = _determine_attrib_eq_order(
- cmp, eq_key or eq, order_key or order, True
- )
-
- # Cache this descriptor here to speed things up later.
- bound_setattr = _obj_setattr.__get__(self, Attribute)
-
- # Despite the big red warning, people *do* instantiate `Attribute`
- # themselves.
- bound_setattr("name", name)
- bound_setattr("default", default)
- bound_setattr("validator", validator)
- bound_setattr("repr", repr)
- bound_setattr("eq", eq)
- bound_setattr("eq_key", eq_key)
- bound_setattr("order", order)
- bound_setattr("order_key", order_key)
- bound_setattr("hash", hash)
- bound_setattr("init", init)
- bound_setattr("converter", converter)
- bound_setattr(
- "metadata",
- (
- metadata_proxy(metadata)
- if metadata
- else _empty_metadata_singleton
- ),
- )
- bound_setattr("type", type)
- bound_setattr("kw_only", kw_only)
- bound_setattr("inherited", inherited)
- bound_setattr("on_setattr", on_setattr)
-
- def __setattr__(self, name, value):
- raise FrozenInstanceError()
-
- @classmethod
- def from_counting_attr(cls, name, ca, type=None):
- # type holds the annotated value. deal with conflicts:
- if type is None:
- type = ca.type
- elif ca.type is not None:
- raise ValueError(
- "Type annotation and type argument cannot both be present"
- )
- inst_dict = {
- k: getattr(ca, k)
- for k in Attribute.__slots__
- if k
- not in (
- "name",
- "validator",
- "default",
- "type",
- "inherited",
- ) # exclude methods and deprecated alias
- }
- return cls(
- name=name,
- validator=ca._validator,
- default=ca._default,
- type=type,
- cmp=None,
- inherited=False,
- **inst_dict
- )
-
- @property
- def cmp(self):
- """
- Simulate the presence of a cmp attribute and warn.
- """
- warnings.warn(_CMP_DEPRECATION, DeprecationWarning, stacklevel=2)
-
- return self.eq and self.order
-
- # Don't use attr.evolve since fields(Attribute) doesn't work
- def evolve(self, **changes):
- """
- Copy *self* and apply *changes*.
-
- This works similarly to `attr.evolve` but that function does not work
- with ``Attribute``.
-
- It is mainly meant to be used for `transform-fields`.
-
- .. versionadded:: 20.3.0
- """
- new = copy.copy(self)
-
- new._setattrs(changes.items())
-
- return new
-
- # Don't use _add_pickle since fields(Attribute) doesn't work
- def __getstate__(self):
- """
- Play nice with pickle.
- """
- return tuple(
- getattr(self, name) if name != "metadata" else dict(self.metadata)
- for name in self.__slots__
- )
-
- def __setstate__(self, state):
- """
- Play nice with pickle.
- """
- self._setattrs(zip(self.__slots__, state))
-
- def _setattrs(self, name_values_pairs):
- bound_setattr = _obj_setattr.__get__(self, Attribute)
- for name, value in name_values_pairs:
- if name != "metadata":
- bound_setattr(name, value)
- else:
- bound_setattr(
- name,
- metadata_proxy(value)
- if value
- else _empty_metadata_singleton,
- )
-
-
-_a = [
- Attribute(
- name=name,
- default=NOTHING,
- validator=None,
- repr=True,
- cmp=None,
- eq=True,
- order=False,
- hash=(name != "metadata"),
- init=True,
- inherited=False,
- )
- for name in Attribute.__slots__
-]
-
-Attribute = _add_hash(
- _add_eq(
- _add_repr(Attribute, attrs=_a),
- attrs=[a for a in _a if a.name != "inherited"],
- ),
- attrs=[a for a in _a if a.hash and a.name != "inherited"],
-)
-
-
-class _CountingAttr(object):
- """
- Intermediate representation of attributes that uses a counter to preserve
- the order in which the attributes have been defined.
-
- *Internal* data structure of the attrs library. Running into is most
- likely the result of a bug like a forgotten `@attr.s` decorator.
- """
-
- __slots__ = (
- "counter",
- "_default",
- "repr",
- "eq",
- "eq_key",
- "order",
- "order_key",
- "hash",
- "init",
- "metadata",
- "_validator",
- "converter",
- "type",
- "kw_only",
- "on_setattr",
- )
- __attrs_attrs__ = tuple(
- Attribute(
- name=name,
- default=NOTHING,
- validator=None,
- repr=True,
- cmp=None,
- hash=True,
- init=True,
- kw_only=False,
- eq=True,
- eq_key=None,
- order=False,
- order_key=None,
- inherited=False,
- on_setattr=None,
- )
- for name in (
- "counter",
- "_default",
- "repr",
- "eq",
- "order",
- "hash",
- "init",
- "on_setattr",
- )
- ) + (
- Attribute(
- name="metadata",
- default=None,
- validator=None,
- repr=True,
- cmp=None,
- hash=False,
- init=True,
- kw_only=False,
- eq=True,
- eq_key=None,
- order=False,
- order_key=None,
- inherited=False,
- on_setattr=None,
- ),
- )
- cls_counter = 0
-
- def __init__(
- self,
- default,
- validator,
- repr,
- cmp,
- hash,
- init,
- converter,
- metadata,
- type,
- kw_only,
- eq,
- eq_key,
- order,
- order_key,
- on_setattr,
- ):
- _CountingAttr.cls_counter += 1
- self.counter = _CountingAttr.cls_counter
- self._default = default
- self._validator = validator
- self.converter = converter
- self.repr = repr
- self.eq = eq
- self.eq_key = eq_key
- self.order = order
- self.order_key = order_key
- self.hash = hash
- self.init = init
- self.metadata = metadata
- self.type = type
- self.kw_only = kw_only
- self.on_setattr = on_setattr
-
- def validator(self, meth):
- """
- Decorator that adds *meth* to the list of validators.
-
- Returns *meth* unchanged.
-
- .. versionadded:: 17.1.0
- """
- if self._validator is None:
- self._validator = meth
- else:
- self._validator = and_(self._validator, meth)
- return meth
-
- def default(self, meth):
- """
- Decorator that allows to set the default for an attribute.
-
- Returns *meth* unchanged.
-
- :raises DefaultAlreadySetError: If default has been set before.
-
- .. versionadded:: 17.1.0
- """
- if self._default is not NOTHING:
- raise DefaultAlreadySetError()
-
- self._default = Factory(meth, takes_self=True)
-
- return meth
-
-
-_CountingAttr = _add_eq(_add_repr(_CountingAttr))
-
-
-class Factory(object):
- """
- Stores a factory callable.
-
- If passed as the default value to `attr.ib`, the factory is used to
- generate a new value.
-
- :param callable factory: A callable that takes either none or exactly one
- mandatory positional argument depending on *takes_self*.
- :param bool takes_self: Pass the partially initialized instance that is
- being initialized as a positional argument.
-
- .. versionadded:: 17.1.0 *takes_self*
- """
-
- __slots__ = ("factory", "takes_self")
-
- def __init__(self, factory, takes_self=False):
- """
- `Factory` is part of the default machinery so if we want a default
- value here, we have to implement it ourselves.
- """
- self.factory = factory
- self.takes_self = takes_self
-
- def __getstate__(self):
- """
- Play nice with pickle.
- """
- return tuple(getattr(self, name) for name in self.__slots__)
-
- def __setstate__(self, state):
- """
- Play nice with pickle.
- """
- for name, value in zip(self.__slots__, state):
- setattr(self, name, value)
-
-
-_f = [
- Attribute(
- name=name,
- default=NOTHING,
- validator=None,
- repr=True,
- cmp=None,
- eq=True,
- order=False,
- hash=True,
- init=True,
- inherited=False,
- )
- for name in Factory.__slots__
-]
-
-Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f)
-
-
-def make_class(name, attrs, bases=(object,), **attributes_arguments):
- """
- A quick way to create a new class called *name* with *attrs*.
-
- :param str name: The name for the new class.
-
- :param attrs: A list of names or a dictionary of mappings of names to
- attributes.
-
- If *attrs* is a list or an ordered dict (`dict` on Python 3.6+,
- `collections.OrderedDict` otherwise), the order is deduced from
- the order of the names or attributes inside *attrs*. Otherwise the
- order of the definition of the attributes is used.
- :type attrs: `list` or `dict`
-
- :param tuple bases: Classes that the new class will subclass.
-
- :param attributes_arguments: Passed unmodified to `attr.s`.
-
- :return: A new class with *attrs*.
- :rtype: type
-
- .. versionadded:: 17.1.0 *bases*
- .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained.
- """
- if isinstance(attrs, dict):
- cls_dict = attrs
- elif isinstance(attrs, (list, tuple)):
- cls_dict = dict((a, attrib()) for a in attrs)
- else:
- raise TypeError("attrs argument must be a dict or a list.")
-
- pre_init = cls_dict.pop("__attrs_pre_init__", None)
- post_init = cls_dict.pop("__attrs_post_init__", None)
- user_init = cls_dict.pop("__init__", None)
-
- body = {}
- if pre_init is not None:
- body["__attrs_pre_init__"] = pre_init
- if post_init is not None:
- body["__attrs_post_init__"] = post_init
- if user_init is not None:
- body["__init__"] = user_init
-
- type_ = new_class(name, bases, {}, lambda ns: ns.update(body))
-
- # For pickling to work, the __module__ variable needs to be set to the
- # frame where the class is created. Bypass this step in environments where
- # sys._getframe is not defined (Jython for example) or sys._getframe is not
- # defined for arguments greater than 0 (IronPython).
- try:
- type_.__module__ = sys._getframe(1).f_globals.get(
- "__name__", "__main__"
- )
- except (AttributeError, ValueError):
- pass
-
- # We do it here for proper warnings with meaningful stacklevel.
- cmp = attributes_arguments.pop("cmp", None)
- (
- attributes_arguments["eq"],
- attributes_arguments["order"],
- ) = _determine_attrs_eq_order(
- cmp,
- attributes_arguments.get("eq"),
- attributes_arguments.get("order"),
- True,
- )
-
- return _attrs(these=cls_dict, **attributes_arguments)(type_)
-
-
-# These are required by within this module so we define them here and merely
-# import into .validators / .converters.
-
-
-@attrs(slots=True, hash=True)
-class _AndValidator(object):
- """
- Compose many validators to a single one.
- """
-
- _validators = attrib()
-
- def __call__(self, inst, attr, value):
- for v in self._validators:
- v(inst, attr, value)
-
-
-def and_(*validators):
- """
- A validator that composes multiple validators into one.
-
- When called on a value, it runs all wrapped validators.
-
- :param callables validators: Arbitrary number of validators.
-
- .. versionadded:: 17.1.0
- """
- vals = []
- for validator in validators:
- vals.extend(
- validator._validators
- if isinstance(validator, _AndValidator)
- else [validator]
- )
-
- return _AndValidator(tuple(vals))
-
-
-def pipe(*converters):
- """
- A converter that composes multiple converters into one.
-
- When called on a value, it runs all wrapped converters, returning the
- *last* value.
-
- Type annotations will be inferred from the wrapped converters', if
- they have any.
-
- :param callables converters: Arbitrary number of converters.
-
- .. versionadded:: 20.1.0
- """
-
- def pipe_converter(val):
- for converter in converters:
- val = converter(val)
-
- return val
-
- if not PY2:
- if not converters:
- # If the converter list is empty, pipe_converter is the identity.
- A = typing.TypeVar("A")
- pipe_converter.__annotations__ = {"val": A, "return": A}
- else:
- # Get parameter type.
- sig = None
- try:
- sig = inspect.signature(converters[0])
- except (ValueError, TypeError): # inspect failed
- pass
- if sig:
- params = list(sig.parameters.values())
- if (
- params
- and params[0].annotation is not inspect.Parameter.empty
- ):
- pipe_converter.__annotations__["val"] = params[
- 0
- ].annotation
- # Get return type.
- sig = None
- try:
- sig = inspect.signature(converters[-1])
- except (ValueError, TypeError): # inspect failed
- pass
- if sig and sig.return_annotation is not inspect.Signature().empty:
- pipe_converter.__annotations__[
- "return"
- ] = sig.return_annotation
-
- return pipe_converter
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/_next_gen.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/_next_gen.py
deleted file mode 100644
index fab0af966a..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/_next_gen.py
+++ /dev/null
@@ -1,158 +0,0 @@
-"""
-These are Python 3.6+-only and keyword-only APIs that call `attr.s` and
-`attr.ib` with different default values.
-"""
-
-from functools import partial
-
-from attr.exceptions import UnannotatedAttributeError
-
-from . import setters
-from ._make import NOTHING, _frozen_setattrs, attrib, attrs
-
-
-def define(
- maybe_cls=None,
- *,
- these=None,
- repr=None,
- hash=None,
- init=None,
- slots=True,
- frozen=False,
- weakref_slot=True,
- str=False,
- auto_attribs=None,
- kw_only=False,
- cache_hash=False,
- auto_exc=True,
- eq=None,
- order=False,
- auto_detect=True,
- getstate_setstate=None,
- on_setattr=None,
- field_transformer=None,
-):
- r"""
- The only behavioral differences are the handling of the *auto_attribs*
- option:
-
- :param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves
- exactly like `attr.s`. If left `None`, `attr.s` will try to guess:
-
- 1. If any attributes are annotated and no unannotated `attr.ib`\ s
- are found, it assumes *auto_attribs=True*.
- 2. Otherwise it assumes *auto_attribs=False* and tries to collect
- `attr.ib`\ s.
-
- and that mutable classes (``frozen=False``) validate on ``__setattr__``.
-
- .. versionadded:: 20.1.0
- """
-
- def do_it(cls, auto_attribs):
- return attrs(
- maybe_cls=cls,
- these=these,
- repr=repr,
- hash=hash,
- init=init,
- slots=slots,
- frozen=frozen,
- weakref_slot=weakref_slot,
- str=str,
- auto_attribs=auto_attribs,
- kw_only=kw_only,
- cache_hash=cache_hash,
- auto_exc=auto_exc,
- eq=eq,
- order=order,
- auto_detect=auto_detect,
- collect_by_mro=True,
- getstate_setstate=getstate_setstate,
- on_setattr=on_setattr,
- field_transformer=field_transformer,
- )
-
- def wrap(cls):
- """
- Making this a wrapper ensures this code runs during class creation.
-
- We also ensure that frozen-ness of classes is inherited.
- """
- nonlocal frozen, on_setattr
-
- had_on_setattr = on_setattr not in (None, setters.NO_OP)
-
- # By default, mutable classes validate on setattr.
- if frozen is False and on_setattr is None:
- on_setattr = setters.validate
-
- # However, if we subclass a frozen class, we inherit the immutability
- # and disable on_setattr.
- for base_cls in cls.__bases__:
- if base_cls.__setattr__ is _frozen_setattrs:
- if had_on_setattr:
- raise ValueError(
- "Frozen classes can't use on_setattr "
- "(frozen-ness was inherited)."
- )
-
- on_setattr = setters.NO_OP
- break
-
- if auto_attribs is not None:
- return do_it(cls, auto_attribs)
-
- try:
- return do_it(cls, True)
- except UnannotatedAttributeError:
- return do_it(cls, False)
-
- # maybe_cls's type depends on the usage of the decorator. It's a class
- # if it's used as `@attrs` but ``None`` if used as `@attrs()`.
- if maybe_cls is None:
- return wrap
- else:
- return wrap(maybe_cls)
-
-
-mutable = define
-frozen = partial(define, frozen=True, on_setattr=None)
-
-
-def field(
- *,
- default=NOTHING,
- validator=None,
- repr=True,
- hash=None,
- init=True,
- metadata=None,
- converter=None,
- factory=None,
- kw_only=False,
- eq=None,
- order=None,
- on_setattr=None,
-):
- """
- Identical to `attr.ib`, except keyword-only and with some arguments
- removed.
-
- .. versionadded:: 20.1.0
- """
- return attrib(
- default=default,
- validator=validator,
- repr=repr,
- hash=hash,
- init=init,
- metadata=metadata,
- converter=converter,
- factory=factory,
- kw_only=kw_only,
- eq=eq,
- order=order,
- on_setattr=on_setattr,
- )
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/_version_info.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/_version_info.py
deleted file mode 100644
index 014e78a1b4..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/_version_info.py
+++ /dev/null
@@ -1,85 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-from functools import total_ordering
-
-from ._funcs import astuple
-from ._make import attrib, attrs
-
-
-@total_ordering
-@attrs(eq=False, order=False, slots=True, frozen=True)
-class VersionInfo(object):
- """
- A version object that can be compared to tuple of length 1--4:
-
- >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2)
- True
- >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1)
- True
- >>> vi = attr.VersionInfo(19, 2, 0, "final")
- >>> vi < (19, 1, 1)
- False
- >>> vi < (19,)
- False
- >>> vi == (19, 2,)
- True
- >>> vi == (19, 2, 1)
- False
-
- .. versionadded:: 19.2
- """
-
- year = attrib(type=int)
- minor = attrib(type=int)
- micro = attrib(type=int)
- releaselevel = attrib(type=str)
-
- @classmethod
- def _from_version_string(cls, s):
- """
- Parse *s* and return a _VersionInfo.
- """
- v = s.split(".")
- if len(v) == 3:
- v.append("final")
-
- return cls(
- year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3]
- )
-
- def _ensure_tuple(self, other):
- """
- Ensure *other* is a tuple of a valid length.
-
- Returns a possibly transformed *other* and ourselves as a tuple of
- the same length as *other*.
- """
-
- if self.__class__ is other.__class__:
- other = astuple(other)
-
- if not isinstance(other, tuple):
- raise NotImplementedError
-
- if not (1 <= len(other) <= 4):
- raise NotImplementedError
-
- return astuple(self)[: len(other)], other
-
- def __eq__(self, other):
- try:
- us, them = self._ensure_tuple(other)
- except NotImplementedError:
- return NotImplemented
-
- return us == them
-
- def __lt__(self, other):
- try:
- us, them = self._ensure_tuple(other)
- except NotImplementedError:
- return NotImplemented
-
- # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't
- # have to do anything special with releaselevel for now.
- return us < them
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/_version_info.pyi b/server_addon/fusion/client/ayon_fusion/vendor/attr/_version_info.pyi
deleted file mode 100644
index 45ced08633..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/_version_info.pyi
+++ /dev/null
@@ -1,9 +0,0 @@
-class VersionInfo:
- @property
- def year(self) -> int: ...
- @property
- def minor(self) -> int: ...
- @property
- def micro(self) -> int: ...
- @property
- def releaselevel(self) -> str: ...
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/converters.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/converters.py
deleted file mode 100644
index 2777db6d0a..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/converters.py
+++ /dev/null
@@ -1,111 +0,0 @@
-"""
-Commonly useful converters.
-"""
-
-from __future__ import absolute_import, division, print_function
-
-from ._compat import PY2
-from ._make import NOTHING, Factory, pipe
-
-
-if not PY2:
- import inspect
- import typing
-
-
-__all__ = [
- "pipe",
- "optional",
- "default_if_none",
-]
-
-
-def optional(converter):
- """
- A converter that allows an attribute to be optional. An optional attribute
- is one which can be set to ``None``.
-
- Type annotations will be inferred from the wrapped converter's, if it
- has any.
-
- :param callable converter: the converter that is used for non-``None``
- values.
-
- .. versionadded:: 17.1.0
- """
-
- def optional_converter(val):
- if val is None:
- return None
- return converter(val)
-
- if not PY2:
- sig = None
- try:
- sig = inspect.signature(converter)
- except (ValueError, TypeError): # inspect failed
- pass
- if sig:
- params = list(sig.parameters.values())
- if params and params[0].annotation is not inspect.Parameter.empty:
- optional_converter.__annotations__["val"] = typing.Optional[
- params[0].annotation
- ]
- if sig.return_annotation is not inspect.Signature.empty:
- optional_converter.__annotations__["return"] = typing.Optional[
- sig.return_annotation
- ]
-
- return optional_converter
-
-
-def default_if_none(default=NOTHING, factory=None):
- """
- A converter that allows to replace ``None`` values by *default* or the
- result of *factory*.
-
- :param default: Value to be used if ``None`` is passed. Passing an instance
- of `attr.Factory` is supported, however the ``takes_self`` option
- is *not*.
- :param callable factory: A callable that takes no parameters whose result
- is used if ``None`` is passed.
-
- :raises TypeError: If **neither** *default* or *factory* is passed.
- :raises TypeError: If **both** *default* and *factory* are passed.
- :raises ValueError: If an instance of `attr.Factory` is passed with
- ``takes_self=True``.
-
- .. versionadded:: 18.2.0
- """
- if default is NOTHING and factory is None:
- raise TypeError("Must pass either `default` or `factory`.")
-
- if default is not NOTHING and factory is not None:
- raise TypeError(
- "Must pass either `default` or `factory` but not both."
- )
-
- if factory is not None:
- default = Factory(factory)
-
- if isinstance(default, Factory):
- if default.takes_self:
- raise ValueError(
- "`takes_self` is not supported by default_if_none."
- )
-
- def default_if_none_converter(val):
- if val is not None:
- return val
-
- return default.factory()
-
- else:
-
- def default_if_none_converter(val):
- if val is not None:
- return val
-
- return default
-
- return default_if_none_converter
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/converters.pyi b/server_addon/fusion/client/ayon_fusion/vendor/attr/converters.pyi
deleted file mode 100644
index 84a57590b0..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/converters.pyi
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Callable, Optional, TypeVar, overload
-
-from . import _ConverterType
-
-
-_T = TypeVar("_T")
-
-def pipe(*validators: _ConverterType) -> _ConverterType: ...
-def optional(converter: _ConverterType) -> _ConverterType: ...
-@overload
-def default_if_none(default: _T) -> _ConverterType: ...
-@overload
-def default_if_none(*, factory: Callable[[], _T]) -> _ConverterType: ...
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/exceptions.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/exceptions.py
deleted file mode 100644
index f6f9861bea..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/exceptions.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from __future__ import absolute_import, division, print_function
-
-
-class FrozenError(AttributeError):
- """
- A frozen/immutable instance or attribute have been attempted to be
- modified.
-
- It mirrors the behavior of ``namedtuples`` by using the same error message
- and subclassing `AttributeError`.
-
- .. versionadded:: 20.1.0
- """
-
- msg = "can't set attribute"
- args = [msg]
-
-
-class FrozenInstanceError(FrozenError):
- """
- A frozen instance has been attempted to be modified.
-
- .. versionadded:: 16.1.0
- """
-
-
-class FrozenAttributeError(FrozenError):
- """
- A frozen attribute has been attempted to be modified.
-
- .. versionadded:: 20.1.0
- """
-
-
-class AttrsAttributeNotFoundError(ValueError):
- """
- An ``attrs`` function couldn't find an attribute that the user asked for.
-
- .. versionadded:: 16.2.0
- """
-
-
-class NotAnAttrsClassError(ValueError):
- """
- A non-``attrs`` class has been passed into an ``attrs`` function.
-
- .. versionadded:: 16.2.0
- """
-
-
-class DefaultAlreadySetError(RuntimeError):
- """
- A default has been set using ``attr.ib()`` and is attempted to be reset
- using the decorator.
-
- .. versionadded:: 17.1.0
- """
-
-
-class UnannotatedAttributeError(RuntimeError):
- """
- A class with ``auto_attribs=True`` has an ``attr.ib()`` without a type
- annotation.
-
- .. versionadded:: 17.3.0
- """
-
-
-class PythonTooOldError(RuntimeError):
- """
- It was attempted to use an ``attrs`` feature that requires a newer Python
- version.
-
- .. versionadded:: 18.2.0
- """
-
-
-class NotCallableError(TypeError):
- """
- A ``attr.ib()`` requiring a callable has been set with a value
- that is not callable.
-
- .. versionadded:: 19.2.0
- """
-
- def __init__(self, msg, value):
- super(TypeError, self).__init__(msg, value)
- self.msg = msg
- self.value = value
-
- def __str__(self):
- return str(self.msg)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/exceptions.pyi b/server_addon/fusion/client/ayon_fusion/vendor/attr/exceptions.pyi
deleted file mode 100644
index a800fb26bb..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/exceptions.pyi
+++ /dev/null
@@ -1,18 +0,0 @@
-from typing import Any
-
-
-class FrozenError(AttributeError):
- msg: str = ...
-
-class FrozenInstanceError(FrozenError): ...
-class FrozenAttributeError(FrozenError): ...
-class AttrsAttributeNotFoundError(ValueError): ...
-class NotAnAttrsClassError(ValueError): ...
-class DefaultAlreadySetError(RuntimeError): ...
-class UnannotatedAttributeError(RuntimeError): ...
-class PythonTooOldError(RuntimeError): ...
-
-class NotCallableError(TypeError):
- msg: str = ...
- value: Any = ...
- def __init__(self, msg: str, value: Any) -> None: ...
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/filters.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/filters.py
deleted file mode 100644
index dc47e8fa38..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/filters.py
+++ /dev/null
@@ -1,52 +0,0 @@
-"""
-Commonly useful filters for `attr.asdict`.
-"""
-
-from __future__ import absolute_import, division, print_function
-
-from ._compat import isclass
-from ._make import Attribute
-
-
-def _split_what(what):
- """
- Returns a tuple of `frozenset`s of classes and attributes.
- """
- return (
- frozenset(cls for cls in what if isclass(cls)),
- frozenset(cls for cls in what if isinstance(cls, Attribute)),
- )
-
-
-def include(*what):
- """
- Whitelist *what*.
-
- :param what: What to whitelist.
- :type what: `list` of `type` or `attr.Attribute`\\ s
-
- :rtype: `callable`
- """
- cls, attrs = _split_what(what)
-
- def include_(attribute, value):
- return value.__class__ in cls or attribute in attrs
-
- return include_
-
-
-def exclude(*what):
- """
- Blacklist *what*.
-
- :param what: What to blacklist.
- :type what: `list` of classes or `attr.Attribute`\\ s.
-
- :rtype: `callable`
- """
- cls, attrs = _split_what(what)
-
- def exclude_(attribute, value):
- return value.__class__ not in cls and attribute not in attrs
-
- return exclude_
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/filters.pyi b/server_addon/fusion/client/ayon_fusion/vendor/attr/filters.pyi
deleted file mode 100644
index f7b63f1bb4..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/filters.pyi
+++ /dev/null
@@ -1,7 +0,0 @@
-from typing import Any, Union
-
-from . import Attribute, _FilterType
-
-
-def include(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
-def exclude(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/py.typed b/server_addon/fusion/client/ayon_fusion/vendor/attr/py.typed
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/setters.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/setters.py
deleted file mode 100644
index 240014b3c1..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/setters.py
+++ /dev/null
@@ -1,77 +0,0 @@
-"""
-Commonly used hooks for on_setattr.
-"""
-
-from __future__ import absolute_import, division, print_function
-
-from . import _config
-from .exceptions import FrozenAttributeError
-
-
-def pipe(*setters):
- """
- Run all *setters* and return the return value of the last one.
-
- .. versionadded:: 20.1.0
- """
-
- def wrapped_pipe(instance, attrib, new_value):
- rv = new_value
-
- for setter in setters:
- rv = setter(instance, attrib, rv)
-
- return rv
-
- return wrapped_pipe
-
-
-def frozen(_, __, ___):
- """
- Prevent an attribute to be modified.
-
- .. versionadded:: 20.1.0
- """
- raise FrozenAttributeError()
-
-
-def validate(instance, attrib, new_value):
- """
- Run *attrib*'s validator on *new_value* if it has one.
-
- .. versionadded:: 20.1.0
- """
- if _config._run_validators is False:
- return new_value
-
- v = attrib.validator
- if not v:
- return new_value
-
- v(instance, attrib, new_value)
-
- return new_value
-
-
-def convert(instance, attrib, new_value):
- """
- Run *attrib*'s converter -- if it has one -- on *new_value* and return the
- result.
-
- .. versionadded:: 20.1.0
- """
- c = attrib.converter
- if c:
- return c(new_value)
-
- return new_value
-
-
-NO_OP = object()
-"""
-Sentinel for disabling class-wide *on_setattr* hooks for certain attributes.
-
-Does not work in `pipe` or within lists.
-
-.. versionadded:: 20.1.0
-"""
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/setters.pyi b/server_addon/fusion/client/ayon_fusion/vendor/attr/setters.pyi
deleted file mode 100644
index a921e07deb..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/setters.pyi
+++ /dev/null
@@ -1,20 +0,0 @@
-from typing import Any, NewType, NoReturn, TypeVar, cast
-
-from . import Attribute, _OnSetAttrType
-
-
-_T = TypeVar("_T")
-
-def frozen(
- instance: Any, attribute: Attribute[Any], new_value: Any
-) -> NoReturn: ...
-def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ...
-def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ...
-
-# convert is allowed to return Any, because they can be chained using pipe.
-def convert(
- instance: Any, attribute: Attribute[Any], new_value: Any
-) -> Any: ...
-
-_NoOpType = NewType("_NoOpType", object)
-NO_OP: _NoOpType
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/validators.py b/server_addon/fusion/client/ayon_fusion/vendor/attr/validators.py
deleted file mode 100644
index b9a73054e9..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/validators.py
+++ /dev/null
@@ -1,379 +0,0 @@
-"""
-Commonly useful validators.
-"""
-
-from __future__ import absolute_import, division, print_function
-
-import re
-
-from ._make import _AndValidator, and_, attrib, attrs
-from .exceptions import NotCallableError
-
-
-__all__ = [
- "and_",
- "deep_iterable",
- "deep_mapping",
- "in_",
- "instance_of",
- "is_callable",
- "matches_re",
- "optional",
- "provides",
-]
-
-
-@attrs(repr=False, slots=True, hash=True)
-class _InstanceOfValidator(object):
- type = attrib()
-
- def __call__(self, inst, attr, value):
- """
- We use a callable class to be able to change the ``__repr__``.
- """
- if not isinstance(value, self.type):
- raise TypeError(
- "'{name}' must be {type!r} (got {value!r} that is a "
- "{actual!r}).".format(
- name=attr.name,
- type=self.type,
- actual=value.__class__,
- value=value,
- ),
- attr,
- self.type,
- value,
- )
-
- def __repr__(self):
- return "".format(
- type=self.type
- )
-
-
-def instance_of(type):
- """
- A validator that raises a `TypeError` if the initializer is called
- with a wrong type for this particular attribute (checks are performed using
- `isinstance` therefore it's also valid to pass a tuple of types).
-
- :param type: The type to check for.
- :type type: type or tuple of types
-
- :raises TypeError: With a human readable error message, the attribute
- (of type `attr.Attribute`), the expected type, and the value it
- got.
- """
- return _InstanceOfValidator(type)
-
-
-@attrs(repr=False, frozen=True, slots=True)
-class _MatchesReValidator(object):
- regex = attrib()
- flags = attrib()
- match_func = attrib()
-
- def __call__(self, inst, attr, value):
- """
- We use a callable class to be able to change the ``__repr__``.
- """
- if not self.match_func(value):
- raise ValueError(
- "'{name}' must match regex {regex!r}"
- " ({value!r} doesn't)".format(
- name=attr.name, regex=self.regex.pattern, value=value
- ),
- attr,
- self.regex,
- value,
- )
-
- def __repr__(self):
- return "".format(
- regex=self.regex
- )
-
-
-def matches_re(regex, flags=0, func=None):
- r"""
- A validator that raises `ValueError` if the initializer is called
- with a string that doesn't match *regex*.
-
- :param str regex: a regex string to match against
- :param int flags: flags that will be passed to the underlying re function
- (default 0)
- :param callable func: which underlying `re` function to call (options
- are `re.fullmatch`, `re.search`, `re.match`, default
- is ``None`` which means either `re.fullmatch` or an emulation of
- it on Python 2). For performance reasons, they won't be used directly
- but on a pre-`re.compile`\ ed pattern.
-
- .. versionadded:: 19.2.0
- """
- fullmatch = getattr(re, "fullmatch", None)
- valid_funcs = (fullmatch, None, re.search, re.match)
- if func not in valid_funcs:
- raise ValueError(
- "'func' must be one of %s."
- % (
- ", ".join(
- sorted(
- e and e.__name__ or "None" for e in set(valid_funcs)
- )
- ),
- )
- )
-
- pattern = re.compile(regex, flags)
- if func is re.match:
- match_func = pattern.match
- elif func is re.search:
- match_func = pattern.search
- else:
- if fullmatch:
- match_func = pattern.fullmatch
- else:
- pattern = re.compile(r"(?:{})\Z".format(regex), flags)
- match_func = pattern.match
-
- return _MatchesReValidator(pattern, flags, match_func)
-
-
-@attrs(repr=False, slots=True, hash=True)
-class _ProvidesValidator(object):
- interface = attrib()
-
- def __call__(self, inst, attr, value):
- """
- We use a callable class to be able to change the ``__repr__``.
- """
- if not self.interface.providedBy(value):
- raise TypeError(
- "'{name}' must provide {interface!r} which {value!r} "
- "doesn't.".format(
- name=attr.name, interface=self.interface, value=value
- ),
- attr,
- self.interface,
- value,
- )
-
- def __repr__(self):
- return "".format(
- interface=self.interface
- )
-
-
-def provides(interface):
- """
- A validator that raises a `TypeError` if the initializer is called
- with an object that does not provide the requested *interface* (checks are
- performed using ``interface.providedBy(value)`` (see `zope.interface
- `_).
-
- :param interface: The interface to check for.
- :type interface: ``zope.interface.Interface``
-
- :raises TypeError: With a human readable error message, the attribute
- (of type `attr.Attribute`), the expected interface, and the
- value it got.
- """
- return _ProvidesValidator(interface)
-
-
-@attrs(repr=False, slots=True, hash=True)
-class _OptionalValidator(object):
- validator = attrib()
-
- def __call__(self, inst, attr, value):
- if value is None:
- return
-
- self.validator(inst, attr, value)
-
- def __repr__(self):
- return "".format(
- what=repr(self.validator)
- )
-
-
-def optional(validator):
- """
- A validator that makes an attribute optional. An optional attribute is one
- which can be set to ``None`` in addition to satisfying the requirements of
- the sub-validator.
-
- :param validator: A validator (or a list of validators) that is used for
- non-``None`` values.
- :type validator: callable or `list` of callables.
-
- .. versionadded:: 15.1.0
- .. versionchanged:: 17.1.0 *validator* can be a list of validators.
- """
- if isinstance(validator, list):
- return _OptionalValidator(_AndValidator(validator))
- return _OptionalValidator(validator)
-
-
-@attrs(repr=False, slots=True, hash=True)
-class _InValidator(object):
- options = attrib()
-
- def __call__(self, inst, attr, value):
- try:
- in_options = value in self.options
- except TypeError: # e.g. `1 in "abc"`
- in_options = False
-
- if not in_options:
- raise ValueError(
- "'{name}' must be in {options!r} (got {value!r})".format(
- name=attr.name, options=self.options, value=value
- )
- )
-
- def __repr__(self):
- return "".format(
- options=self.options
- )
-
-
-def in_(options):
- """
- A validator that raises a `ValueError` if the initializer is called
- with a value that does not belong in the options provided. The check is
- performed using ``value in options``.
-
- :param options: Allowed options.
- :type options: list, tuple, `enum.Enum`, ...
-
- :raises ValueError: With a human readable error message, the attribute (of
- type `attr.Attribute`), the expected options, and the value it
- got.
-
- .. versionadded:: 17.1.0
- """
- return _InValidator(options)
-
-
-@attrs(repr=False, slots=False, hash=True)
-class _IsCallableValidator(object):
- def __call__(self, inst, attr, value):
- """
- We use a callable class to be able to change the ``__repr__``.
- """
- if not callable(value):
- message = (
- "'{name}' must be callable "
- "(got {value!r} that is a {actual!r})."
- )
- raise NotCallableError(
- msg=message.format(
- name=attr.name, value=value, actual=value.__class__
- ),
- value=value,
- )
-
- def __repr__(self):
- return ""
-
-
-def is_callable():
- """
- A validator that raises a `attr.exceptions.NotCallableError` if the
- initializer is called with a value for this particular attribute
- that is not callable.
-
- .. versionadded:: 19.1.0
-
- :raises `attr.exceptions.NotCallableError`: With a human readable error
- message containing the attribute (`attr.Attribute`) name,
- and the value it got.
- """
- return _IsCallableValidator()
-
-
-@attrs(repr=False, slots=True, hash=True)
-class _DeepIterable(object):
- member_validator = attrib(validator=is_callable())
- iterable_validator = attrib(
- default=None, validator=optional(is_callable())
- )
-
- def __call__(self, inst, attr, value):
- """
- We use a callable class to be able to change the ``__repr__``.
- """
- if self.iterable_validator is not None:
- self.iterable_validator(inst, attr, value)
-
- for member in value:
- self.member_validator(inst, attr, member)
-
- def __repr__(self):
- iterable_identifier = (
- ""
- if self.iterable_validator is None
- else " {iterable!r}".format(iterable=self.iterable_validator)
- )
- return (
- ""
- ).format(
- iterable_identifier=iterable_identifier,
- member=self.member_validator,
- )
-
-
-def deep_iterable(member_validator, iterable_validator=None):
- """
- A validator that performs deep validation of an iterable.
-
- :param member_validator: Validator to apply to iterable members
- :param iterable_validator: Validator to apply to iterable itself
- (optional)
-
- .. versionadded:: 19.1.0
-
- :raises TypeError: if any sub-validators fail
- """
- return _DeepIterable(member_validator, iterable_validator)
-
-
-@attrs(repr=False, slots=True, hash=True)
-class _DeepMapping(object):
- key_validator = attrib(validator=is_callable())
- value_validator = attrib(validator=is_callable())
- mapping_validator = attrib(default=None, validator=optional(is_callable()))
-
- def __call__(self, inst, attr, value):
- """
- We use a callable class to be able to change the ``__repr__``.
- """
- if self.mapping_validator is not None:
- self.mapping_validator(inst, attr, value)
-
- for key in value:
- self.key_validator(inst, attr, key)
- self.value_validator(inst, attr, value[key])
-
- def __repr__(self):
- return (
- ""
- ).format(key=self.key_validator, value=self.value_validator)
-
-
-def deep_mapping(key_validator, value_validator, mapping_validator=None):
- """
- A validator that performs deep validation of a dictionary.
-
- :param key_validator: Validator to apply to dictionary keys
- :param value_validator: Validator to apply to dictionary values
- :param mapping_validator: Validator to apply to top-level mapping
- attribute (optional)
-
- .. versionadded:: 19.1.0
-
- :raises TypeError: if any sub-validators fail
- """
- return _DeepMapping(key_validator, value_validator, mapping_validator)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/attr/validators.pyi b/server_addon/fusion/client/ayon_fusion/vendor/attr/validators.pyi
deleted file mode 100644
index fe92aac421..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/attr/validators.pyi
+++ /dev/null
@@ -1,68 +0,0 @@
-from typing import (
- Any,
- AnyStr,
- Callable,
- Container,
- Iterable,
- List,
- Mapping,
- Match,
- Optional,
- Tuple,
- Type,
- TypeVar,
- Union,
- overload,
-)
-
-from . import _ValidatorType
-
-
-_T = TypeVar("_T")
-_T1 = TypeVar("_T1")
-_T2 = TypeVar("_T2")
-_T3 = TypeVar("_T3")
-_I = TypeVar("_I", bound=Iterable)
-_K = TypeVar("_K")
-_V = TypeVar("_V")
-_M = TypeVar("_M", bound=Mapping)
-
-# To be more precise on instance_of use some overloads.
-# If there are more than 3 items in the tuple then we fall back to Any
-@overload
-def instance_of(type: Type[_T]) -> _ValidatorType[_T]: ...
-@overload
-def instance_of(type: Tuple[Type[_T]]) -> _ValidatorType[_T]: ...
-@overload
-def instance_of(
- type: Tuple[Type[_T1], Type[_T2]]
-) -> _ValidatorType[Union[_T1, _T2]]: ...
-@overload
-def instance_of(
- type: Tuple[Type[_T1], Type[_T2], Type[_T3]]
-) -> _ValidatorType[Union[_T1, _T2, _T3]]: ...
-@overload
-def instance_of(type: Tuple[type, ...]) -> _ValidatorType[Any]: ...
-def provides(interface: Any) -> _ValidatorType[Any]: ...
-def optional(
- validator: Union[_ValidatorType[_T], List[_ValidatorType[_T]]]
-) -> _ValidatorType[Optional[_T]]: ...
-def in_(options: Container[_T]) -> _ValidatorType[_T]: ...
-def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ...
-def matches_re(
- regex: AnyStr,
- flags: int = ...,
- func: Optional[
- Callable[[AnyStr, AnyStr, int], Optional[Match[AnyStr]]]
- ] = ...,
-) -> _ValidatorType[AnyStr]: ...
-def deep_iterable(
- member_validator: _ValidatorType[_T],
- iterable_validator: Optional[_ValidatorType[_I]] = ...,
-) -> _ValidatorType[_I]: ...
-def deep_mapping(
- key_validator: _ValidatorType[_K],
- value_validator: _ValidatorType[_V],
- mapping_validator: Optional[_ValidatorType[_M]] = ...,
-) -> _ValidatorType[_M]: ...
-def is_callable() -> _ValidatorType[_T]: ...
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/__init__.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/__init__.py
deleted file mode 100644
index fe86b59d78..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/__init__.py
+++ /dev/null
@@ -1,85 +0,0 @@
-"""
-Python HTTP library with thread-safe connection pooling, file post support, user friendly, and more
-"""
-from __future__ import absolute_import
-
-# Set default logging handler to avoid "No handler found" warnings.
-import logging
-import warnings
-from logging import NullHandler
-
-from . import exceptions
-from ._version import __version__
-from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url
-from .filepost import encode_multipart_formdata
-from .poolmanager import PoolManager, ProxyManager, proxy_from_url
-from .response import HTTPResponse
-from .util.request import make_headers
-from .util.retry import Retry
-from .util.timeout import Timeout
-from .util.url import get_host
-
-__author__ = "Andrey Petrov (andrey.petrov@shazow.net)"
-__license__ = "MIT"
-__version__ = __version__
-
-__all__ = (
- "HTTPConnectionPool",
- "HTTPSConnectionPool",
- "PoolManager",
- "ProxyManager",
- "HTTPResponse",
- "Retry",
- "Timeout",
- "add_stderr_logger",
- "connection_from_url",
- "disable_warnings",
- "encode_multipart_formdata",
- "get_host",
- "make_headers",
- "proxy_from_url",
-)
-
-logging.getLogger(__name__).addHandler(NullHandler())
-
-
-def add_stderr_logger(level=logging.DEBUG):
- """
- Helper for quickly adding a StreamHandler to the logger. Useful for
- debugging.
-
- Returns the handler after adding it.
- """
- # This method needs to be in this __init__.py to get the __name__ correct
- # even if urllib3 is vendored within another package.
- logger = logging.getLogger(__name__)
- handler = logging.StreamHandler()
- handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
- logger.addHandler(handler)
- logger.setLevel(level)
- logger.debug("Added a stderr logging handler to logger: %s", __name__)
- return handler
-
-
-# ... Clean up.
-del NullHandler
-
-
-# All warning filters *must* be appended unless you're really certain that they
-# shouldn't be: otherwise, it's very hard for users to use most Python
-# mechanisms to silence them.
-# SecurityWarning's always go off by default.
-warnings.simplefilter("always", exceptions.SecurityWarning, append=True)
-# SubjectAltNameWarning's should go off once per host
-warnings.simplefilter("default", exceptions.SubjectAltNameWarning, append=True)
-# InsecurePlatformWarning's don't vary between requests, so we keep it default.
-warnings.simplefilter("default", exceptions.InsecurePlatformWarning, append=True)
-# SNIMissingWarnings should go off only once.
-warnings.simplefilter("default", exceptions.SNIMissingWarning, append=True)
-
-
-def disable_warnings(category=exceptions.HTTPWarning):
- """
- Helper for quickly disabling all urllib3 warnings.
- """
- warnings.simplefilter("ignore", category)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/_collections.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/_collections.py
deleted file mode 100644
index da9857e986..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/_collections.py
+++ /dev/null
@@ -1,337 +0,0 @@
-from __future__ import absolute_import
-
-try:
- from collections.abc import Mapping, MutableMapping
-except ImportError:
- from collections import Mapping, MutableMapping
-try:
- from threading import RLock
-except ImportError: # Platform-specific: No threads available
-
- class RLock:
- def __enter__(self):
- pass
-
- def __exit__(self, exc_type, exc_value, traceback):
- pass
-
-
-from collections import OrderedDict
-
-from .exceptions import InvalidHeader
-from .packages import six
-from .packages.six import iterkeys, itervalues
-
-__all__ = ["RecentlyUsedContainer", "HTTPHeaderDict"]
-
-
-_Null = object()
-
-
-class RecentlyUsedContainer(MutableMapping):
- """
- Provides a thread-safe dict-like container which maintains up to
- ``maxsize`` keys while throwing away the least-recently-used keys beyond
- ``maxsize``.
-
- :param maxsize:
- Maximum number of recent elements to retain.
-
- :param dispose_func:
- Every time an item is evicted from the container,
- ``dispose_func(value)`` is called. Callback which will get called
- """
-
- ContainerCls = OrderedDict
-
- def __init__(self, maxsize=10, dispose_func=None):
- self._maxsize = maxsize
- self.dispose_func = dispose_func
-
- self._container = self.ContainerCls()
- self.lock = RLock()
-
- def __getitem__(self, key):
- # Re-insert the item, moving it to the end of the eviction line.
- with self.lock:
- item = self._container.pop(key)
- self._container[key] = item
- return item
-
- def __setitem__(self, key, value):
- evicted_value = _Null
- with self.lock:
- # Possibly evict the existing value of 'key'
- evicted_value = self._container.get(key, _Null)
- self._container[key] = value
-
- # If we didn't evict an existing value, we might have to evict the
- # least recently used item from the beginning of the container.
- if len(self._container) > self._maxsize:
- _key, evicted_value = self._container.popitem(last=False)
-
- if self.dispose_func and evicted_value is not _Null:
- self.dispose_func(evicted_value)
-
- def __delitem__(self, key):
- with self.lock:
- value = self._container.pop(key)
-
- if self.dispose_func:
- self.dispose_func(value)
-
- def __len__(self):
- with self.lock:
- return len(self._container)
-
- def __iter__(self):
- raise NotImplementedError(
- "Iteration over this class is unlikely to be threadsafe."
- )
-
- def clear(self):
- with self.lock:
- # Copy pointers to all values, then wipe the mapping
- values = list(itervalues(self._container))
- self._container.clear()
-
- if self.dispose_func:
- for value in values:
- self.dispose_func(value)
-
- def keys(self):
- with self.lock:
- return list(iterkeys(self._container))
-
-
-class HTTPHeaderDict(MutableMapping):
- """
- :param headers:
- An iterable of field-value pairs. Must not contain multiple field names
- when compared case-insensitively.
-
- :param kwargs:
- Additional field-value pairs to pass in to ``dict.update``.
-
- A ``dict`` like container for storing HTTP Headers.
-
- Field names are stored and compared case-insensitively in compliance with
- RFC 7230. Iteration provides the first case-sensitive key seen for each
- case-insensitive pair.
-
- Using ``__setitem__`` syntax overwrites fields that compare equal
- case-insensitively in order to maintain ``dict``'s api. For fields that
- compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add``
- in a loop.
-
- If multiple fields that are equal case-insensitively are passed to the
- constructor or ``.update``, the behavior is undefined and some will be
- lost.
-
- >>> headers = HTTPHeaderDict()
- >>> headers.add('Set-Cookie', 'foo=bar')
- >>> headers.add('set-cookie', 'baz=quxx')
- >>> headers['content-length'] = '7'
- >>> headers['SET-cookie']
- 'foo=bar, baz=quxx'
- >>> headers['Content-Length']
- '7'
- """
-
- def __init__(self, headers=None, **kwargs):
- super(HTTPHeaderDict, self).__init__()
- self._container = OrderedDict()
- if headers is not None:
- if isinstance(headers, HTTPHeaderDict):
- self._copy_from(headers)
- else:
- self.extend(headers)
- if kwargs:
- self.extend(kwargs)
-
- def __setitem__(self, key, val):
- self._container[key.lower()] = [key, val]
- return self._container[key.lower()]
-
- def __getitem__(self, key):
- val = self._container[key.lower()]
- return ", ".join(val[1:])
-
- def __delitem__(self, key):
- del self._container[key.lower()]
-
- def __contains__(self, key):
- return key.lower() in self._container
-
- def __eq__(self, other):
- if not isinstance(other, Mapping) and not hasattr(other, "keys"):
- return False
- if not isinstance(other, type(self)):
- other = type(self)(other)
- return dict((k.lower(), v) for k, v in self.itermerged()) == dict(
- (k.lower(), v) for k, v in other.itermerged()
- )
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
- if six.PY2: # Python 2
- iterkeys = MutableMapping.iterkeys
- itervalues = MutableMapping.itervalues
-
- __marker = object()
-
- def __len__(self):
- return len(self._container)
-
- def __iter__(self):
- # Only provide the originally cased names
- for vals in self._container.values():
- yield vals[0]
-
- def pop(self, key, default=__marker):
- """D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
- If key is not found, d is returned if given, otherwise KeyError is raised.
- """
- # Using the MutableMapping function directly fails due to the private marker.
- # Using ordinary dict.pop would expose the internal structures.
- # So let's reinvent the wheel.
- try:
- value = self[key]
- except KeyError:
- if default is self.__marker:
- raise
- return default
- else:
- del self[key]
- return value
-
- def discard(self, key):
- try:
- del self[key]
- except KeyError:
- pass
-
- def add(self, key, val):
- """Adds a (name, value) pair, doesn't overwrite the value if it already
- exists.
-
- >>> headers = HTTPHeaderDict(foo='bar')
- >>> headers.add('Foo', 'baz')
- >>> headers['foo']
- 'bar, baz'
- """
- key_lower = key.lower()
- new_vals = [key, val]
- # Keep the common case aka no item present as fast as possible
- vals = self._container.setdefault(key_lower, new_vals)
- if new_vals is not vals:
- vals.append(val)
-
- def extend(self, *args, **kwargs):
- """Generic import function for any type of header-like object.
- Adapted version of MutableMapping.update in order to insert items
- with self.add instead of self.__setitem__
- """
- if len(args) > 1:
- raise TypeError(
- "extend() takes at most 1 positional "
- "arguments ({0} given)".format(len(args))
- )
- other = args[0] if len(args) >= 1 else ()
-
- if isinstance(other, HTTPHeaderDict):
- for key, val in other.iteritems():
- self.add(key, val)
- elif isinstance(other, Mapping):
- for key in other:
- self.add(key, other[key])
- elif hasattr(other, "keys"):
- for key in other.keys():
- self.add(key, other[key])
- else:
- for key, value in other:
- self.add(key, value)
-
- for key, value in kwargs.items():
- self.add(key, value)
-
- def getlist(self, key, default=__marker):
- """Returns a list of all the values for the named field. Returns an
- empty list if the key doesn't exist."""
- try:
- vals = self._container[key.lower()]
- except KeyError:
- if default is self.__marker:
- return []
- return default
- else:
- return vals[1:]
-
- # Backwards compatibility for httplib
- getheaders = getlist
- getallmatchingheaders = getlist
- iget = getlist
-
- # Backwards compatibility for http.cookiejar
- get_all = getlist
-
- def __repr__(self):
- return "%s(%s)" % (type(self).__name__, dict(self.itermerged()))
-
- def _copy_from(self, other):
- for key in other:
- val = other.getlist(key)
- if isinstance(val, list):
- # Don't need to convert tuples
- val = list(val)
- self._container[key.lower()] = [key] + val
-
- def copy(self):
- clone = type(self)()
- clone._copy_from(self)
- return clone
-
- def iteritems(self):
- """Iterate over all header lines, including duplicate ones."""
- for key in self:
- vals = self._container[key.lower()]
- for val in vals[1:]:
- yield vals[0], val
-
- def itermerged(self):
- """Iterate over all headers, merging duplicate ones together."""
- for key in self:
- val = self._container[key.lower()]
- yield val[0], ", ".join(val[1:])
-
- def items(self):
- return list(self.iteritems())
-
- @classmethod
- def from_httplib(cls, message): # Python 2
- """Read headers from a Python 2 httplib message object."""
- # python2.7 does not expose a proper API for exporting multiheaders
- # efficiently. This function re-reads raw lines from the message
- # object and extracts the multiheaders properly.
- obs_fold_continued_leaders = (" ", "\t")
- headers = []
-
- for line in message.headers:
- if line.startswith(obs_fold_continued_leaders):
- if not headers:
- # We received a header line that starts with OWS as described
- # in RFC-7230 S3.2.4. This indicates a multiline header, but
- # there exists no previous header to which we can attach it.
- raise InvalidHeader(
- "Header continuation with no previous header: %s" % line
- )
- else:
- key, value = headers[-1]
- headers[-1] = (key, value + " " + line.strip())
- continue
-
- key, value = line.split(":", 1)
- headers.append((key, value.strip()))
-
- return cls(headers)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/_version.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/_version.py
deleted file mode 100644
index e8ebee957f..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/_version.py
+++ /dev/null
@@ -1,2 +0,0 @@
-# This file is protected via CODEOWNERS
-__version__ = "1.26.6"
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/connection.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/connection.py
deleted file mode 100644
index 4c996659c8..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/connection.py
+++ /dev/null
@@ -1,539 +0,0 @@
-from __future__ import absolute_import
-
-import datetime
-import logging
-import os
-import re
-import socket
-import warnings
-from socket import error as SocketError
-from socket import timeout as SocketTimeout
-
-from .packages import six
-from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection
-from .packages.six.moves.http_client import HTTPException # noqa: F401
-from .util.proxy import create_proxy_ssl_context
-
-try: # Compiled with SSL?
- import ssl
-
- BaseSSLError = ssl.SSLError
-except (ImportError, AttributeError): # Platform-specific: No SSL.
- ssl = None
-
- class BaseSSLError(BaseException):
- pass
-
-
-try:
- # Python 3: not a no-op, we're adding this to the namespace so it can be imported.
- ConnectionError = ConnectionError
-except NameError:
- # Python 2
- class ConnectionError(Exception):
- pass
-
-
-try: # Python 3:
- # Not a no-op, we're adding this to the namespace so it can be imported.
- BrokenPipeError = BrokenPipeError
-except NameError: # Python 2:
-
- class BrokenPipeError(Exception):
- pass
-
-
-from ._collections import HTTPHeaderDict # noqa (historical, removed in v2)
-from ._version import __version__
-from .exceptions import (
- ConnectTimeoutError,
- NewConnectionError,
- SubjectAltNameWarning,
- SystemTimeWarning,
-)
-from .packages.ssl_match_hostname import CertificateError, match_hostname
-from .util import SKIP_HEADER, SKIPPABLE_HEADERS, connection
-from .util.ssl_ import (
- assert_fingerprint,
- create_urllib3_context,
- resolve_cert_reqs,
- resolve_ssl_version,
- ssl_wrap_socket,
-)
-
-log = logging.getLogger(__name__)
-
-port_by_scheme = {"http": 80, "https": 443}
-
-# When it comes time to update this value as a part of regular maintenance
-# (ie test_recent_date is failing) update it to ~6 months before the current date.
-RECENT_DATE = datetime.date(2020, 7, 1)
-
-_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")
-
-
-class HTTPConnection(_HTTPConnection, object):
- """
- Based on :class:`http.client.HTTPConnection` but provides an extra constructor
- backwards-compatibility layer between older and newer Pythons.
-
- Additional keyword parameters are used to configure attributes of the connection.
- Accepted parameters include:
-
- - ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool`
- - ``source_address``: Set the source address for the current connection.
- - ``socket_options``: Set specific options on the underlying socket. If not specified, then
- defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling
- Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy.
-
- For example, if you wish to enable TCP Keep Alive in addition to the defaults,
- you might pass:
-
- .. code-block:: python
-
- HTTPConnection.default_socket_options + [
- (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
- ]
-
- Or you may want to disable the defaults by passing an empty list (e.g., ``[]``).
- """
-
- default_port = port_by_scheme["http"]
-
- #: Disable Nagle's algorithm by default.
- #: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]``
- default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]
-
- #: Whether this connection verifies the host's certificate.
- is_verified = False
-
- def __init__(self, *args, **kw):
- if not six.PY2:
- kw.pop("strict", None)
-
- # Pre-set source_address.
- self.source_address = kw.get("source_address")
-
- #: The socket options provided by the user. If no options are
- #: provided, we use the default options.
- self.socket_options = kw.pop("socket_options", self.default_socket_options)
-
- # Proxy options provided by the user.
- self.proxy = kw.pop("proxy", None)
- self.proxy_config = kw.pop("proxy_config", None)
-
- _HTTPConnection.__init__(self, *args, **kw)
-
- @property
- def host(self):
- """
- Getter method to remove any trailing dots that indicate the hostname is an FQDN.
-
- In general, SSL certificates don't include the trailing dot indicating a
- fully-qualified domain name, and thus, they don't validate properly when
- checked against a domain name that includes the dot. In addition, some
- servers may not expect to receive the trailing dot when provided.
-
- However, the hostname with trailing dot is critical to DNS resolution; doing a
- lookup with the trailing dot will properly only resolve the appropriate FQDN,
- whereas a lookup without a trailing dot will search the system's search domain
- list. Thus, it's important to keep the original host around for use only in
- those cases where it's appropriate (i.e., when doing DNS lookup to establish the
- actual TCP connection across which we're going to send HTTP requests).
- """
- return self._dns_host.rstrip(".")
-
- @host.setter
- def host(self, value):
- """
- Setter for the `host` property.
-
- We assume that only urllib3 uses the _dns_host attribute; httplib itself
- only uses `host`, and it seems reasonable that other libraries follow suit.
- """
- self._dns_host = value
-
- def _new_conn(self):
- """Establish a socket connection and set nodelay settings on it.
-
- :return: New socket connection.
- """
- extra_kw = {}
- if self.source_address:
- extra_kw["source_address"] = self.source_address
-
- if self.socket_options:
- extra_kw["socket_options"] = self.socket_options
-
- try:
- conn = connection.create_connection(
- (self._dns_host, self.port), self.timeout, **extra_kw
- )
-
- except SocketTimeout:
- raise ConnectTimeoutError(
- self,
- "Connection to %s timed out. (connect timeout=%s)"
- % (self.host, self.timeout),
- )
-
- except SocketError as e:
- raise NewConnectionError(
- self, "Failed to establish a new connection: %s" % e
- )
-
- return conn
-
- def _is_using_tunnel(self):
- # Google App Engine's httplib does not define _tunnel_host
- return getattr(self, "_tunnel_host", None)
-
- def _prepare_conn(self, conn):
- self.sock = conn
- if self._is_using_tunnel():
- # TODO: Fix tunnel so it doesn't depend on self.sock state.
- self._tunnel()
- # Mark this connection as not reusable
- self.auto_open = 0
-
- def connect(self):
- conn = self._new_conn()
- self._prepare_conn(conn)
-
- def putrequest(self, method, url, *args, **kwargs):
- """ """
- # Empty docstring because the indentation of CPython's implementation
- # is broken but we don't want this method in our documentation.
- match = _CONTAINS_CONTROL_CHAR_RE.search(method)
- if match:
- raise ValueError(
- "Method cannot contain non-token characters %r (found at least %r)"
- % (method, match.group())
- )
-
- return _HTTPConnection.putrequest(self, method, url, *args, **kwargs)
-
- def putheader(self, header, *values):
- """ """
- if not any(isinstance(v, str) and v == SKIP_HEADER for v in values):
- _HTTPConnection.putheader(self, header, *values)
- elif six.ensure_str(header.lower()) not in SKIPPABLE_HEADERS:
- raise ValueError(
- "urllib3.util.SKIP_HEADER only supports '%s'"
- % ("', '".join(map(str.title, sorted(SKIPPABLE_HEADERS))),)
- )
-
- def request(self, method, url, body=None, headers=None):
- if headers is None:
- headers = {}
- else:
- # Avoid modifying the headers passed into .request()
- headers = headers.copy()
- if "user-agent" not in (six.ensure_str(k.lower()) for k in headers):
- headers["User-Agent"] = _get_default_user_agent()
- super(HTTPConnection, self).request(method, url, body=body, headers=headers)
-
- def request_chunked(self, method, url, body=None, headers=None):
- """
- Alternative to the common request method, which sends the
- body with chunked encoding and not as one block
- """
- headers = headers or {}
- header_keys = set([six.ensure_str(k.lower()) for k in headers])
- skip_accept_encoding = "accept-encoding" in header_keys
- skip_host = "host" in header_keys
- self.putrequest(
- method, url, skip_accept_encoding=skip_accept_encoding, skip_host=skip_host
- )
- if "user-agent" not in header_keys:
- self.putheader("User-Agent", _get_default_user_agent())
- for header, value in headers.items():
- self.putheader(header, value)
- if "transfer-encoding" not in header_keys:
- self.putheader("Transfer-Encoding", "chunked")
- self.endheaders()
-
- if body is not None:
- stringish_types = six.string_types + (bytes,)
- if isinstance(body, stringish_types):
- body = (body,)
- for chunk in body:
- if not chunk:
- continue
- if not isinstance(chunk, bytes):
- chunk = chunk.encode("utf8")
- len_str = hex(len(chunk))[2:]
- to_send = bytearray(len_str.encode())
- to_send += b"\r\n"
- to_send += chunk
- to_send += b"\r\n"
- self.send(to_send)
-
- # After the if clause, to always have a closed body
- self.send(b"0\r\n\r\n")
-
-
-class HTTPSConnection(HTTPConnection):
- """
- Many of the parameters to this constructor are passed to the underlying SSL
- socket by means of :py:func:`urllib3.util.ssl_wrap_socket`.
- """
-
- default_port = port_by_scheme["https"]
-
- cert_reqs = None
- ca_certs = None
- ca_cert_dir = None
- ca_cert_data = None
- ssl_version = None
- assert_fingerprint = None
- tls_in_tls_required = False
-
- def __init__(
- self,
- host,
- port=None,
- key_file=None,
- cert_file=None,
- key_password=None,
- strict=None,
- timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
- ssl_context=None,
- server_hostname=None,
- **kw
- ):
-
- HTTPConnection.__init__(self, host, port, strict=strict, timeout=timeout, **kw)
-
- self.key_file = key_file
- self.cert_file = cert_file
- self.key_password = key_password
- self.ssl_context = ssl_context
- self.server_hostname = server_hostname
-
- # Required property for Google AppEngine 1.9.0 which otherwise causes
- # HTTPS requests to go out as HTTP. (See Issue #356)
- self._protocol = "https"
-
- def set_cert(
- self,
- key_file=None,
- cert_file=None,
- cert_reqs=None,
- key_password=None,
- ca_certs=None,
- assert_hostname=None,
- assert_fingerprint=None,
- ca_cert_dir=None,
- ca_cert_data=None,
- ):
- """
- This method should only be called once, before the connection is used.
- """
- # If cert_reqs is not provided we'll assume CERT_REQUIRED unless we also
- # have an SSLContext object in which case we'll use its verify_mode.
- if cert_reqs is None:
- if self.ssl_context is not None:
- cert_reqs = self.ssl_context.verify_mode
- else:
- cert_reqs = resolve_cert_reqs(None)
-
- self.key_file = key_file
- self.cert_file = cert_file
- self.cert_reqs = cert_reqs
- self.key_password = key_password
- self.assert_hostname = assert_hostname
- self.assert_fingerprint = assert_fingerprint
- self.ca_certs = ca_certs and os.path.expanduser(ca_certs)
- self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir)
- self.ca_cert_data = ca_cert_data
-
- def connect(self):
- # Add certificate verification
- conn = self._new_conn()
- hostname = self.host
- tls_in_tls = False
-
- if self._is_using_tunnel():
- if self.tls_in_tls_required:
- conn = self._connect_tls_proxy(hostname, conn)
- tls_in_tls = True
-
- self.sock = conn
-
- # Calls self._set_hostport(), so self.host is
- # self._tunnel_host below.
- self._tunnel()
- # Mark this connection as not reusable
- self.auto_open = 0
-
- # Override the host with the one we're requesting data from.
- hostname = self._tunnel_host
-
- server_hostname = hostname
- if self.server_hostname is not None:
- server_hostname = self.server_hostname
-
- is_time_off = datetime.date.today() < RECENT_DATE
- if is_time_off:
- warnings.warn(
- (
- "System time is way off (before {0}). This will probably "
- "lead to SSL verification errors"
- ).format(RECENT_DATE),
- SystemTimeWarning,
- )
-
- # Wrap socket using verification with the root certs in
- # trusted_root_certs
- default_ssl_context = False
- if self.ssl_context is None:
- default_ssl_context = True
- self.ssl_context = create_urllib3_context(
- ssl_version=resolve_ssl_version(self.ssl_version),
- cert_reqs=resolve_cert_reqs(self.cert_reqs),
- )
-
- context = self.ssl_context
- context.verify_mode = resolve_cert_reqs(self.cert_reqs)
-
- # Try to load OS default certs if none are given.
- # Works well on Windows (requires Python3.4+)
- if (
- not self.ca_certs
- and not self.ca_cert_dir
- and not self.ca_cert_data
- and default_ssl_context
- and hasattr(context, "load_default_certs")
- ):
- context.load_default_certs()
-
- self.sock = ssl_wrap_socket(
- sock=conn,
- keyfile=self.key_file,
- certfile=self.cert_file,
- key_password=self.key_password,
- ca_certs=self.ca_certs,
- ca_cert_dir=self.ca_cert_dir,
- ca_cert_data=self.ca_cert_data,
- server_hostname=server_hostname,
- ssl_context=context,
- tls_in_tls=tls_in_tls,
- )
-
- # If we're using all defaults and the connection
- # is TLSv1 or TLSv1.1 we throw a DeprecationWarning
- # for the host.
- if (
- default_ssl_context
- and self.ssl_version is None
- and hasattr(self.sock, "version")
- and self.sock.version() in {"TLSv1", "TLSv1.1"}
- ):
- warnings.warn(
- "Negotiating TLSv1/TLSv1.1 by default is deprecated "
- "and will be disabled in urllib3 v2.0.0. Connecting to "
- "'%s' with '%s' can be enabled by explicitly opting-in "
- "with 'ssl_version'" % (self.host, self.sock.version()),
- DeprecationWarning,
- )
-
- if self.assert_fingerprint:
- assert_fingerprint(
- self.sock.getpeercert(binary_form=True), self.assert_fingerprint
- )
- elif (
- context.verify_mode != ssl.CERT_NONE
- and not getattr(context, "check_hostname", False)
- and self.assert_hostname is not False
- ):
- # While urllib3 attempts to always turn off hostname matching from
- # the TLS library, this cannot always be done. So we check whether
- # the TLS Library still thinks it's matching hostnames.
- cert = self.sock.getpeercert()
- if not cert.get("subjectAltName", ()):
- warnings.warn(
- (
- "Certificate for {0} has no `subjectAltName`, falling back to check for a "
- "`commonName` for now. This feature is being removed by major browsers and "
- "deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 "
- "for details.)".format(hostname)
- ),
- SubjectAltNameWarning,
- )
- _match_hostname(cert, self.assert_hostname or server_hostname)
-
- self.is_verified = (
- context.verify_mode == ssl.CERT_REQUIRED
- or self.assert_fingerprint is not None
- )
-
- def _connect_tls_proxy(self, hostname, conn):
- """
- Establish a TLS connection to the proxy using the provided SSL context.
- """
- proxy_config = self.proxy_config
- ssl_context = proxy_config.ssl_context
- if ssl_context:
- # If the user provided a proxy context, we assume CA and client
- # certificates have already been set
- return ssl_wrap_socket(
- sock=conn,
- server_hostname=hostname,
- ssl_context=ssl_context,
- )
-
- ssl_context = create_proxy_ssl_context(
- self.ssl_version,
- self.cert_reqs,
- self.ca_certs,
- self.ca_cert_dir,
- self.ca_cert_data,
- )
- # By default urllib3's SSLContext disables `check_hostname` and uses
- # a custom check. For proxies we're good with relying on the default
- # verification.
- ssl_context.check_hostname = True
-
- # If no cert was provided, use only the default options for server
- # certificate validation
- return ssl_wrap_socket(
- sock=conn,
- ca_certs=self.ca_certs,
- ca_cert_dir=self.ca_cert_dir,
- ca_cert_data=self.ca_cert_data,
- server_hostname=hostname,
- ssl_context=ssl_context,
- )
-
-
-def _match_hostname(cert, asserted_hostname):
- try:
- match_hostname(cert, asserted_hostname)
- except CertificateError as e:
- log.warning(
- "Certificate did not match expected hostname: %s. Certificate: %s",
- asserted_hostname,
- cert,
- )
- # Add cert to exception and reraise so client code can inspect
- # the cert when catching the exception, if they want to
- e._peer_cert = cert
- raise
-
-
-def _get_default_user_agent():
- return "python-urllib3/%s" % __version__
-
-
-class DummyConnection(object):
- """Used to detect a failed ConnectionCls import."""
-
- pass
-
-
-if not ssl:
- HTTPSConnection = DummyConnection # noqa: F811
-
-
-VerifiedHTTPSConnection = HTTPSConnection
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/connectionpool.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/connectionpool.py
deleted file mode 100644
index 459bbe095b..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/connectionpool.py
+++ /dev/null
@@ -1,1067 +0,0 @@
-from __future__ import absolute_import
-
-import errno
-import logging
-import socket
-import sys
-import warnings
-from socket import error as SocketError
-from socket import timeout as SocketTimeout
-
-from .connection import (
- BaseSSLError,
- BrokenPipeError,
- DummyConnection,
- HTTPConnection,
- HTTPException,
- HTTPSConnection,
- VerifiedHTTPSConnection,
- port_by_scheme,
-)
-from .exceptions import (
- ClosedPoolError,
- EmptyPoolError,
- HeaderParsingError,
- HostChangedError,
- InsecureRequestWarning,
- LocationValueError,
- MaxRetryError,
- NewConnectionError,
- ProtocolError,
- ProxyError,
- ReadTimeoutError,
- SSLError,
- TimeoutError,
-)
-from .packages import six
-from .packages.six.moves import queue
-from .packages.ssl_match_hostname import CertificateError
-from .request import RequestMethods
-from .response import HTTPResponse
-from .util.connection import is_connection_dropped
-from .util.proxy import connection_requires_http_tunnel
-from .util.queue import LifoQueue
-from .util.request import set_file_position
-from .util.response import assert_header_parsing
-from .util.retry import Retry
-from .util.timeout import Timeout
-from .util.url import Url, _encode_target
-from .util.url import _normalize_host as normalize_host
-from .util.url import get_host, parse_url
-
-xrange = six.moves.xrange
-
-log = logging.getLogger(__name__)
-
-_Default = object()
-
-
-# Pool objects
-class ConnectionPool(object):
- """
- Base class for all connection pools, such as
- :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`.
-
- .. note::
- ConnectionPool.urlopen() does not normalize or percent-encode target URIs
- which is useful if your target server doesn't support percent-encoded
- target URIs.
- """
-
- scheme = None
- QueueCls = LifoQueue
-
- def __init__(self, host, port=None):
- if not host:
- raise LocationValueError("No host specified.")
-
- self.host = _normalize_host(host, scheme=self.scheme)
- self._proxy_host = host.lower()
- self.port = port
-
- def __str__(self):
- return "%s(host=%r, port=%r)" % (type(self).__name__, self.host, self.port)
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.close()
- # Return False to re-raise any potential exceptions
- return False
-
- def close(self):
- """
- Close all pooled connections and disable the pool.
- """
- pass
-
-
-# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252
-_blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK}
-
-
-class HTTPConnectionPool(ConnectionPool, RequestMethods):
- """
- Thread-safe connection pool for one host.
-
- :param host:
- Host used for this HTTP Connection (e.g. "localhost"), passed into
- :class:`http.client.HTTPConnection`.
-
- :param port:
- Port used for this HTTP Connection (None is equivalent to 80), passed
- into :class:`http.client.HTTPConnection`.
-
- :param strict:
- Causes BadStatusLine to be raised if the status line can't be parsed
- as a valid HTTP/1.0 or 1.1 status line, passed into
- :class:`http.client.HTTPConnection`.
-
- .. note::
- Only works in Python 2. This parameter is ignored in Python 3.
-
- :param timeout:
- Socket timeout in seconds for each individual connection. This can
- be a float or integer, which sets the timeout for the HTTP request,
- or an instance of :class:`urllib3.util.Timeout` which gives you more
- fine-grained control over request timeouts. After the constructor has
- been parsed, this is always a `urllib3.util.Timeout` object.
-
- :param maxsize:
- Number of connections to save that can be reused. More than 1 is useful
- in multithreaded situations. If ``block`` is set to False, more
- connections will be created but they will not be saved once they've
- been used.
-
- :param block:
- If set to True, no more than ``maxsize`` connections will be used at
- a time. When no free connections are available, the call will block
- until a connection has been released. This is a useful side effect for
- particular multithreaded situations where one does not want to use more
- than maxsize connections per host to prevent flooding.
-
- :param headers:
- Headers to include with all requests, unless other headers are given
- explicitly.
-
- :param retries:
- Retry configuration to use by default with requests in this pool.
-
- :param _proxy:
- Parsed proxy URL, should not be used directly, instead, see
- :class:`urllib3.ProxyManager`
-
- :param _proxy_headers:
- A dictionary with proxy headers, should not be used directly,
- instead, see :class:`urllib3.ProxyManager`
-
- :param \\**conn_kw:
- Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`,
- :class:`urllib3.connection.HTTPSConnection` instances.
- """
-
- scheme = "http"
- ConnectionCls = HTTPConnection
- ResponseCls = HTTPResponse
-
- def __init__(
- self,
- host,
- port=None,
- strict=False,
- timeout=Timeout.DEFAULT_TIMEOUT,
- maxsize=1,
- block=False,
- headers=None,
- retries=None,
- _proxy=None,
- _proxy_headers=None,
- _proxy_config=None,
- **conn_kw
- ):
- ConnectionPool.__init__(self, host, port)
- RequestMethods.__init__(self, headers)
-
- self.strict = strict
-
- if not isinstance(timeout, Timeout):
- timeout = Timeout.from_float(timeout)
-
- if retries is None:
- retries = Retry.DEFAULT
-
- self.timeout = timeout
- self.retries = retries
-
- self.pool = self.QueueCls(maxsize)
- self.block = block
-
- self.proxy = _proxy
- self.proxy_headers = _proxy_headers or {}
- self.proxy_config = _proxy_config
-
- # Fill the queue up so that doing get() on it will block properly
- for _ in xrange(maxsize):
- self.pool.put(None)
-
- # These are mostly for testing and debugging purposes.
- self.num_connections = 0
- self.num_requests = 0
- self.conn_kw = conn_kw
-
- if self.proxy:
- # Enable Nagle's algorithm for proxies, to avoid packet fragmentation.
- # We cannot know if the user has added default socket options, so we cannot replace the
- # list.
- self.conn_kw.setdefault("socket_options", [])
-
- self.conn_kw["proxy"] = self.proxy
- self.conn_kw["proxy_config"] = self.proxy_config
-
- def _new_conn(self):
- """
- Return a fresh :class:`HTTPConnection`.
- """
- self.num_connections += 1
- log.debug(
- "Starting new HTTP connection (%d): %s:%s",
- self.num_connections,
- self.host,
- self.port or "80",
- )
-
- conn = self.ConnectionCls(
- host=self.host,
- port=self.port,
- timeout=self.timeout.connect_timeout,
- strict=self.strict,
- **self.conn_kw
- )
- return conn
-
- def _get_conn(self, timeout=None):
- """
- Get a connection. Will return a pooled connection if one is available.
-
- If no connections are available and :prop:`.block` is ``False``, then a
- fresh connection is returned.
-
- :param timeout:
- Seconds to wait before giving up and raising
- :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and
- :prop:`.block` is ``True``.
- """
- conn = None
- try:
- conn = self.pool.get(block=self.block, timeout=timeout)
-
- except AttributeError: # self.pool is None
- raise ClosedPoolError(self, "Pool is closed.")
-
- except queue.Empty:
- if self.block:
- raise EmptyPoolError(
- self,
- "Pool reached maximum size and no more connections are allowed.",
- )
- pass # Oh well, we'll create a new connection then
-
- # If this is a persistent connection, check if it got disconnected
- if conn and is_connection_dropped(conn):
- log.debug("Resetting dropped connection: %s", self.host)
- conn.close()
- if getattr(conn, "auto_open", 1) == 0:
- # This is a proxied connection that has been mutated by
- # http.client._tunnel() and cannot be reused (since it would
- # attempt to bypass the proxy)
- conn = None
-
- return conn or self._new_conn()
-
- def _put_conn(self, conn):
- """
- Put a connection back into the pool.
-
- :param conn:
- Connection object for the current host and port as returned by
- :meth:`._new_conn` or :meth:`._get_conn`.
-
- If the pool is already full, the connection is closed and discarded
- because we exceeded maxsize. If connections are discarded frequently,
- then maxsize should be increased.
-
- If the pool is closed, then the connection will be closed and discarded.
- """
- try:
- self.pool.put(conn, block=False)
- return # Everything is dandy, done.
- except AttributeError:
- # self.pool is None.
- pass
- except queue.Full:
- # This should never happen if self.block == True
- log.warning("Connection pool is full, discarding connection: %s", self.host)
-
- # Connection never got put back into the pool, close it.
- if conn:
- conn.close()
-
- def _validate_conn(self, conn):
- """
- Called right before a request is made, after the socket is created.
- """
- pass
-
- def _prepare_proxy(self, conn):
- # Nothing to do for HTTP connections.
- pass
-
- def _get_timeout(self, timeout):
- """Helper that always returns a :class:`urllib3.util.Timeout`"""
- if timeout is _Default:
- return self.timeout.clone()
-
- if isinstance(timeout, Timeout):
- return timeout.clone()
- else:
- # User passed us an int/float. This is for backwards compatibility,
- # can be removed later
- return Timeout.from_float(timeout)
-
- def _raise_timeout(self, err, url, timeout_value):
- """Is the error actually a timeout? Will raise a ReadTimeout or pass"""
-
- if isinstance(err, SocketTimeout):
- raise ReadTimeoutError(
- self, url, "Read timed out. (read timeout=%s)" % timeout_value
- )
-
- # See the above comment about EAGAIN in Python 3. In Python 2 we have
- # to specifically catch it and throw the timeout error
- if hasattr(err, "errno") and err.errno in _blocking_errnos:
- raise ReadTimeoutError(
- self, url, "Read timed out. (read timeout=%s)" % timeout_value
- )
-
- # Catch possible read timeouts thrown as SSL errors. If not the
- # case, rethrow the original. We need to do this because of:
- # http://bugs.python.org/issue10272
- if "timed out" in str(err) or "did not complete (read)" in str(
- err
- ): # Python < 2.7.4
- raise ReadTimeoutError(
- self, url, "Read timed out. (read timeout=%s)" % timeout_value
- )
-
- def _make_request(
- self, conn, method, url, timeout=_Default, chunked=False, **httplib_request_kw
- ):
- """
- Perform a request on a given urllib connection object taken from our
- pool.
-
- :param conn:
- a connection from one of our connection pools
-
- :param timeout:
- Socket timeout in seconds for the request. This can be a
- float or integer, which will set the same timeout value for
- the socket connect and the socket read, or an instance of
- :class:`urllib3.util.Timeout`, which gives you more fine-grained
- control over your timeouts.
- """
- self.num_requests += 1
-
- timeout_obj = self._get_timeout(timeout)
- timeout_obj.start_connect()
- conn.timeout = timeout_obj.connect_timeout
-
- # Trigger any extra validation we need to do.
- try:
- self._validate_conn(conn)
- except (SocketTimeout, BaseSSLError) as e:
- # Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout.
- self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)
- raise
-
- # conn.request() calls http.client.*.request, not the method in
- # urllib3.request. It also calls makefile (recv) on the socket.
- try:
- if chunked:
- conn.request_chunked(method, url, **httplib_request_kw)
- else:
- conn.request(method, url, **httplib_request_kw)
-
- # We are swallowing BrokenPipeError (errno.EPIPE) since the server is
- # legitimately able to close the connection after sending a valid response.
- # With this behaviour, the received response is still readable.
- except BrokenPipeError:
- # Python 3
- pass
- except IOError as e:
- # Python 2 and macOS/Linux
- # EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE is needed on macOS
- # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
- if e.errno not in {
- errno.EPIPE,
- errno.ESHUTDOWN,
- errno.EPROTOTYPE,
- }:
- raise
-
- # Reset the timeout for the recv() on the socket
- read_timeout = timeout_obj.read_timeout
-
- # App Engine doesn't have a sock attr
- if getattr(conn, "sock", None):
- # In Python 3 socket.py will catch EAGAIN and return None when you
- # try and read into the file pointer created by http.client, which
- # instead raises a BadStatusLine exception. Instead of catching
- # the exception and assuming all BadStatusLine exceptions are read
- # timeouts, check for a zero timeout before making the request.
- if read_timeout == 0:
- raise ReadTimeoutError(
- self, url, "Read timed out. (read timeout=%s)" % read_timeout
- )
- if read_timeout is Timeout.DEFAULT_TIMEOUT:
- conn.sock.settimeout(socket.getdefaulttimeout())
- else: # None or a value
- conn.sock.settimeout(read_timeout)
-
- # Receive the response from the server
- try:
- try:
- # Python 2.7, use buffering of HTTP responses
- httplib_response = conn.getresponse(buffering=True)
- except TypeError:
- # Python 3
- try:
- httplib_response = conn.getresponse()
- except BaseException as e:
- # Remove the TypeError from the exception chain in
- # Python 3 (including for exceptions like SystemExit).
- # Otherwise it looks like a bug in the code.
- six.raise_from(e, None)
- except (SocketTimeout, BaseSSLError, SocketError) as e:
- self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
- raise
-
- # AppEngine doesn't have a version attr.
- http_version = getattr(conn, "_http_vsn_str", "HTTP/?")
- log.debug(
- '%s://%s:%s "%s %s %s" %s %s',
- self.scheme,
- self.host,
- self.port,
- method,
- url,
- http_version,
- httplib_response.status,
- httplib_response.length,
- )
-
- try:
- assert_header_parsing(httplib_response.msg)
- except (HeaderParsingError, TypeError) as hpe: # Platform-specific: Python 3
- log.warning(
- "Failed to parse headers (url=%s): %s",
- self._absolute_url(url),
- hpe,
- exc_info=True,
- )
-
- return httplib_response
-
- def _absolute_url(self, path):
- return Url(scheme=self.scheme, host=self.host, port=self.port, path=path).url
-
- def close(self):
- """
- Close all pooled connections and disable the pool.
- """
- if self.pool is None:
- return
- # Disable access to the pool
- old_pool, self.pool = self.pool, None
-
- try:
- while True:
- conn = old_pool.get(block=False)
- if conn:
- conn.close()
-
- except queue.Empty:
- pass # Done.
-
- def is_same_host(self, url):
- """
- Check if the given ``url`` is a member of the same host as this
- connection pool.
- """
- if url.startswith("/"):
- return True
-
- # TODO: Add optional support for socket.gethostbyname checking.
- scheme, host, port = get_host(url)
- if host is not None:
- host = _normalize_host(host, scheme=scheme)
-
- # Use explicit default port for comparison when none is given
- if self.port and not port:
- port = port_by_scheme.get(scheme)
- elif not self.port and port == port_by_scheme.get(scheme):
- port = None
-
- return (scheme, host, port) == (self.scheme, self.host, self.port)
-
- def urlopen(
- self,
- method,
- url,
- body=None,
- headers=None,
- retries=None,
- redirect=True,
- assert_same_host=True,
- timeout=_Default,
- pool_timeout=None,
- release_conn=None,
- chunked=False,
- body_pos=None,
- **response_kw
- ):
- """
- Get a connection from the pool and perform an HTTP request. This is the
- lowest level call for making a request, so you'll need to specify all
- the raw details.
-
- .. note::
-
- More commonly, it's appropriate to use a convenience method provided
- by :class:`.RequestMethods`, such as :meth:`request`.
-
- .. note::
-
- `release_conn` will only behave as expected if
- `preload_content=False` because we want to make
- `preload_content=False` the default behaviour someday soon without
- breaking backwards compatibility.
-
- :param method:
- HTTP request method (such as GET, POST, PUT, etc.)
-
- :param url:
- The URL to perform the request on.
-
- :param body:
- Data to send in the request body, either :class:`str`, :class:`bytes`,
- an iterable of :class:`str`/:class:`bytes`, or a file-like object.
-
- :param headers:
- Dictionary of custom headers to send, such as User-Agent,
- If-None-Match, etc. If None, pool headers are used. If provided,
- these headers completely replace any pool-specific headers.
-
- :param retries:
- Configure the number of retries to allow before raising a
- :class:`~urllib3.exceptions.MaxRetryError` exception.
-
- Pass ``None`` to retry until you receive a response. Pass a
- :class:`~urllib3.util.retry.Retry` object for fine-grained control
- over different types of retries.
- Pass an integer number to retry connection errors that many times,
- but no other types of errors. Pass zero to never retry.
-
- If ``False``, then retries are disabled and any exception is raised
- immediately. Also, instead of raising a MaxRetryError on redirects,
- the redirect response will be returned.
-
- :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
-
- :param redirect:
- If True, automatically handle redirects (status codes 301, 302,
- 303, 307, 308). Each redirect counts as a retry. Disabling retries
- will disable redirect, too.
-
- :param assert_same_host:
- If ``True``, will make sure that the host of the pool requests is
- consistent else will raise HostChangedError. When ``False``, you can
- use the pool on an HTTP proxy and request foreign hosts.
-
- :param timeout:
- If specified, overrides the default timeout for this one
- request. It may be a float (in seconds) or an instance of
- :class:`urllib3.util.Timeout`.
-
- :param pool_timeout:
- If set and the pool is set to block=True, then this method will
- block for ``pool_timeout`` seconds and raise EmptyPoolError if no
- connection is available within the time period.
-
- :param release_conn:
- If False, then the urlopen call will not release the connection
- back into the pool once a response is received (but will release if
- you read the entire contents of the response such as when
- `preload_content=True`). This is useful if you're not preloading
- the response's content immediately. You will need to call
- ``r.release_conn()`` on the response ``r`` to return the connection
- back into the pool. If None, it takes the value of
- ``response_kw.get('preload_content', True)``.
-
- :param chunked:
- If True, urllib3 will send the body using chunked transfer
- encoding. Otherwise, urllib3 will send the body using the standard
- content-length form. Defaults to False.
-
- :param int body_pos:
- Position to seek to in file-like body in the event of a retry or
- redirect. Typically this won't need to be set because urllib3 will
- auto-populate the value when needed.
-
- :param \\**response_kw:
- Additional parameters are passed to
- :meth:`urllib3.response.HTTPResponse.from_httplib`
- """
-
- parsed_url = parse_url(url)
- destination_scheme = parsed_url.scheme
-
- if headers is None:
- headers = self.headers
-
- if not isinstance(retries, Retry):
- retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
-
- if release_conn is None:
- release_conn = response_kw.get("preload_content", True)
-
- # Check host
- if assert_same_host and not self.is_same_host(url):
- raise HostChangedError(self, url, retries)
-
- # Ensure that the URL we're connecting to is properly encoded
- if url.startswith("/"):
- url = six.ensure_str(_encode_target(url))
- else:
- url = six.ensure_str(parsed_url.url)
-
- conn = None
-
- # Track whether `conn` needs to be released before
- # returning/raising/recursing. Update this variable if necessary, and
- # leave `release_conn` constant throughout the function. That way, if
- # the function recurses, the original value of `release_conn` will be
- # passed down into the recursive call, and its value will be respected.
- #
- # See issue #651 [1] for details.
- #
- # [1]
- release_this_conn = release_conn
-
- http_tunnel_required = connection_requires_http_tunnel(
- self.proxy, self.proxy_config, destination_scheme
- )
-
- # Merge the proxy headers. Only done when not using HTTP CONNECT. We
- # have to copy the headers dict so we can safely change it without those
- # changes being reflected in anyone else's copy.
- if not http_tunnel_required:
- headers = headers.copy()
- headers.update(self.proxy_headers)
-
- # Must keep the exception bound to a separate variable or else Python 3
- # complains about UnboundLocalError.
- err = None
-
- # Keep track of whether we cleanly exited the except block. This
- # ensures we do proper cleanup in finally.
- clean_exit = False
-
- # Rewind body position, if needed. Record current position
- # for future rewinds in the event of a redirect/retry.
- body_pos = set_file_position(body, body_pos)
-
- try:
- # Request a connection from the queue.
- timeout_obj = self._get_timeout(timeout)
- conn = self._get_conn(timeout=pool_timeout)
-
- conn.timeout = timeout_obj.connect_timeout
-
- is_new_proxy_conn = self.proxy is not None and not getattr(
- conn, "sock", None
- )
- if is_new_proxy_conn and http_tunnel_required:
- self._prepare_proxy(conn)
-
- # Make the request on the httplib connection object.
- httplib_response = self._make_request(
- conn,
- method,
- url,
- timeout=timeout_obj,
- body=body,
- headers=headers,
- chunked=chunked,
- )
-
- # If we're going to release the connection in ``finally:``, then
- # the response doesn't need to know about the connection. Otherwise
- # it will also try to release it and we'll have a double-release
- # mess.
- response_conn = conn if not release_conn else None
-
- # Pass method to Response for length checking
- response_kw["request_method"] = method
-
- # Import httplib's response into our own wrapper object
- response = self.ResponseCls.from_httplib(
- httplib_response,
- pool=self,
- connection=response_conn,
- retries=retries,
- **response_kw
- )
-
- # Everything went great!
- clean_exit = True
-
- except EmptyPoolError:
- # Didn't get a connection from the pool, no need to clean up
- clean_exit = True
- release_this_conn = False
- raise
-
- except (
- TimeoutError,
- HTTPException,
- SocketError,
- ProtocolError,
- BaseSSLError,
- SSLError,
- CertificateError,
- ) as e:
- # Discard the connection for these exceptions. It will be
- # replaced during the next _get_conn() call.
- clean_exit = False
- if isinstance(e, (BaseSSLError, CertificateError)):
- e = SSLError(e)
- elif isinstance(e, (SocketError, NewConnectionError)) and self.proxy:
- e = ProxyError("Cannot connect to proxy.", e)
- elif isinstance(e, (SocketError, HTTPException)):
- e = ProtocolError("Connection aborted.", e)
-
- retries = retries.increment(
- method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
- )
- retries.sleep()
-
- # Keep track of the error for the retry warning.
- err = e
-
- finally:
- if not clean_exit:
- # We hit some kind of exception, handled or otherwise. We need
- # to throw the connection away unless explicitly told not to.
- # Close the connection, set the variable to None, and make sure
- # we put the None back in the pool to avoid leaking it.
- conn = conn and conn.close()
- release_this_conn = True
-
- if release_this_conn:
- # Put the connection back to be reused. If the connection is
- # expired then it will be None, which will get replaced with a
- # fresh connection during _get_conn.
- self._put_conn(conn)
-
- if not conn:
- # Try again
- log.warning(
- "Retrying (%r) after connection broken by '%r': %s", retries, err, url
- )
- return self.urlopen(
- method,
- url,
- body,
- headers,
- retries,
- redirect,
- assert_same_host,
- timeout=timeout,
- pool_timeout=pool_timeout,
- release_conn=release_conn,
- chunked=chunked,
- body_pos=body_pos,
- **response_kw
- )
-
- # Handle redirect?
- redirect_location = redirect and response.get_redirect_location()
- if redirect_location:
- if response.status == 303:
- method = "GET"
-
- try:
- retries = retries.increment(method, url, response=response, _pool=self)
- except MaxRetryError:
- if retries.raise_on_redirect:
- response.drain_conn()
- raise
- return response
-
- response.drain_conn()
- retries.sleep_for_retry(response)
- log.debug("Redirecting %s -> %s", url, redirect_location)
- return self.urlopen(
- method,
- redirect_location,
- body,
- headers,
- retries=retries,
- redirect=redirect,
- assert_same_host=assert_same_host,
- timeout=timeout,
- pool_timeout=pool_timeout,
- release_conn=release_conn,
- chunked=chunked,
- body_pos=body_pos,
- **response_kw
- )
-
- # Check if we should retry the HTTP response.
- has_retry_after = bool(response.getheader("Retry-After"))
- if retries.is_retry(method, response.status, has_retry_after):
- try:
- retries = retries.increment(method, url, response=response, _pool=self)
- except MaxRetryError:
- if retries.raise_on_status:
- response.drain_conn()
- raise
- return response
-
- response.drain_conn()
- retries.sleep(response)
- log.debug("Retry: %s", url)
- return self.urlopen(
- method,
- url,
- body,
- headers,
- retries=retries,
- redirect=redirect,
- assert_same_host=assert_same_host,
- timeout=timeout,
- pool_timeout=pool_timeout,
- release_conn=release_conn,
- chunked=chunked,
- body_pos=body_pos,
- **response_kw
- )
-
- return response
-
-
-class HTTPSConnectionPool(HTTPConnectionPool):
- """
- Same as :class:`.HTTPConnectionPool`, but HTTPS.
-
- :class:`.HTTPSConnection` uses one of ``assert_fingerprint``,
- ``assert_hostname`` and ``host`` in this order to verify connections.
- If ``assert_hostname`` is False, no verification is done.
-
- The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``,
- ``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl`
- is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade
- the connection socket into an SSL socket.
- """
-
- scheme = "https"
- ConnectionCls = HTTPSConnection
-
- def __init__(
- self,
- host,
- port=None,
- strict=False,
- timeout=Timeout.DEFAULT_TIMEOUT,
- maxsize=1,
- block=False,
- headers=None,
- retries=None,
- _proxy=None,
- _proxy_headers=None,
- key_file=None,
- cert_file=None,
- cert_reqs=None,
- key_password=None,
- ca_certs=None,
- ssl_version=None,
- assert_hostname=None,
- assert_fingerprint=None,
- ca_cert_dir=None,
- **conn_kw
- ):
-
- HTTPConnectionPool.__init__(
- self,
- host,
- port,
- strict,
- timeout,
- maxsize,
- block,
- headers,
- retries,
- _proxy,
- _proxy_headers,
- **conn_kw
- )
-
- self.key_file = key_file
- self.cert_file = cert_file
- self.cert_reqs = cert_reqs
- self.key_password = key_password
- self.ca_certs = ca_certs
- self.ca_cert_dir = ca_cert_dir
- self.ssl_version = ssl_version
- self.assert_hostname = assert_hostname
- self.assert_fingerprint = assert_fingerprint
-
- def _prepare_conn(self, conn):
- """
- Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket`
- and establish the tunnel if proxy is used.
- """
-
- if isinstance(conn, VerifiedHTTPSConnection):
- conn.set_cert(
- key_file=self.key_file,
- key_password=self.key_password,
- cert_file=self.cert_file,
- cert_reqs=self.cert_reqs,
- ca_certs=self.ca_certs,
- ca_cert_dir=self.ca_cert_dir,
- assert_hostname=self.assert_hostname,
- assert_fingerprint=self.assert_fingerprint,
- )
- conn.ssl_version = self.ssl_version
- return conn
-
- def _prepare_proxy(self, conn):
- """
- Establishes a tunnel connection through HTTP CONNECT.
-
- Tunnel connection is established early because otherwise httplib would
- improperly set Host: header to proxy's IP:port.
- """
-
- conn.set_tunnel(self._proxy_host, self.port, self.proxy_headers)
-
- if self.proxy.scheme == "https":
- conn.tls_in_tls_required = True
-
- conn.connect()
-
- def _new_conn(self):
- """
- Return a fresh :class:`http.client.HTTPSConnection`.
- """
- self.num_connections += 1
- log.debug(
- "Starting new HTTPS connection (%d): %s:%s",
- self.num_connections,
- self.host,
- self.port or "443",
- )
-
- if not self.ConnectionCls or self.ConnectionCls is DummyConnection:
- raise SSLError(
- "Can't connect to HTTPS URL because the SSL module is not available."
- )
-
- actual_host = self.host
- actual_port = self.port
- if self.proxy is not None:
- actual_host = self.proxy.host
- actual_port = self.proxy.port
-
- conn = self.ConnectionCls(
- host=actual_host,
- port=actual_port,
- timeout=self.timeout.connect_timeout,
- strict=self.strict,
- cert_file=self.cert_file,
- key_file=self.key_file,
- key_password=self.key_password,
- **self.conn_kw
- )
-
- return self._prepare_conn(conn)
-
- def _validate_conn(self, conn):
- """
- Called right before a request is made, after the socket is created.
- """
- super(HTTPSConnectionPool, self)._validate_conn(conn)
-
- # Force connect early to allow us to validate the connection.
- if not getattr(conn, "sock", None): # AppEngine might not have `.sock`
- conn.connect()
-
- if not conn.is_verified:
- warnings.warn(
- (
- "Unverified HTTPS request is being made to host '%s'. "
- "Adding certificate verification is strongly advised. See: "
- "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html"
- "#ssl-warnings" % conn.host
- ),
- InsecureRequestWarning,
- )
-
-
-def connection_from_url(url, **kw):
- """
- Given a url, return an :class:`.ConnectionPool` instance of its host.
-
- This is a shortcut for not having to parse out the scheme, host, and port
- of the url before creating an :class:`.ConnectionPool` instance.
-
- :param url:
- Absolute URL string that must include the scheme. Port is optional.
-
- :param \\**kw:
- Passes additional parameters to the constructor of the appropriate
- :class:`.ConnectionPool`. Useful for specifying things like
- timeout, maxsize, headers, etc.
-
- Example::
-
- >>> conn = connection_from_url('http://google.com/')
- >>> r = conn.request('GET', '/')
- """
- scheme, host, port = get_host(url)
- port = port or port_by_scheme.get(scheme, 80)
- if scheme == "https":
- return HTTPSConnectionPool(host, port=port, **kw)
- else:
- return HTTPConnectionPool(host, port=port, **kw)
-
-
-def _normalize_host(host, scheme):
- """
- Normalize hosts for comparisons and use with sockets.
- """
-
- host = normalize_host(host, scheme)
-
- # httplib doesn't like it when we include brackets in IPv6 addresses
- # Specifically, if we include brackets but also pass the port then
- # httplib crazily doubles up the square brackets on the Host header.
- # Instead, we need to make sure we never pass ``None`` as the port.
- # However, for backward compatibility reasons we can't actually
- # *assert* that. See http://bugs.python.org/issue28539
- if host.startswith("[") and host.endswith("]"):
- host = host[1:-1]
- return host
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/__init__.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_appengine_environ.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_appengine_environ.py
deleted file mode 100644
index 8765b907d7..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_appengine_environ.py
+++ /dev/null
@@ -1,36 +0,0 @@
-"""
-This module provides means to detect the App Engine environment.
-"""
-
-import os
-
-
-def is_appengine():
- return is_local_appengine() or is_prod_appengine()
-
-
-def is_appengine_sandbox():
- """Reports if the app is running in the first generation sandbox.
-
- The second generation runtimes are technically still in a sandbox, but it
- is much less restrictive, so generally you shouldn't need to check for it.
- see https://cloud.google.com/appengine/docs/standard/runtimes
- """
- return is_appengine() and os.environ["APPENGINE_RUNTIME"] == "python27"
-
-
-def is_local_appengine():
- return "APPENGINE_RUNTIME" in os.environ and os.environ.get(
- "SERVER_SOFTWARE", ""
- ).startswith("Development/")
-
-
-def is_prod_appengine():
- return "APPENGINE_RUNTIME" in os.environ and os.environ.get(
- "SERVER_SOFTWARE", ""
- ).startswith("Google App Engine/")
-
-
-def is_prod_appengine_mvms():
- """Deprecated."""
- return False
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/__init__.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/bindings.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/bindings.py
deleted file mode 100644
index 11524d400b..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/bindings.py
+++ /dev/null
@@ -1,519 +0,0 @@
-"""
-This module uses ctypes to bind a whole bunch of functions and constants from
-SecureTransport. The goal here is to provide the low-level API to
-SecureTransport. These are essentially the C-level functions and constants, and
-they're pretty gross to work with.
-
-This code is a bastardised version of the code found in Will Bond's oscrypto
-library. An enormous debt is owed to him for blazing this trail for us. For
-that reason, this code should be considered to be covered both by urllib3's
-license and by oscrypto's:
-
- Copyright (c) 2015-2016 Will Bond
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
-"""
-from __future__ import absolute_import
-
-import platform
-from ctypes import (
- CDLL,
- CFUNCTYPE,
- POINTER,
- c_bool,
- c_byte,
- c_char_p,
- c_int32,
- c_long,
- c_size_t,
- c_uint32,
- c_ulong,
- c_void_p,
-)
-from ctypes.util import find_library
-
-from urllib3.packages.six import raise_from
-
-if platform.system() != "Darwin":
- raise ImportError("Only macOS is supported")
-
-version = platform.mac_ver()[0]
-version_info = tuple(map(int, version.split(".")))
-if version_info < (10, 8):
- raise OSError(
- "Only OS X 10.8 and newer are supported, not %s.%s"
- % (version_info[0], version_info[1])
- )
-
-
-def load_cdll(name, macos10_16_path):
- """Loads a CDLL by name, falling back to known path on 10.16+"""
- try:
- # Big Sur is technically 11 but we use 10.16 due to the Big Sur
- # beta being labeled as 10.16.
- if version_info >= (10, 16):
- path = macos10_16_path
- else:
- path = find_library(name)
- if not path:
- raise OSError # Caught and reraised as 'ImportError'
- return CDLL(path, use_errno=True)
- except OSError:
- raise_from(ImportError("The library %s failed to load" % name), None)
-
-
-Security = load_cdll(
- "Security", "/System/Library/Frameworks/Security.framework/Security"
-)
-CoreFoundation = load_cdll(
- "CoreFoundation",
- "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation",
-)
-
-
-Boolean = c_bool
-CFIndex = c_long
-CFStringEncoding = c_uint32
-CFData = c_void_p
-CFString = c_void_p
-CFArray = c_void_p
-CFMutableArray = c_void_p
-CFDictionary = c_void_p
-CFError = c_void_p
-CFType = c_void_p
-CFTypeID = c_ulong
-
-CFTypeRef = POINTER(CFType)
-CFAllocatorRef = c_void_p
-
-OSStatus = c_int32
-
-CFDataRef = POINTER(CFData)
-CFStringRef = POINTER(CFString)
-CFArrayRef = POINTER(CFArray)
-CFMutableArrayRef = POINTER(CFMutableArray)
-CFDictionaryRef = POINTER(CFDictionary)
-CFArrayCallBacks = c_void_p
-CFDictionaryKeyCallBacks = c_void_p
-CFDictionaryValueCallBacks = c_void_p
-
-SecCertificateRef = POINTER(c_void_p)
-SecExternalFormat = c_uint32
-SecExternalItemType = c_uint32
-SecIdentityRef = POINTER(c_void_p)
-SecItemImportExportFlags = c_uint32
-SecItemImportExportKeyParameters = c_void_p
-SecKeychainRef = POINTER(c_void_p)
-SSLProtocol = c_uint32
-SSLCipherSuite = c_uint32
-SSLContextRef = POINTER(c_void_p)
-SecTrustRef = POINTER(c_void_p)
-SSLConnectionRef = c_uint32
-SecTrustResultType = c_uint32
-SecTrustOptionFlags = c_uint32
-SSLProtocolSide = c_uint32
-SSLConnectionType = c_uint32
-SSLSessionOption = c_uint32
-
-
-try:
- Security.SecItemImport.argtypes = [
- CFDataRef,
- CFStringRef,
- POINTER(SecExternalFormat),
- POINTER(SecExternalItemType),
- SecItemImportExportFlags,
- POINTER(SecItemImportExportKeyParameters),
- SecKeychainRef,
- POINTER(CFArrayRef),
- ]
- Security.SecItemImport.restype = OSStatus
-
- Security.SecCertificateGetTypeID.argtypes = []
- Security.SecCertificateGetTypeID.restype = CFTypeID
-
- Security.SecIdentityGetTypeID.argtypes = []
- Security.SecIdentityGetTypeID.restype = CFTypeID
-
- Security.SecKeyGetTypeID.argtypes = []
- Security.SecKeyGetTypeID.restype = CFTypeID
-
- Security.SecCertificateCreateWithData.argtypes = [CFAllocatorRef, CFDataRef]
- Security.SecCertificateCreateWithData.restype = SecCertificateRef
-
- Security.SecCertificateCopyData.argtypes = [SecCertificateRef]
- Security.SecCertificateCopyData.restype = CFDataRef
-
- Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p]
- Security.SecCopyErrorMessageString.restype = CFStringRef
-
- Security.SecIdentityCreateWithCertificate.argtypes = [
- CFTypeRef,
- SecCertificateRef,
- POINTER(SecIdentityRef),
- ]
- Security.SecIdentityCreateWithCertificate.restype = OSStatus
-
- Security.SecKeychainCreate.argtypes = [
- c_char_p,
- c_uint32,
- c_void_p,
- Boolean,
- c_void_p,
- POINTER(SecKeychainRef),
- ]
- Security.SecKeychainCreate.restype = OSStatus
-
- Security.SecKeychainDelete.argtypes = [SecKeychainRef]
- Security.SecKeychainDelete.restype = OSStatus
-
- Security.SecPKCS12Import.argtypes = [
- CFDataRef,
- CFDictionaryRef,
- POINTER(CFArrayRef),
- ]
- Security.SecPKCS12Import.restype = OSStatus
-
- SSLReadFunc = CFUNCTYPE(OSStatus, SSLConnectionRef, c_void_p, POINTER(c_size_t))
- SSLWriteFunc = CFUNCTYPE(
- OSStatus, SSLConnectionRef, POINTER(c_byte), POINTER(c_size_t)
- )
-
- Security.SSLSetIOFuncs.argtypes = [SSLContextRef, SSLReadFunc, SSLWriteFunc]
- Security.SSLSetIOFuncs.restype = OSStatus
-
- Security.SSLSetPeerID.argtypes = [SSLContextRef, c_char_p, c_size_t]
- Security.SSLSetPeerID.restype = OSStatus
-
- Security.SSLSetCertificate.argtypes = [SSLContextRef, CFArrayRef]
- Security.SSLSetCertificate.restype = OSStatus
-
- Security.SSLSetCertificateAuthorities.argtypes = [SSLContextRef, CFTypeRef, Boolean]
- Security.SSLSetCertificateAuthorities.restype = OSStatus
-
- Security.SSLSetConnection.argtypes = [SSLContextRef, SSLConnectionRef]
- Security.SSLSetConnection.restype = OSStatus
-
- Security.SSLSetPeerDomainName.argtypes = [SSLContextRef, c_char_p, c_size_t]
- Security.SSLSetPeerDomainName.restype = OSStatus
-
- Security.SSLHandshake.argtypes = [SSLContextRef]
- Security.SSLHandshake.restype = OSStatus
-
- Security.SSLRead.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)]
- Security.SSLRead.restype = OSStatus
-
- Security.SSLWrite.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)]
- Security.SSLWrite.restype = OSStatus
-
- Security.SSLClose.argtypes = [SSLContextRef]
- Security.SSLClose.restype = OSStatus
-
- Security.SSLGetNumberSupportedCiphers.argtypes = [SSLContextRef, POINTER(c_size_t)]
- Security.SSLGetNumberSupportedCiphers.restype = OSStatus
-
- Security.SSLGetSupportedCiphers.argtypes = [
- SSLContextRef,
- POINTER(SSLCipherSuite),
- POINTER(c_size_t),
- ]
- Security.SSLGetSupportedCiphers.restype = OSStatus
-
- Security.SSLSetEnabledCiphers.argtypes = [
- SSLContextRef,
- POINTER(SSLCipherSuite),
- c_size_t,
- ]
- Security.SSLSetEnabledCiphers.restype = OSStatus
-
- Security.SSLGetNumberEnabledCiphers.argtype = [SSLContextRef, POINTER(c_size_t)]
- Security.SSLGetNumberEnabledCiphers.restype = OSStatus
-
- Security.SSLGetEnabledCiphers.argtypes = [
- SSLContextRef,
- POINTER(SSLCipherSuite),
- POINTER(c_size_t),
- ]
- Security.SSLGetEnabledCiphers.restype = OSStatus
-
- Security.SSLGetNegotiatedCipher.argtypes = [SSLContextRef, POINTER(SSLCipherSuite)]
- Security.SSLGetNegotiatedCipher.restype = OSStatus
-
- Security.SSLGetNegotiatedProtocolVersion.argtypes = [
- SSLContextRef,
- POINTER(SSLProtocol),
- ]
- Security.SSLGetNegotiatedProtocolVersion.restype = OSStatus
-
- Security.SSLCopyPeerTrust.argtypes = [SSLContextRef, POINTER(SecTrustRef)]
- Security.SSLCopyPeerTrust.restype = OSStatus
-
- Security.SecTrustSetAnchorCertificates.argtypes = [SecTrustRef, CFArrayRef]
- Security.SecTrustSetAnchorCertificates.restype = OSStatus
-
- Security.SecTrustSetAnchorCertificatesOnly.argstypes = [SecTrustRef, Boolean]
- Security.SecTrustSetAnchorCertificatesOnly.restype = OSStatus
-
- Security.SecTrustEvaluate.argtypes = [SecTrustRef, POINTER(SecTrustResultType)]
- Security.SecTrustEvaluate.restype = OSStatus
-
- Security.SecTrustGetCertificateCount.argtypes = [SecTrustRef]
- Security.SecTrustGetCertificateCount.restype = CFIndex
-
- Security.SecTrustGetCertificateAtIndex.argtypes = [SecTrustRef, CFIndex]
- Security.SecTrustGetCertificateAtIndex.restype = SecCertificateRef
-
- Security.SSLCreateContext.argtypes = [
- CFAllocatorRef,
- SSLProtocolSide,
- SSLConnectionType,
- ]
- Security.SSLCreateContext.restype = SSLContextRef
-
- Security.SSLSetSessionOption.argtypes = [SSLContextRef, SSLSessionOption, Boolean]
- Security.SSLSetSessionOption.restype = OSStatus
-
- Security.SSLSetProtocolVersionMin.argtypes = [SSLContextRef, SSLProtocol]
- Security.SSLSetProtocolVersionMin.restype = OSStatus
-
- Security.SSLSetProtocolVersionMax.argtypes = [SSLContextRef, SSLProtocol]
- Security.SSLSetProtocolVersionMax.restype = OSStatus
-
- try:
- Security.SSLSetALPNProtocols.argtypes = [SSLContextRef, CFArrayRef]
- Security.SSLSetALPNProtocols.restype = OSStatus
- except AttributeError:
- # Supported only in 10.12+
- pass
-
- Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p]
- Security.SecCopyErrorMessageString.restype = CFStringRef
-
- Security.SSLReadFunc = SSLReadFunc
- Security.SSLWriteFunc = SSLWriteFunc
- Security.SSLContextRef = SSLContextRef
- Security.SSLProtocol = SSLProtocol
- Security.SSLCipherSuite = SSLCipherSuite
- Security.SecIdentityRef = SecIdentityRef
- Security.SecKeychainRef = SecKeychainRef
- Security.SecTrustRef = SecTrustRef
- Security.SecTrustResultType = SecTrustResultType
- Security.SecExternalFormat = SecExternalFormat
- Security.OSStatus = OSStatus
-
- Security.kSecImportExportPassphrase = CFStringRef.in_dll(
- Security, "kSecImportExportPassphrase"
- )
- Security.kSecImportItemIdentity = CFStringRef.in_dll(
- Security, "kSecImportItemIdentity"
- )
-
- # CoreFoundation time!
- CoreFoundation.CFRetain.argtypes = [CFTypeRef]
- CoreFoundation.CFRetain.restype = CFTypeRef
-
- CoreFoundation.CFRelease.argtypes = [CFTypeRef]
- CoreFoundation.CFRelease.restype = None
-
- CoreFoundation.CFGetTypeID.argtypes = [CFTypeRef]
- CoreFoundation.CFGetTypeID.restype = CFTypeID
-
- CoreFoundation.CFStringCreateWithCString.argtypes = [
- CFAllocatorRef,
- c_char_p,
- CFStringEncoding,
- ]
- CoreFoundation.CFStringCreateWithCString.restype = CFStringRef
-
- CoreFoundation.CFStringGetCStringPtr.argtypes = [CFStringRef, CFStringEncoding]
- CoreFoundation.CFStringGetCStringPtr.restype = c_char_p
-
- CoreFoundation.CFStringGetCString.argtypes = [
- CFStringRef,
- c_char_p,
- CFIndex,
- CFStringEncoding,
- ]
- CoreFoundation.CFStringGetCString.restype = c_bool
-
- CoreFoundation.CFDataCreate.argtypes = [CFAllocatorRef, c_char_p, CFIndex]
- CoreFoundation.CFDataCreate.restype = CFDataRef
-
- CoreFoundation.CFDataGetLength.argtypes = [CFDataRef]
- CoreFoundation.CFDataGetLength.restype = CFIndex
-
- CoreFoundation.CFDataGetBytePtr.argtypes = [CFDataRef]
- CoreFoundation.CFDataGetBytePtr.restype = c_void_p
-
- CoreFoundation.CFDictionaryCreate.argtypes = [
- CFAllocatorRef,
- POINTER(CFTypeRef),
- POINTER(CFTypeRef),
- CFIndex,
- CFDictionaryKeyCallBacks,
- CFDictionaryValueCallBacks,
- ]
- CoreFoundation.CFDictionaryCreate.restype = CFDictionaryRef
-
- CoreFoundation.CFDictionaryGetValue.argtypes = [CFDictionaryRef, CFTypeRef]
- CoreFoundation.CFDictionaryGetValue.restype = CFTypeRef
-
- CoreFoundation.CFArrayCreate.argtypes = [
- CFAllocatorRef,
- POINTER(CFTypeRef),
- CFIndex,
- CFArrayCallBacks,
- ]
- CoreFoundation.CFArrayCreate.restype = CFArrayRef
-
- CoreFoundation.CFArrayCreateMutable.argtypes = [
- CFAllocatorRef,
- CFIndex,
- CFArrayCallBacks,
- ]
- CoreFoundation.CFArrayCreateMutable.restype = CFMutableArrayRef
-
- CoreFoundation.CFArrayAppendValue.argtypes = [CFMutableArrayRef, c_void_p]
- CoreFoundation.CFArrayAppendValue.restype = None
-
- CoreFoundation.CFArrayGetCount.argtypes = [CFArrayRef]
- CoreFoundation.CFArrayGetCount.restype = CFIndex
-
- CoreFoundation.CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex]
- CoreFoundation.CFArrayGetValueAtIndex.restype = c_void_p
-
- CoreFoundation.kCFAllocatorDefault = CFAllocatorRef.in_dll(
- CoreFoundation, "kCFAllocatorDefault"
- )
- CoreFoundation.kCFTypeArrayCallBacks = c_void_p.in_dll(
- CoreFoundation, "kCFTypeArrayCallBacks"
- )
- CoreFoundation.kCFTypeDictionaryKeyCallBacks = c_void_p.in_dll(
- CoreFoundation, "kCFTypeDictionaryKeyCallBacks"
- )
- CoreFoundation.kCFTypeDictionaryValueCallBacks = c_void_p.in_dll(
- CoreFoundation, "kCFTypeDictionaryValueCallBacks"
- )
-
- CoreFoundation.CFTypeRef = CFTypeRef
- CoreFoundation.CFArrayRef = CFArrayRef
- CoreFoundation.CFStringRef = CFStringRef
- CoreFoundation.CFDictionaryRef = CFDictionaryRef
-
-except (AttributeError):
- raise ImportError("Error initializing ctypes")
-
-
-class CFConst(object):
- """
- A class object that acts as essentially a namespace for CoreFoundation
- constants.
- """
-
- kCFStringEncodingUTF8 = CFStringEncoding(0x08000100)
-
-
-class SecurityConst(object):
- """
- A class object that acts as essentially a namespace for Security constants.
- """
-
- kSSLSessionOptionBreakOnServerAuth = 0
-
- kSSLProtocol2 = 1
- kSSLProtocol3 = 2
- kTLSProtocol1 = 4
- kTLSProtocol11 = 7
- kTLSProtocol12 = 8
- # SecureTransport does not support TLS 1.3 even if there's a constant for it
- kTLSProtocol13 = 10
- kTLSProtocolMaxSupported = 999
-
- kSSLClientSide = 1
- kSSLStreamType = 0
-
- kSecFormatPEMSequence = 10
-
- kSecTrustResultInvalid = 0
- kSecTrustResultProceed = 1
- # This gap is present on purpose: this was kSecTrustResultConfirm, which
- # is deprecated.
- kSecTrustResultDeny = 3
- kSecTrustResultUnspecified = 4
- kSecTrustResultRecoverableTrustFailure = 5
- kSecTrustResultFatalTrustFailure = 6
- kSecTrustResultOtherError = 7
-
- errSSLProtocol = -9800
- errSSLWouldBlock = -9803
- errSSLClosedGraceful = -9805
- errSSLClosedNoNotify = -9816
- errSSLClosedAbort = -9806
-
- errSSLXCertChainInvalid = -9807
- errSSLCrypto = -9809
- errSSLInternal = -9810
- errSSLCertExpired = -9814
- errSSLCertNotYetValid = -9815
- errSSLUnknownRootCert = -9812
- errSSLNoRootCert = -9813
- errSSLHostNameMismatch = -9843
- errSSLPeerHandshakeFail = -9824
- errSSLPeerUserCancelled = -9839
- errSSLWeakPeerEphemeralDHKey = -9850
- errSSLServerAuthCompleted = -9841
- errSSLRecordOverflow = -9847
-
- errSecVerifyFailed = -67808
- errSecNoTrustSettings = -25263
- errSecItemNotFound = -25300
- errSecInvalidTrustSettings = -25262
-
- # Cipher suites. We only pick the ones our default cipher string allows.
- # Source: https://developer.apple.com/documentation/security/1550981-ssl_cipher_suite_values
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8
- TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F
- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033
- TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D
- TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C
- TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D
- TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C
- TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035
- TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F
- TLS_AES_128_GCM_SHA256 = 0x1301
- TLS_AES_256_GCM_SHA384 = 0x1302
- TLS_AES_128_CCM_8_SHA256 = 0x1305
- TLS_AES_128_CCM_SHA256 = 0x1304
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/low_level.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/low_level.py
deleted file mode 100644
index ed8120190c..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/_securetransport/low_level.py
+++ /dev/null
@@ -1,396 +0,0 @@
-"""
-Low-level helpers for the SecureTransport bindings.
-
-These are Python functions that are not directly related to the high-level APIs
-but are necessary to get them to work. They include a whole bunch of low-level
-CoreFoundation messing about and memory management. The concerns in this module
-are almost entirely about trying to avoid memory leaks and providing
-appropriate and useful assistance to the higher-level code.
-"""
-import base64
-import ctypes
-import itertools
-import os
-import re
-import ssl
-import struct
-import tempfile
-
-from .bindings import CFConst, CoreFoundation, Security
-
-# This regular expression is used to grab PEM data out of a PEM bundle.
-_PEM_CERTS_RE = re.compile(
- b"-----BEGIN CERTIFICATE-----\n(.*?)\n-----END CERTIFICATE-----", re.DOTALL
-)
-
-
-def _cf_data_from_bytes(bytestring):
- """
- Given a bytestring, create a CFData object from it. This CFData object must
- be CFReleased by the caller.
- """
- return CoreFoundation.CFDataCreate(
- CoreFoundation.kCFAllocatorDefault, bytestring, len(bytestring)
- )
-
-
-def _cf_dictionary_from_tuples(tuples):
- """
- Given a list of Python tuples, create an associated CFDictionary.
- """
- dictionary_size = len(tuples)
-
- # We need to get the dictionary keys and values out in the same order.
- keys = (t[0] for t in tuples)
- values = (t[1] for t in tuples)
- cf_keys = (CoreFoundation.CFTypeRef * dictionary_size)(*keys)
- cf_values = (CoreFoundation.CFTypeRef * dictionary_size)(*values)
-
- return CoreFoundation.CFDictionaryCreate(
- CoreFoundation.kCFAllocatorDefault,
- cf_keys,
- cf_values,
- dictionary_size,
- CoreFoundation.kCFTypeDictionaryKeyCallBacks,
- CoreFoundation.kCFTypeDictionaryValueCallBacks,
- )
-
-
-def _cfstr(py_bstr):
- """
- Given a Python binary data, create a CFString.
- The string must be CFReleased by the caller.
- """
- c_str = ctypes.c_char_p(py_bstr)
- cf_str = CoreFoundation.CFStringCreateWithCString(
- CoreFoundation.kCFAllocatorDefault,
- c_str,
- CFConst.kCFStringEncodingUTF8,
- )
- return cf_str
-
-
-def _create_cfstring_array(lst):
- """
- Given a list of Python binary data, create an associated CFMutableArray.
- The array must be CFReleased by the caller.
-
- Raises an ssl.SSLError on failure.
- """
- cf_arr = None
- try:
- cf_arr = CoreFoundation.CFArrayCreateMutable(
- CoreFoundation.kCFAllocatorDefault,
- 0,
- ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
- )
- if not cf_arr:
- raise MemoryError("Unable to allocate memory!")
- for item in lst:
- cf_str = _cfstr(item)
- if not cf_str:
- raise MemoryError("Unable to allocate memory!")
- try:
- CoreFoundation.CFArrayAppendValue(cf_arr, cf_str)
- finally:
- CoreFoundation.CFRelease(cf_str)
- except BaseException as e:
- if cf_arr:
- CoreFoundation.CFRelease(cf_arr)
- raise ssl.SSLError("Unable to allocate array: %s" % (e,))
- return cf_arr
-
-
-def _cf_string_to_unicode(value):
- """
- Creates a Unicode string from a CFString object. Used entirely for error
- reporting.
-
- Yes, it annoys me quite a lot that this function is this complex.
- """
- value_as_void_p = ctypes.cast(value, ctypes.POINTER(ctypes.c_void_p))
-
- string = CoreFoundation.CFStringGetCStringPtr(
- value_as_void_p, CFConst.kCFStringEncodingUTF8
- )
- if string is None:
- buffer = ctypes.create_string_buffer(1024)
- result = CoreFoundation.CFStringGetCString(
- value_as_void_p, buffer, 1024, CFConst.kCFStringEncodingUTF8
- )
- if not result:
- raise OSError("Error copying C string from CFStringRef")
- string = buffer.value
- if string is not None:
- string = string.decode("utf-8")
- return string
-
-
-def _assert_no_error(error, exception_class=None):
- """
- Checks the return code and throws an exception if there is an error to
- report
- """
- if error == 0:
- return
-
- cf_error_string = Security.SecCopyErrorMessageString(error, None)
- output = _cf_string_to_unicode(cf_error_string)
- CoreFoundation.CFRelease(cf_error_string)
-
- if output is None or output == u"":
- output = u"OSStatus %s" % error
-
- if exception_class is None:
- exception_class = ssl.SSLError
-
- raise exception_class(output)
-
-
-def _cert_array_from_pem(pem_bundle):
- """
- Given a bundle of certs in PEM format, turns them into a CFArray of certs
- that can be used to validate a cert chain.
- """
- # Normalize the PEM bundle's line endings.
- pem_bundle = pem_bundle.replace(b"\r\n", b"\n")
-
- der_certs = [
- base64.b64decode(match.group(1)) for match in _PEM_CERTS_RE.finditer(pem_bundle)
- ]
- if not der_certs:
- raise ssl.SSLError("No root certificates specified")
-
- cert_array = CoreFoundation.CFArrayCreateMutable(
- CoreFoundation.kCFAllocatorDefault,
- 0,
- ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
- )
- if not cert_array:
- raise ssl.SSLError("Unable to allocate memory!")
-
- try:
- for der_bytes in der_certs:
- certdata = _cf_data_from_bytes(der_bytes)
- if not certdata:
- raise ssl.SSLError("Unable to allocate memory!")
- cert = Security.SecCertificateCreateWithData(
- CoreFoundation.kCFAllocatorDefault, certdata
- )
- CoreFoundation.CFRelease(certdata)
- if not cert:
- raise ssl.SSLError("Unable to build cert object!")
-
- CoreFoundation.CFArrayAppendValue(cert_array, cert)
- CoreFoundation.CFRelease(cert)
- except Exception:
- # We need to free the array before the exception bubbles further.
- # We only want to do that if an error occurs: otherwise, the caller
- # should free.
- CoreFoundation.CFRelease(cert_array)
-
- return cert_array
-
-
-def _is_cert(item):
- """
- Returns True if a given CFTypeRef is a certificate.
- """
- expected = Security.SecCertificateGetTypeID()
- return CoreFoundation.CFGetTypeID(item) == expected
-
-
-def _is_identity(item):
- """
- Returns True if a given CFTypeRef is an identity.
- """
- expected = Security.SecIdentityGetTypeID()
- return CoreFoundation.CFGetTypeID(item) == expected
-
-
-def _temporary_keychain():
- """
- This function creates a temporary Mac keychain that we can use to work with
- credentials. This keychain uses a one-time password and a temporary file to
- store the data. We expect to have one keychain per socket. The returned
- SecKeychainRef must be freed by the caller, including calling
- SecKeychainDelete.
-
- Returns a tuple of the SecKeychainRef and the path to the temporary
- directory that contains it.
- """
- # Unfortunately, SecKeychainCreate requires a path to a keychain. This
- # means we cannot use mkstemp to use a generic temporary file. Instead,
- # we're going to create a temporary directory and a filename to use there.
- # This filename will be 8 random bytes expanded into base64. We also need
- # some random bytes to password-protect the keychain we're creating, so we
- # ask for 40 random bytes.
- random_bytes = os.urandom(40)
- filename = base64.b16encode(random_bytes[:8]).decode("utf-8")
- password = base64.b16encode(random_bytes[8:]) # Must be valid UTF-8
- tempdirectory = tempfile.mkdtemp()
-
- keychain_path = os.path.join(tempdirectory, filename).encode("utf-8")
-
- # We now want to create the keychain itself.
- keychain = Security.SecKeychainRef()
- status = Security.SecKeychainCreate(
- keychain_path, len(password), password, False, None, ctypes.byref(keychain)
- )
- _assert_no_error(status)
-
- # Having created the keychain, we want to pass it off to the caller.
- return keychain, tempdirectory
-
-
-def _load_items_from_file(keychain, path):
- """
- Given a single file, loads all the trust objects from it into arrays and
- the keychain.
- Returns a tuple of lists: the first list is a list of identities, the
- second a list of certs.
- """
- certificates = []
- identities = []
- result_array = None
-
- with open(path, "rb") as f:
- raw_filedata = f.read()
-
- try:
- filedata = CoreFoundation.CFDataCreate(
- CoreFoundation.kCFAllocatorDefault, raw_filedata, len(raw_filedata)
- )
- result_array = CoreFoundation.CFArrayRef()
- result = Security.SecItemImport(
- filedata, # cert data
- None, # Filename, leaving it out for now
- None, # What the type of the file is, we don't care
- None, # what's in the file, we don't care
- 0, # import flags
- None, # key params, can include passphrase in the future
- keychain, # The keychain to insert into
- ctypes.byref(result_array), # Results
- )
- _assert_no_error(result)
-
- # A CFArray is not very useful to us as an intermediary
- # representation, so we are going to extract the objects we want
- # and then free the array. We don't need to keep hold of keys: the
- # keychain already has them!
- result_count = CoreFoundation.CFArrayGetCount(result_array)
- for index in range(result_count):
- item = CoreFoundation.CFArrayGetValueAtIndex(result_array, index)
- item = ctypes.cast(item, CoreFoundation.CFTypeRef)
-
- if _is_cert(item):
- CoreFoundation.CFRetain(item)
- certificates.append(item)
- elif _is_identity(item):
- CoreFoundation.CFRetain(item)
- identities.append(item)
- finally:
- if result_array:
- CoreFoundation.CFRelease(result_array)
-
- CoreFoundation.CFRelease(filedata)
-
- return (identities, certificates)
-
-
-def _load_client_cert_chain(keychain, *paths):
- """
- Load certificates and maybe keys from a number of files. Has the end goal
- of returning a CFArray containing one SecIdentityRef, and then zero or more
- SecCertificateRef objects, suitable for use as a client certificate trust
- chain.
- """
- # Ok, the strategy.
- #
- # This relies on knowing that macOS will not give you a SecIdentityRef
- # unless you have imported a key into a keychain. This is a somewhat
- # artificial limitation of macOS (for example, it doesn't necessarily
- # affect iOS), but there is nothing inside Security.framework that lets you
- # get a SecIdentityRef without having a key in a keychain.
- #
- # So the policy here is we take all the files and iterate them in order.
- # Each one will use SecItemImport to have one or more objects loaded from
- # it. We will also point at a keychain that macOS can use to work with the
- # private key.
- #
- # Once we have all the objects, we'll check what we actually have. If we
- # already have a SecIdentityRef in hand, fab: we'll use that. Otherwise,
- # we'll take the first certificate (which we assume to be our leaf) and
- # ask the keychain to give us a SecIdentityRef with that cert's associated
- # key.
- #
- # We'll then return a CFArray containing the trust chain: one
- # SecIdentityRef and then zero-or-more SecCertificateRef objects. The
- # responsibility for freeing this CFArray will be with the caller. This
- # CFArray must remain alive for the entire connection, so in practice it
- # will be stored with a single SSLSocket, along with the reference to the
- # keychain.
- certificates = []
- identities = []
-
- # Filter out bad paths.
- paths = (path for path in paths if path)
-
- try:
- for file_path in paths:
- new_identities, new_certs = _load_items_from_file(keychain, file_path)
- identities.extend(new_identities)
- certificates.extend(new_certs)
-
- # Ok, we have everything. The question is: do we have an identity? If
- # not, we want to grab one from the first cert we have.
- if not identities:
- new_identity = Security.SecIdentityRef()
- status = Security.SecIdentityCreateWithCertificate(
- keychain, certificates[0], ctypes.byref(new_identity)
- )
- _assert_no_error(status)
- identities.append(new_identity)
-
- # We now want to release the original certificate, as we no longer
- # need it.
- CoreFoundation.CFRelease(certificates.pop(0))
-
- # We now need to build a new CFArray that holds the trust chain.
- trust_chain = CoreFoundation.CFArrayCreateMutable(
- CoreFoundation.kCFAllocatorDefault,
- 0,
- ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
- )
- for item in itertools.chain(identities, certificates):
- # ArrayAppendValue does a CFRetain on the item. That's fine,
- # because the finally block will release our other refs to them.
- CoreFoundation.CFArrayAppendValue(trust_chain, item)
-
- return trust_chain
- finally:
- for obj in itertools.chain(identities, certificates):
- CoreFoundation.CFRelease(obj)
-
-
-TLS_PROTOCOL_VERSIONS = {
- "SSLv2": (0, 2),
- "SSLv3": (3, 0),
- "TLSv1": (3, 1),
- "TLSv1.1": (3, 2),
- "TLSv1.2": (3, 3),
-}
-
-
-def _build_tls_unknown_ca_alert(version):
- """
- Builds a TLS alert record for an unknown CA.
- """
- ver_maj, ver_min = TLS_PROTOCOL_VERSIONS[version]
- severity_fatal = 0x02
- description_unknown_ca = 0x30
- msg = struct.pack(">BB", severity_fatal, description_unknown_ca)
- msg_len = len(msg)
- record_type_alert = 0x15
- record = struct.pack(">BBBH", record_type_alert, ver_maj, ver_min, msg_len) + msg
- return record
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/appengine.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/appengine.py
deleted file mode 100644
index f91bdd6e77..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/appengine.py
+++ /dev/null
@@ -1,314 +0,0 @@
-"""
-This module provides a pool manager that uses Google App Engine's
-`URLFetch Service `_.
-
-Example usage::
-
- from urllib3 import PoolManager
- from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox
-
- if is_appengine_sandbox():
- # AppEngineManager uses AppEngine's URLFetch API behind the scenes
- http = AppEngineManager()
- else:
- # PoolManager uses a socket-level API behind the scenes
- http = PoolManager()
-
- r = http.request('GET', 'https://google.com/')
-
-There are `limitations `_ to the URLFetch service and it may not be
-the best choice for your application. There are three options for using
-urllib3 on Google App Engine:
-
-1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is
- cost-effective in many circumstances as long as your usage is within the
- limitations.
-2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets.
- Sockets also have `limitations and restrictions
- `_ and have a lower free quota than URLFetch.
- To use sockets, be sure to specify the following in your ``app.yaml``::
-
- env_variables:
- GAE_USE_SOCKETS_HTTPLIB : 'true'
-
-3. If you are using `App Engine Flexible
-`_, you can use the standard
-:class:`PoolManager` without any configuration or special environment variables.
-"""
-
-from __future__ import absolute_import
-
-import io
-import logging
-import warnings
-
-from ..exceptions import (
- HTTPError,
- HTTPWarning,
- MaxRetryError,
- ProtocolError,
- SSLError,
- TimeoutError,
-)
-from ..packages.six.moves.urllib.parse import urljoin
-from ..request import RequestMethods
-from ..response import HTTPResponse
-from ..util.retry import Retry
-from ..util.timeout import Timeout
-from . import _appengine_environ
-
-try:
- from google.appengine.api import urlfetch
-except ImportError:
- urlfetch = None
-
-
-log = logging.getLogger(__name__)
-
-
-class AppEnginePlatformWarning(HTTPWarning):
- pass
-
-
-class AppEnginePlatformError(HTTPError):
- pass
-
-
-class AppEngineManager(RequestMethods):
- """
- Connection manager for Google App Engine sandbox applications.
-
- This manager uses the URLFetch service directly instead of using the
- emulated httplib, and is subject to URLFetch limitations as described in
- the App Engine documentation `here
- `_.
-
- Notably it will raise an :class:`AppEnginePlatformError` if:
- * URLFetch is not available.
- * If you attempt to use this on App Engine Flexible, as full socket
- support is available.
- * If a request size is more than 10 megabytes.
- * If a response size is more than 32 megabytes.
- * If you use an unsupported request method such as OPTIONS.
-
- Beyond those cases, it will raise normal urllib3 errors.
- """
-
- def __init__(
- self,
- headers=None,
- retries=None,
- validate_certificate=True,
- urlfetch_retries=True,
- ):
- if not urlfetch:
- raise AppEnginePlatformError(
- "URLFetch is not available in this environment."
- )
-
- warnings.warn(
- "urllib3 is using URLFetch on Google App Engine sandbox instead "
- "of sockets. To use sockets directly instead of URLFetch see "
- "https://urllib3.readthedocs.io/en/1.26.x/reference/urllib3.contrib.html.",
- AppEnginePlatformWarning,
- )
-
- RequestMethods.__init__(self, headers)
- self.validate_certificate = validate_certificate
- self.urlfetch_retries = urlfetch_retries
-
- self.retries = retries or Retry.DEFAULT
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- # Return False to re-raise any potential exceptions
- return False
-
- def urlopen(
- self,
- method,
- url,
- body=None,
- headers=None,
- retries=None,
- redirect=True,
- timeout=Timeout.DEFAULT_TIMEOUT,
- **response_kw
- ):
-
- retries = self._get_retries(retries, redirect)
-
- try:
- follow_redirects = redirect and retries.redirect != 0 and retries.total
- response = urlfetch.fetch(
- url,
- payload=body,
- method=method,
- headers=headers or {},
- allow_truncated=False,
- follow_redirects=self.urlfetch_retries and follow_redirects,
- deadline=self._get_absolute_timeout(timeout),
- validate_certificate=self.validate_certificate,
- )
- except urlfetch.DeadlineExceededError as e:
- raise TimeoutError(self, e)
-
- except urlfetch.InvalidURLError as e:
- if "too large" in str(e):
- raise AppEnginePlatformError(
- "URLFetch request too large, URLFetch only "
- "supports requests up to 10mb in size.",
- e,
- )
- raise ProtocolError(e)
-
- except urlfetch.DownloadError as e:
- if "Too many redirects" in str(e):
- raise MaxRetryError(self, url, reason=e)
- raise ProtocolError(e)
-
- except urlfetch.ResponseTooLargeError as e:
- raise AppEnginePlatformError(
- "URLFetch response too large, URLFetch only supports"
- "responses up to 32mb in size.",
- e,
- )
-
- except urlfetch.SSLCertificateError as e:
- raise SSLError(e)
-
- except urlfetch.InvalidMethodError as e:
- raise AppEnginePlatformError(
- "URLFetch does not support method: %s" % method, e
- )
-
- http_response = self._urlfetch_response_to_http_response(
- response, retries=retries, **response_kw
- )
-
- # Handle redirect?
- redirect_location = redirect and http_response.get_redirect_location()
- if redirect_location:
- # Check for redirect response
- if self.urlfetch_retries and retries.raise_on_redirect:
- raise MaxRetryError(self, url, "too many redirects")
- else:
- if http_response.status == 303:
- method = "GET"
-
- try:
- retries = retries.increment(
- method, url, response=http_response, _pool=self
- )
- except MaxRetryError:
- if retries.raise_on_redirect:
- raise MaxRetryError(self, url, "too many redirects")
- return http_response
-
- retries.sleep_for_retry(http_response)
- log.debug("Redirecting %s -> %s", url, redirect_location)
- redirect_url = urljoin(url, redirect_location)
- return self.urlopen(
- method,
- redirect_url,
- body,
- headers,
- retries=retries,
- redirect=redirect,
- timeout=timeout,
- **response_kw
- )
-
- # Check if we should retry the HTTP response.
- has_retry_after = bool(http_response.getheader("Retry-After"))
- if retries.is_retry(method, http_response.status, has_retry_after):
- retries = retries.increment(method, url, response=http_response, _pool=self)
- log.debug("Retry: %s", url)
- retries.sleep(http_response)
- return self.urlopen(
- method,
- url,
- body=body,
- headers=headers,
- retries=retries,
- redirect=redirect,
- timeout=timeout,
- **response_kw
- )
-
- return http_response
-
- def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw):
-
- if is_prod_appengine():
- # Production GAE handles deflate encoding automatically, but does
- # not remove the encoding header.
- content_encoding = urlfetch_resp.headers.get("content-encoding")
-
- if content_encoding == "deflate":
- del urlfetch_resp.headers["content-encoding"]
-
- transfer_encoding = urlfetch_resp.headers.get("transfer-encoding")
- # We have a full response's content,
- # so let's make sure we don't report ourselves as chunked data.
- if transfer_encoding == "chunked":
- encodings = transfer_encoding.split(",")
- encodings.remove("chunked")
- urlfetch_resp.headers["transfer-encoding"] = ",".join(encodings)
-
- original_response = HTTPResponse(
- # In order for decoding to work, we must present the content as
- # a file-like object.
- body=io.BytesIO(urlfetch_resp.content),
- msg=urlfetch_resp.header_msg,
- headers=urlfetch_resp.headers,
- status=urlfetch_resp.status_code,
- **response_kw
- )
-
- return HTTPResponse(
- body=io.BytesIO(urlfetch_resp.content),
- headers=urlfetch_resp.headers,
- status=urlfetch_resp.status_code,
- original_response=original_response,
- **response_kw
- )
-
- def _get_absolute_timeout(self, timeout):
- if timeout is Timeout.DEFAULT_TIMEOUT:
- return None # Defer to URLFetch's default.
- if isinstance(timeout, Timeout):
- if timeout._read is not None or timeout._connect is not None:
- warnings.warn(
- "URLFetch does not support granular timeout settings, "
- "reverting to total or default URLFetch timeout.",
- AppEnginePlatformWarning,
- )
- return timeout.total
- return timeout
-
- def _get_retries(self, retries, redirect):
- if not isinstance(retries, Retry):
- retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
-
- if retries.connect or retries.read or retries.redirect:
- warnings.warn(
- "URLFetch only supports total retries and does not "
- "recognize connect, read, or redirect retry parameters.",
- AppEnginePlatformWarning,
- )
-
- return retries
-
-
-# Alias methods from _appengine_environ to maintain public API interface.
-
-is_appengine = _appengine_environ.is_appengine
-is_appengine_sandbox = _appengine_environ.is_appengine_sandbox
-is_local_appengine = _appengine_environ.is_local_appengine
-is_prod_appengine = _appengine_environ.is_prod_appengine
-is_prod_appengine_mvms = _appengine_environ.is_prod_appengine_mvms
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/ntlmpool.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/ntlmpool.py
deleted file mode 100644
index 41a8fd174c..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/ntlmpool.py
+++ /dev/null
@@ -1,130 +0,0 @@
-"""
-NTLM authenticating pool, contributed by erikcederstran
-
-Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10
-"""
-from __future__ import absolute_import
-
-import warnings
-from logging import getLogger
-
-from ntlm import ntlm
-
-from .. import HTTPSConnectionPool
-from ..packages.six.moves.http_client import HTTPSConnection
-
-warnings.warn(
- "The 'urllib3.contrib.ntlmpool' module is deprecated and will be removed "
- "in urllib3 v2.0 release, urllib3 is not able to support it properly due "
- "to reasons listed in issue: https://github.com/urllib3/urllib3/issues/2282. "
- "If you are a user of this module please comment in the mentioned issue.",
- DeprecationWarning,
-)
-
-log = getLogger(__name__)
-
-
-class NTLMConnectionPool(HTTPSConnectionPool):
- """
- Implements an NTLM authentication version of an urllib3 connection pool
- """
-
- scheme = "https"
-
- def __init__(self, user, pw, authurl, *args, **kwargs):
- """
- authurl is a random URL on the server that is protected by NTLM.
- user is the Windows user, probably in the DOMAIN\\username format.
- pw is the password for the user.
- """
- super(NTLMConnectionPool, self).__init__(*args, **kwargs)
- self.authurl = authurl
- self.rawuser = user
- user_parts = user.split("\\", 1)
- self.domain = user_parts[0].upper()
- self.user = user_parts[1]
- self.pw = pw
-
- def _new_conn(self):
- # Performs the NTLM handshake that secures the connection. The socket
- # must be kept open while requests are performed.
- self.num_connections += 1
- log.debug(
- "Starting NTLM HTTPS connection no. %d: https://%s%s",
- self.num_connections,
- self.host,
- self.authurl,
- )
-
- headers = {"Connection": "Keep-Alive"}
- req_header = "Authorization"
- resp_header = "www-authenticate"
-
- conn = HTTPSConnection(host=self.host, port=self.port)
-
- # Send negotiation message
- headers[req_header] = "NTLM %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE(
- self.rawuser
- )
- log.debug("Request headers: %s", headers)
- conn.request("GET", self.authurl, None, headers)
- res = conn.getresponse()
- reshdr = dict(res.getheaders())
- log.debug("Response status: %s %s", res.status, res.reason)
- log.debug("Response headers: %s", reshdr)
- log.debug("Response data: %s [...]", res.read(100))
-
- # Remove the reference to the socket, so that it can not be closed by
- # the response object (we want to keep the socket open)
- res.fp = None
-
- # Server should respond with a challenge message
- auth_header_values = reshdr[resp_header].split(", ")
- auth_header_value = None
- for s in auth_header_values:
- if s[:5] == "NTLM ":
- auth_header_value = s[5:]
- if auth_header_value is None:
- raise Exception(
- "Unexpected %s response header: %s" % (resp_header, reshdr[resp_header])
- )
-
- # Send authentication message
- ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(
- auth_header_value
- )
- auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(
- ServerChallenge, self.user, self.domain, self.pw, NegotiateFlags
- )
- headers[req_header] = "NTLM %s" % auth_msg
- log.debug("Request headers: %s", headers)
- conn.request("GET", self.authurl, None, headers)
- res = conn.getresponse()
- log.debug("Response status: %s %s", res.status, res.reason)
- log.debug("Response headers: %s", dict(res.getheaders()))
- log.debug("Response data: %s [...]", res.read()[:100])
- if res.status != 200:
- if res.status == 401:
- raise Exception("Server rejected request: wrong username or password")
- raise Exception("Wrong server response: %s %s" % (res.status, res.reason))
-
- res.fp = None
- log.debug("Connection established")
- return conn
-
- def urlopen(
- self,
- method,
- url,
- body=None,
- headers=None,
- retries=3,
- redirect=True,
- assert_same_host=True,
- ):
- if headers is None:
- headers = {}
- headers["Connection"] = "Keep-Alive"
- return super(NTLMConnectionPool, self).urlopen(
- method, url, body, headers, retries, redirect, assert_same_host
- )
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/pyopenssl.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/pyopenssl.py
deleted file mode 100644
index def83afdb2..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/pyopenssl.py
+++ /dev/null
@@ -1,511 +0,0 @@
-"""
-TLS with SNI_-support for Python 2. Follow these instructions if you would
-like to verify TLS certificates in Python 2. Note, the default libraries do
-*not* do certificate checking; you need to do additional work to validate
-certificates yourself.
-
-This needs the following packages installed:
-
-* `pyOpenSSL`_ (tested with 16.0.0)
-* `cryptography`_ (minimum 1.3.4, from pyopenssl)
-* `idna`_ (minimum 2.0, from cryptography)
-
-However, pyopenssl depends on cryptography, which depends on idna, so while we
-use all three directly here we end up having relatively few packages required.
-
-You can install them with the following command:
-
-.. code-block:: bash
-
- $ python -m pip install pyopenssl cryptography idna
-
-To activate certificate checking, call
-:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code
-before you begin making HTTP requests. This can be done in a ``sitecustomize``
-module, or at any other time before your application begins using ``urllib3``,
-like this:
-
-.. code-block:: python
-
- try:
- import urllib3.contrib.pyopenssl
- urllib3.contrib.pyopenssl.inject_into_urllib3()
- except ImportError:
- pass
-
-Now you can use :mod:`urllib3` as you normally would, and it will support SNI
-when the required modules are installed.
-
-Activating this module also has the positive side effect of disabling SSL/TLS
-compression in Python 2 (see `CRIME attack`_).
-
-.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication
-.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit)
-.. _pyopenssl: https://www.pyopenssl.org
-.. _cryptography: https://cryptography.io
-.. _idna: https://github.com/kjd/idna
-"""
-from __future__ import absolute_import
-
-import OpenSSL.SSL
-from cryptography import x509
-from cryptography.hazmat.backends.openssl import backend as openssl_backend
-from cryptography.hazmat.backends.openssl.x509 import _Certificate
-
-try:
- from cryptography.x509 import UnsupportedExtension
-except ImportError:
- # UnsupportedExtension is gone in cryptography >= 2.1.0
- class UnsupportedExtension(Exception):
- pass
-
-
-from io import BytesIO
-from socket import error as SocketError
-from socket import timeout
-
-try: # Platform-specific: Python 2
- from socket import _fileobject
-except ImportError: # Platform-specific: Python 3
- _fileobject = None
- from ..packages.backports.makefile import backport_makefile
-
-import logging
-import ssl
-import sys
-
-from .. import util
-from ..packages import six
-from ..util.ssl_ import PROTOCOL_TLS_CLIENT
-
-__all__ = ["inject_into_urllib3", "extract_from_urllib3"]
-
-# SNI always works.
-HAS_SNI = True
-
-# Map from urllib3 to PyOpenSSL compatible parameter-values.
-_openssl_versions = {
- util.PROTOCOL_TLS: OpenSSL.SSL.SSLv23_METHOD,
- PROTOCOL_TLS_CLIENT: OpenSSL.SSL.SSLv23_METHOD,
- ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,
-}
-
-if hasattr(ssl, "PROTOCOL_SSLv3") and hasattr(OpenSSL.SSL, "SSLv3_METHOD"):
- _openssl_versions[ssl.PROTOCOL_SSLv3] = OpenSSL.SSL.SSLv3_METHOD
-
-if hasattr(ssl, "PROTOCOL_TLSv1_1") and hasattr(OpenSSL.SSL, "TLSv1_1_METHOD"):
- _openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD
-
-if hasattr(ssl, "PROTOCOL_TLSv1_2") and hasattr(OpenSSL.SSL, "TLSv1_2_METHOD"):
- _openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD
-
-
-_stdlib_to_openssl_verify = {
- ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE,
- ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER,
- ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER
- + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
-}
-_openssl_to_stdlib_verify = dict((v, k) for k, v in _stdlib_to_openssl_verify.items())
-
-# OpenSSL will only write 16K at a time
-SSL_WRITE_BLOCKSIZE = 16384
-
-orig_util_HAS_SNI = util.HAS_SNI
-orig_util_SSLContext = util.ssl_.SSLContext
-
-
-log = logging.getLogger(__name__)
-
-
-def inject_into_urllib3():
- "Monkey-patch urllib3 with PyOpenSSL-backed SSL-support."
-
- _validate_dependencies_met()
-
- util.SSLContext = PyOpenSSLContext
- util.ssl_.SSLContext = PyOpenSSLContext
- util.HAS_SNI = HAS_SNI
- util.ssl_.HAS_SNI = HAS_SNI
- util.IS_PYOPENSSL = True
- util.ssl_.IS_PYOPENSSL = True
-
-
-def extract_from_urllib3():
- "Undo monkey-patching by :func:`inject_into_urllib3`."
-
- util.SSLContext = orig_util_SSLContext
- util.ssl_.SSLContext = orig_util_SSLContext
- util.HAS_SNI = orig_util_HAS_SNI
- util.ssl_.HAS_SNI = orig_util_HAS_SNI
- util.IS_PYOPENSSL = False
- util.ssl_.IS_PYOPENSSL = False
-
-
-def _validate_dependencies_met():
- """
- Verifies that PyOpenSSL's package-level dependencies have been met.
- Throws `ImportError` if they are not met.
- """
- # Method added in `cryptography==1.1`; not available in older versions
- from cryptography.x509.extensions import Extensions
-
- if getattr(Extensions, "get_extension_for_class", None) is None:
- raise ImportError(
- "'cryptography' module missing required functionality. "
- "Try upgrading to v1.3.4 or newer."
- )
-
- # pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509
- # attribute is only present on those versions.
- from OpenSSL.crypto import X509
-
- x509 = X509()
- if getattr(x509, "_x509", None) is None:
- raise ImportError(
- "'pyOpenSSL' module missing required functionality. "
- "Try upgrading to v0.14 or newer."
- )
-
-
-def _dnsname_to_stdlib(name):
- """
- Converts a dNSName SubjectAlternativeName field to the form used by the
- standard library on the given Python version.
-
- Cryptography produces a dNSName as a unicode string that was idna-decoded
- from ASCII bytes. We need to idna-encode that string to get it back, and
- then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib
- uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8).
-
- If the name cannot be idna-encoded then we return None signalling that
- the name given should be skipped.
- """
-
- def idna_encode(name):
- """
- Borrowed wholesale from the Python Cryptography Project. It turns out
- that we can't just safely call `idna.encode`: it can explode for
- wildcard names. This avoids that problem.
- """
- import idna
-
- try:
- for prefix in [u"*.", u"."]:
- if name.startswith(prefix):
- name = name[len(prefix) :]
- return prefix.encode("ascii") + idna.encode(name)
- return idna.encode(name)
- except idna.core.IDNAError:
- return None
-
- # Don't send IPv6 addresses through the IDNA encoder.
- if ":" in name:
- return name
-
- name = idna_encode(name)
- if name is None:
- return None
- elif sys.version_info >= (3, 0):
- name = name.decode("utf-8")
- return name
-
-
-def get_subj_alt_name(peer_cert):
- """
- Given an PyOpenSSL certificate, provides all the subject alternative names.
- """
- # Pass the cert to cryptography, which has much better APIs for this.
- if hasattr(peer_cert, "to_cryptography"):
- cert = peer_cert.to_cryptography()
- else:
- # This is technically using private APIs, but should work across all
- # relevant versions before PyOpenSSL got a proper API for this.
- cert = _Certificate(openssl_backend, peer_cert._x509)
-
- # We want to find the SAN extension. Ask Cryptography to locate it (it's
- # faster than looping in Python)
- try:
- ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value
- except x509.ExtensionNotFound:
- # No such extension, return the empty list.
- return []
- except (
- x509.DuplicateExtension,
- UnsupportedExtension,
- x509.UnsupportedGeneralNameType,
- UnicodeError,
- ) as e:
- # A problem has been found with the quality of the certificate. Assume
- # no SAN field is present.
- log.warning(
- "A problem was encountered with the certificate that prevented "
- "urllib3 from finding the SubjectAlternativeName field. This can "
- "affect certificate validation. The error was %s",
- e,
- )
- return []
-
- # We want to return dNSName and iPAddress fields. We need to cast the IPs
- # back to strings because the match_hostname function wants them as
- # strings.
- # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8
- # decoded. This is pretty frustrating, but that's what the standard library
- # does with certificates, and so we need to attempt to do the same.
- # We also want to skip over names which cannot be idna encoded.
- names = [
- ("DNS", name)
- for name in map(_dnsname_to_stdlib, ext.get_values_for_type(x509.DNSName))
- if name is not None
- ]
- names.extend(
- ("IP Address", str(name)) for name in ext.get_values_for_type(x509.IPAddress)
- )
-
- return names
-
-
-class WrappedSocket(object):
- """API-compatibility wrapper for Python OpenSSL's Connection-class.
-
- Note: _makefile_refs, _drop() and _reuse() are needed for the garbage
- collector of pypy.
- """
-
- def __init__(self, connection, socket, suppress_ragged_eofs=True):
- self.connection = connection
- self.socket = socket
- self.suppress_ragged_eofs = suppress_ragged_eofs
- self._makefile_refs = 0
- self._closed = False
-
- def fileno(self):
- return self.socket.fileno()
-
- # Copy-pasted from Python 3.5 source code
- def _decref_socketios(self):
- if self._makefile_refs > 0:
- self._makefile_refs -= 1
- if self._closed:
- self.close()
-
- def recv(self, *args, **kwargs):
- try:
- data = self.connection.recv(*args, **kwargs)
- except OpenSSL.SSL.SysCallError as e:
- if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"):
- return b""
- else:
- raise SocketError(str(e))
- except OpenSSL.SSL.ZeroReturnError:
- if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:
- return b""
- else:
- raise
- except OpenSSL.SSL.WantReadError:
- if not util.wait_for_read(self.socket, self.socket.gettimeout()):
- raise timeout("The read operation timed out")
- else:
- return self.recv(*args, **kwargs)
-
- # TLS 1.3 post-handshake authentication
- except OpenSSL.SSL.Error as e:
- raise ssl.SSLError("read error: %r" % e)
- else:
- return data
-
- def recv_into(self, *args, **kwargs):
- try:
- return self.connection.recv_into(*args, **kwargs)
- except OpenSSL.SSL.SysCallError as e:
- if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"):
- return 0
- else:
- raise SocketError(str(e))
- except OpenSSL.SSL.ZeroReturnError:
- if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:
- return 0
- else:
- raise
- except OpenSSL.SSL.WantReadError:
- if not util.wait_for_read(self.socket, self.socket.gettimeout()):
- raise timeout("The read operation timed out")
- else:
- return self.recv_into(*args, **kwargs)
-
- # TLS 1.3 post-handshake authentication
- except OpenSSL.SSL.Error as e:
- raise ssl.SSLError("read error: %r" % e)
-
- def settimeout(self, timeout):
- return self.socket.settimeout(timeout)
-
- def _send_until_done(self, data):
- while True:
- try:
- return self.connection.send(data)
- except OpenSSL.SSL.WantWriteError:
- if not util.wait_for_write(self.socket, self.socket.gettimeout()):
- raise timeout()
- continue
- except OpenSSL.SSL.SysCallError as e:
- raise SocketError(str(e))
-
- def sendall(self, data):
- total_sent = 0
- while total_sent < len(data):
- sent = self._send_until_done(
- data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE]
- )
- total_sent += sent
-
- def shutdown(self):
- # FIXME rethrow compatible exceptions should we ever use this
- self.connection.shutdown()
-
- def close(self):
- if self._makefile_refs < 1:
- try:
- self._closed = True
- return self.connection.close()
- except OpenSSL.SSL.Error:
- return
- else:
- self._makefile_refs -= 1
-
- def getpeercert(self, binary_form=False):
- x509 = self.connection.get_peer_certificate()
-
- if not x509:
- return x509
-
- if binary_form:
- return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, x509)
-
- return {
- "subject": ((("commonName", x509.get_subject().CN),),),
- "subjectAltName": get_subj_alt_name(x509),
- }
-
- def version(self):
- return self.connection.get_protocol_version_name()
-
- def _reuse(self):
- self._makefile_refs += 1
-
- def _drop(self):
- if self._makefile_refs < 1:
- self.close()
- else:
- self._makefile_refs -= 1
-
-
-if _fileobject: # Platform-specific: Python 2
-
- def makefile(self, mode, bufsize=-1):
- self._makefile_refs += 1
- return _fileobject(self, mode, bufsize, close=True)
-
-
-else: # Platform-specific: Python 3
- makefile = backport_makefile
-
-WrappedSocket.makefile = makefile
-
-
-class PyOpenSSLContext(object):
- """
- I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible
- for translating the interface of the standard library ``SSLContext`` object
- to calls into PyOpenSSL.
- """
-
- def __init__(self, protocol):
- self.protocol = _openssl_versions[protocol]
- self._ctx = OpenSSL.SSL.Context(self.protocol)
- self._options = 0
- self.check_hostname = False
-
- @property
- def options(self):
- return self._options
-
- @options.setter
- def options(self, value):
- self._options = value
- self._ctx.set_options(value)
-
- @property
- def verify_mode(self):
- return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()]
-
- @verify_mode.setter
- def verify_mode(self, value):
- self._ctx.set_verify(_stdlib_to_openssl_verify[value], _verify_callback)
-
- def set_default_verify_paths(self):
- self._ctx.set_default_verify_paths()
-
- def set_ciphers(self, ciphers):
- if isinstance(ciphers, six.text_type):
- ciphers = ciphers.encode("utf-8")
- self._ctx.set_cipher_list(ciphers)
-
- def load_verify_locations(self, cafile=None, capath=None, cadata=None):
- if cafile is not None:
- cafile = cafile.encode("utf-8")
- if capath is not None:
- capath = capath.encode("utf-8")
- try:
- self._ctx.load_verify_locations(cafile, capath)
- if cadata is not None:
- self._ctx.load_verify_locations(BytesIO(cadata))
- except OpenSSL.SSL.Error as e:
- raise ssl.SSLError("unable to load trusted certificates: %r" % e)
-
- def load_cert_chain(self, certfile, keyfile=None, password=None):
- self._ctx.use_certificate_chain_file(certfile)
- if password is not None:
- if not isinstance(password, six.binary_type):
- password = password.encode("utf-8")
- self._ctx.set_passwd_cb(lambda *_: password)
- self._ctx.use_privatekey_file(keyfile or certfile)
-
- def set_alpn_protocols(self, protocols):
- protocols = [six.ensure_binary(p) for p in protocols]
- return self._ctx.set_alpn_protos(protocols)
-
- def wrap_socket(
- self,
- sock,
- server_side=False,
- do_handshake_on_connect=True,
- suppress_ragged_eofs=True,
- server_hostname=None,
- ):
- cnx = OpenSSL.SSL.Connection(self._ctx, sock)
-
- if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3
- server_hostname = server_hostname.encode("utf-8")
-
- if server_hostname is not None:
- cnx.set_tlsext_host_name(server_hostname)
-
- cnx.set_connect_state()
-
- while True:
- try:
- cnx.do_handshake()
- except OpenSSL.SSL.WantReadError:
- if not util.wait_for_read(sock, sock.gettimeout()):
- raise timeout("select timed out")
- continue
- except OpenSSL.SSL.Error as e:
- raise ssl.SSLError("bad handshake: %r" % e)
- break
-
- return WrappedSocket(cnx, sock)
-
-
-def _verify_callback(cnx, x509, err_no, err_depth, return_code):
- return err_no == 0
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/securetransport.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/securetransport.py
deleted file mode 100644
index 554c015fed..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/securetransport.py
+++ /dev/null
@@ -1,922 +0,0 @@
-"""
-SecureTranport support for urllib3 via ctypes.
-
-This makes platform-native TLS available to urllib3 users on macOS without the
-use of a compiler. This is an important feature because the Python Package
-Index is moving to become a TLSv1.2-or-higher server, and the default OpenSSL
-that ships with macOS is not capable of doing TLSv1.2. The only way to resolve
-this is to give macOS users an alternative solution to the problem, and that
-solution is to use SecureTransport.
-
-We use ctypes here because this solution must not require a compiler. That's
-because pip is not allowed to require a compiler either.
-
-This is not intended to be a seriously long-term solution to this problem.
-The hope is that PEP 543 will eventually solve this issue for us, at which
-point we can retire this contrib module. But in the short term, we need to
-solve the impending tire fire that is Python on Mac without this kind of
-contrib module. So...here we are.
-
-To use this module, simply import and inject it::
-
- import urllib3.contrib.securetransport
- urllib3.contrib.securetransport.inject_into_urllib3()
-
-Happy TLSing!
-
-This code is a bastardised version of the code found in Will Bond's oscrypto
-library. An enormous debt is owed to him for blazing this trail for us. For
-that reason, this code should be considered to be covered both by urllib3's
-license and by oscrypto's:
-
-.. code-block::
-
- Copyright (c) 2015-2016 Will Bond
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
-"""
-from __future__ import absolute_import
-
-import contextlib
-import ctypes
-import errno
-import os.path
-import shutil
-import socket
-import ssl
-import struct
-import threading
-import weakref
-
-import six
-
-from .. import util
-from ..util.ssl_ import PROTOCOL_TLS_CLIENT
-from ._securetransport.bindings import CoreFoundation, Security, SecurityConst
-from ._securetransport.low_level import (
- _assert_no_error,
- _build_tls_unknown_ca_alert,
- _cert_array_from_pem,
- _create_cfstring_array,
- _load_client_cert_chain,
- _temporary_keychain,
-)
-
-try: # Platform-specific: Python 2
- from socket import _fileobject
-except ImportError: # Platform-specific: Python 3
- _fileobject = None
- from ..packages.backports.makefile import backport_makefile
-
-__all__ = ["inject_into_urllib3", "extract_from_urllib3"]
-
-# SNI always works
-HAS_SNI = True
-
-orig_util_HAS_SNI = util.HAS_SNI
-orig_util_SSLContext = util.ssl_.SSLContext
-
-# This dictionary is used by the read callback to obtain a handle to the
-# calling wrapped socket. This is a pretty silly approach, but for now it'll
-# do. I feel like I should be able to smuggle a handle to the wrapped socket
-# directly in the SSLConnectionRef, but for now this approach will work I
-# guess.
-#
-# We need to lock around this structure for inserts, but we don't do it for
-# reads/writes in the callbacks. The reasoning here goes as follows:
-#
-# 1. It is not possible to call into the callbacks before the dictionary is
-# populated, so once in the callback the id must be in the dictionary.
-# 2. The callbacks don't mutate the dictionary, they only read from it, and
-# so cannot conflict with any of the insertions.
-#
-# This is good: if we had to lock in the callbacks we'd drastically slow down
-# the performance of this code.
-_connection_refs = weakref.WeakValueDictionary()
-_connection_ref_lock = threading.Lock()
-
-# Limit writes to 16kB. This is OpenSSL's limit, but we'll cargo-cult it over
-# for no better reason than we need *a* limit, and this one is right there.
-SSL_WRITE_BLOCKSIZE = 16384
-
-# This is our equivalent of util.ssl_.DEFAULT_CIPHERS, but expanded out to
-# individual cipher suites. We need to do this because this is how
-# SecureTransport wants them.
-CIPHER_SUITES = [
- SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
- SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
- SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- SecurityConst.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
- SecurityConst.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
- SecurityConst.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
- SecurityConst.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
- SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
- SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
- SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
- SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
- SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
- SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
- SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
- SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
- SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
- SecurityConst.TLS_AES_256_GCM_SHA384,
- SecurityConst.TLS_AES_128_GCM_SHA256,
- SecurityConst.TLS_RSA_WITH_AES_256_GCM_SHA384,
- SecurityConst.TLS_RSA_WITH_AES_128_GCM_SHA256,
- SecurityConst.TLS_AES_128_CCM_8_SHA256,
- SecurityConst.TLS_AES_128_CCM_SHA256,
- SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA256,
- SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA256,
- SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA,
- SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA,
-]
-
-# Basically this is simple: for PROTOCOL_SSLv23 we turn it into a low of
-# TLSv1 and a high of TLSv1.2. For everything else, we pin to that version.
-# TLSv1 to 1.2 are supported on macOS 10.8+
-_protocol_to_min_max = {
- util.PROTOCOL_TLS: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12),
- PROTOCOL_TLS_CLIENT: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12),
-}
-
-if hasattr(ssl, "PROTOCOL_SSLv2"):
- _protocol_to_min_max[ssl.PROTOCOL_SSLv2] = (
- SecurityConst.kSSLProtocol2,
- SecurityConst.kSSLProtocol2,
- )
-if hasattr(ssl, "PROTOCOL_SSLv3"):
- _protocol_to_min_max[ssl.PROTOCOL_SSLv3] = (
- SecurityConst.kSSLProtocol3,
- SecurityConst.kSSLProtocol3,
- )
-if hasattr(ssl, "PROTOCOL_TLSv1"):
- _protocol_to_min_max[ssl.PROTOCOL_TLSv1] = (
- SecurityConst.kTLSProtocol1,
- SecurityConst.kTLSProtocol1,
- )
-if hasattr(ssl, "PROTOCOL_TLSv1_1"):
- _protocol_to_min_max[ssl.PROTOCOL_TLSv1_1] = (
- SecurityConst.kTLSProtocol11,
- SecurityConst.kTLSProtocol11,
- )
-if hasattr(ssl, "PROTOCOL_TLSv1_2"):
- _protocol_to_min_max[ssl.PROTOCOL_TLSv1_2] = (
- SecurityConst.kTLSProtocol12,
- SecurityConst.kTLSProtocol12,
- )
-
-
-def inject_into_urllib3():
- """
- Monkey-patch urllib3 with SecureTransport-backed SSL-support.
- """
- util.SSLContext = SecureTransportContext
- util.ssl_.SSLContext = SecureTransportContext
- util.HAS_SNI = HAS_SNI
- util.ssl_.HAS_SNI = HAS_SNI
- util.IS_SECURETRANSPORT = True
- util.ssl_.IS_SECURETRANSPORT = True
-
-
-def extract_from_urllib3():
- """
- Undo monkey-patching by :func:`inject_into_urllib3`.
- """
- util.SSLContext = orig_util_SSLContext
- util.ssl_.SSLContext = orig_util_SSLContext
- util.HAS_SNI = orig_util_HAS_SNI
- util.ssl_.HAS_SNI = orig_util_HAS_SNI
- util.IS_SECURETRANSPORT = False
- util.ssl_.IS_SECURETRANSPORT = False
-
-
-def _read_callback(connection_id, data_buffer, data_length_pointer):
- """
- SecureTransport read callback. This is called by ST to request that data
- be returned from the socket.
- """
- wrapped_socket = None
- try:
- wrapped_socket = _connection_refs.get(connection_id)
- if wrapped_socket is None:
- return SecurityConst.errSSLInternal
- base_socket = wrapped_socket.socket
-
- requested_length = data_length_pointer[0]
-
- timeout = wrapped_socket.gettimeout()
- error = None
- read_count = 0
-
- try:
- while read_count < requested_length:
- if timeout is None or timeout >= 0:
- if not util.wait_for_read(base_socket, timeout):
- raise socket.error(errno.EAGAIN, "timed out")
-
- remaining = requested_length - read_count
- buffer = (ctypes.c_char * remaining).from_address(
- data_buffer + read_count
- )
- chunk_size = base_socket.recv_into(buffer, remaining)
- read_count += chunk_size
- if not chunk_size:
- if not read_count:
- return SecurityConst.errSSLClosedGraceful
- break
- except (socket.error) as e:
- error = e.errno
-
- if error is not None and error != errno.EAGAIN:
- data_length_pointer[0] = read_count
- if error == errno.ECONNRESET or error == errno.EPIPE:
- return SecurityConst.errSSLClosedAbort
- raise
-
- data_length_pointer[0] = read_count
-
- if read_count != requested_length:
- return SecurityConst.errSSLWouldBlock
-
- return 0
- except Exception as e:
- if wrapped_socket is not None:
- wrapped_socket._exception = e
- return SecurityConst.errSSLInternal
-
-
-def _write_callback(connection_id, data_buffer, data_length_pointer):
- """
- SecureTransport write callback. This is called by ST to request that data
- actually be sent on the network.
- """
- wrapped_socket = None
- try:
- wrapped_socket = _connection_refs.get(connection_id)
- if wrapped_socket is None:
- return SecurityConst.errSSLInternal
- base_socket = wrapped_socket.socket
-
- bytes_to_write = data_length_pointer[0]
- data = ctypes.string_at(data_buffer, bytes_to_write)
-
- timeout = wrapped_socket.gettimeout()
- error = None
- sent = 0
-
- try:
- while sent < bytes_to_write:
- if timeout is None or timeout >= 0:
- if not util.wait_for_write(base_socket, timeout):
- raise socket.error(errno.EAGAIN, "timed out")
- chunk_sent = base_socket.send(data)
- sent += chunk_sent
-
- # This has some needless copying here, but I'm not sure there's
- # much value in optimising this data path.
- data = data[chunk_sent:]
- except (socket.error) as e:
- error = e.errno
-
- if error is not None and error != errno.EAGAIN:
- data_length_pointer[0] = sent
- if error == errno.ECONNRESET or error == errno.EPIPE:
- return SecurityConst.errSSLClosedAbort
- raise
-
- data_length_pointer[0] = sent
-
- if sent != bytes_to_write:
- return SecurityConst.errSSLWouldBlock
-
- return 0
- except Exception as e:
- if wrapped_socket is not None:
- wrapped_socket._exception = e
- return SecurityConst.errSSLInternal
-
-
-# We need to keep these two objects references alive: if they get GC'd while
-# in use then SecureTransport could attempt to call a function that is in freed
-# memory. That would be...uh...bad. Yeah, that's the word. Bad.
-_read_callback_pointer = Security.SSLReadFunc(_read_callback)
-_write_callback_pointer = Security.SSLWriteFunc(_write_callback)
-
-
-class WrappedSocket(object):
- """
- API-compatibility wrapper for Python's OpenSSL wrapped socket object.
-
- Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage
- collector of PyPy.
- """
-
- def __init__(self, socket):
- self.socket = socket
- self.context = None
- self._makefile_refs = 0
- self._closed = False
- self._exception = None
- self._keychain = None
- self._keychain_dir = None
- self._client_cert_chain = None
-
- # We save off the previously-configured timeout and then set it to
- # zero. This is done because we use select and friends to handle the
- # timeouts, but if we leave the timeout set on the lower socket then
- # Python will "kindly" call select on that socket again for us. Avoid
- # that by forcing the timeout to zero.
- self._timeout = self.socket.gettimeout()
- self.socket.settimeout(0)
-
- @contextlib.contextmanager
- def _raise_on_error(self):
- """
- A context manager that can be used to wrap calls that do I/O from
- SecureTransport. If any of the I/O callbacks hit an exception, this
- context manager will correctly propagate the exception after the fact.
- This avoids silently swallowing those exceptions.
-
- It also correctly forces the socket closed.
- """
- self._exception = None
-
- # We explicitly don't catch around this yield because in the unlikely
- # event that an exception was hit in the block we don't want to swallow
- # it.
- yield
- if self._exception is not None:
- exception, self._exception = self._exception, None
- self.close()
- raise exception
-
- def _set_ciphers(self):
- """
- Sets up the allowed ciphers. By default this matches the set in
- util.ssl_.DEFAULT_CIPHERS, at least as supported by macOS. This is done
- custom and doesn't allow changing at this time, mostly because parsing
- OpenSSL cipher strings is going to be a freaking nightmare.
- """
- ciphers = (Security.SSLCipherSuite * len(CIPHER_SUITES))(*CIPHER_SUITES)
- result = Security.SSLSetEnabledCiphers(
- self.context, ciphers, len(CIPHER_SUITES)
- )
- _assert_no_error(result)
-
- def _set_alpn_protocols(self, protocols):
- """
- Sets up the ALPN protocols on the context.
- """
- if not protocols:
- return
- protocols_arr = _create_cfstring_array(protocols)
- try:
- result = Security.SSLSetALPNProtocols(self.context, protocols_arr)
- _assert_no_error(result)
- finally:
- CoreFoundation.CFRelease(protocols_arr)
-
- def _custom_validate(self, verify, trust_bundle):
- """
- Called when we have set custom validation. We do this in two cases:
- first, when cert validation is entirely disabled; and second, when
- using a custom trust DB.
- Raises an SSLError if the connection is not trusted.
- """
- # If we disabled cert validation, just say: cool.
- if not verify:
- return
-
- successes = (
- SecurityConst.kSecTrustResultUnspecified,
- SecurityConst.kSecTrustResultProceed,
- )
- try:
- trust_result = self._evaluate_trust(trust_bundle)
- if trust_result in successes:
- return
- reason = "error code: %d" % (trust_result,)
- except Exception as e:
- # Do not trust on error
- reason = "exception: %r" % (e,)
-
- # SecureTransport does not send an alert nor shuts down the connection.
- rec = _build_tls_unknown_ca_alert(self.version())
- self.socket.sendall(rec)
- # close the connection immediately
- # l_onoff = 1, activate linger
- # l_linger = 0, linger for 0 seoncds
- opts = struct.pack("ii", 1, 0)
- self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, opts)
- self.close()
- raise ssl.SSLError("certificate verify failed, %s" % reason)
-
- def _evaluate_trust(self, trust_bundle):
- # We want data in memory, so load it up.
- if os.path.isfile(trust_bundle):
- with open(trust_bundle, "rb") as f:
- trust_bundle = f.read()
-
- cert_array = None
- trust = Security.SecTrustRef()
-
- try:
- # Get a CFArray that contains the certs we want.
- cert_array = _cert_array_from_pem(trust_bundle)
-
- # Ok, now the hard part. We want to get the SecTrustRef that ST has
- # created for this connection, shove our CAs into it, tell ST to
- # ignore everything else it knows, and then ask if it can build a
- # chain. This is a buuuunch of code.
- result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust))
- _assert_no_error(result)
- if not trust:
- raise ssl.SSLError("Failed to copy trust reference")
-
- result = Security.SecTrustSetAnchorCertificates(trust, cert_array)
- _assert_no_error(result)
-
- result = Security.SecTrustSetAnchorCertificatesOnly(trust, True)
- _assert_no_error(result)
-
- trust_result = Security.SecTrustResultType()
- result = Security.SecTrustEvaluate(trust, ctypes.byref(trust_result))
- _assert_no_error(result)
- finally:
- if trust:
- CoreFoundation.CFRelease(trust)
-
- if cert_array is not None:
- CoreFoundation.CFRelease(cert_array)
-
- return trust_result.value
-
- def handshake(
- self,
- server_hostname,
- verify,
- trust_bundle,
- min_version,
- max_version,
- client_cert,
- client_key,
- client_key_passphrase,
- alpn_protocols,
- ):
- """
- Actually performs the TLS handshake. This is run automatically by
- wrapped socket, and shouldn't be needed in user code.
- """
- # First, we do the initial bits of connection setup. We need to create
- # a context, set its I/O funcs, and set the connection reference.
- self.context = Security.SSLCreateContext(
- None, SecurityConst.kSSLClientSide, SecurityConst.kSSLStreamType
- )
- result = Security.SSLSetIOFuncs(
- self.context, _read_callback_pointer, _write_callback_pointer
- )
- _assert_no_error(result)
-
- # Here we need to compute the handle to use. We do this by taking the
- # id of self modulo 2**31 - 1. If this is already in the dictionary, we
- # just keep incrementing by one until we find a free space.
- with _connection_ref_lock:
- handle = id(self) % 2147483647
- while handle in _connection_refs:
- handle = (handle + 1) % 2147483647
- _connection_refs[handle] = self
-
- result = Security.SSLSetConnection(self.context, handle)
- _assert_no_error(result)
-
- # If we have a server hostname, we should set that too.
- if server_hostname:
- if not isinstance(server_hostname, bytes):
- server_hostname = server_hostname.encode("utf-8")
-
- result = Security.SSLSetPeerDomainName(
- self.context, server_hostname, len(server_hostname)
- )
- _assert_no_error(result)
-
- # Setup the ciphers.
- self._set_ciphers()
-
- # Setup the ALPN protocols.
- self._set_alpn_protocols(alpn_protocols)
-
- # Set the minimum and maximum TLS versions.
- result = Security.SSLSetProtocolVersionMin(self.context, min_version)
- _assert_no_error(result)
-
- result = Security.SSLSetProtocolVersionMax(self.context, max_version)
- _assert_no_error(result)
-
- # If there's a trust DB, we need to use it. We do that by telling
- # SecureTransport to break on server auth. We also do that if we don't
- # want to validate the certs at all: we just won't actually do any
- # authing in that case.
- if not verify or trust_bundle is not None:
- result = Security.SSLSetSessionOption(
- self.context, SecurityConst.kSSLSessionOptionBreakOnServerAuth, True
- )
- _assert_no_error(result)
-
- # If there's a client cert, we need to use it.
- if client_cert:
- self._keychain, self._keychain_dir = _temporary_keychain()
- self._client_cert_chain = _load_client_cert_chain(
- self._keychain, client_cert, client_key
- )
- result = Security.SSLSetCertificate(self.context, self._client_cert_chain)
- _assert_no_error(result)
-
- while True:
- with self._raise_on_error():
- result = Security.SSLHandshake(self.context)
-
- if result == SecurityConst.errSSLWouldBlock:
- raise socket.timeout("handshake timed out")
- elif result == SecurityConst.errSSLServerAuthCompleted:
- self._custom_validate(verify, trust_bundle)
- continue
- else:
- _assert_no_error(result)
- break
-
- def fileno(self):
- return self.socket.fileno()
-
- # Copy-pasted from Python 3.5 source code
- def _decref_socketios(self):
- if self._makefile_refs > 0:
- self._makefile_refs -= 1
- if self._closed:
- self.close()
-
- def recv(self, bufsiz):
- buffer = ctypes.create_string_buffer(bufsiz)
- bytes_read = self.recv_into(buffer, bufsiz)
- data = buffer[:bytes_read]
- return data
-
- def recv_into(self, buffer, nbytes=None):
- # Read short on EOF.
- if self._closed:
- return 0
-
- if nbytes is None:
- nbytes = len(buffer)
-
- buffer = (ctypes.c_char * nbytes).from_buffer(buffer)
- processed_bytes = ctypes.c_size_t(0)
-
- with self._raise_on_error():
- result = Security.SSLRead(
- self.context, buffer, nbytes, ctypes.byref(processed_bytes)
- )
-
- # There are some result codes that we want to treat as "not always
- # errors". Specifically, those are errSSLWouldBlock,
- # errSSLClosedGraceful, and errSSLClosedNoNotify.
- if result == SecurityConst.errSSLWouldBlock:
- # If we didn't process any bytes, then this was just a time out.
- # However, we can get errSSLWouldBlock in situations when we *did*
- # read some data, and in those cases we should just read "short"
- # and return.
- if processed_bytes.value == 0:
- # Timed out, no data read.
- raise socket.timeout("recv timed out")
- elif result in (
- SecurityConst.errSSLClosedGraceful,
- SecurityConst.errSSLClosedNoNotify,
- ):
- # The remote peer has closed this connection. We should do so as
- # well. Note that we don't actually return here because in
- # principle this could actually be fired along with return data.
- # It's unlikely though.
- self.close()
- else:
- _assert_no_error(result)
-
- # Ok, we read and probably succeeded. We should return whatever data
- # was actually read.
- return processed_bytes.value
-
- def settimeout(self, timeout):
- self._timeout = timeout
-
- def gettimeout(self):
- return self._timeout
-
- def send(self, data):
- processed_bytes = ctypes.c_size_t(0)
-
- with self._raise_on_error():
- result = Security.SSLWrite(
- self.context, data, len(data), ctypes.byref(processed_bytes)
- )
-
- if result == SecurityConst.errSSLWouldBlock and processed_bytes.value == 0:
- # Timed out
- raise socket.timeout("send timed out")
- else:
- _assert_no_error(result)
-
- # We sent, and probably succeeded. Tell them how much we sent.
- return processed_bytes.value
-
- def sendall(self, data):
- total_sent = 0
- while total_sent < len(data):
- sent = self.send(data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE])
- total_sent += sent
-
- def shutdown(self):
- with self._raise_on_error():
- Security.SSLClose(self.context)
-
- def close(self):
- # TODO: should I do clean shutdown here? Do I have to?
- if self._makefile_refs < 1:
- self._closed = True
- if self.context:
- CoreFoundation.CFRelease(self.context)
- self.context = None
- if self._client_cert_chain:
- CoreFoundation.CFRelease(self._client_cert_chain)
- self._client_cert_chain = None
- if self._keychain:
- Security.SecKeychainDelete(self._keychain)
- CoreFoundation.CFRelease(self._keychain)
- shutil.rmtree(self._keychain_dir)
- self._keychain = self._keychain_dir = None
- return self.socket.close()
- else:
- self._makefile_refs -= 1
-
- def getpeercert(self, binary_form=False):
- # Urgh, annoying.
- #
- # Here's how we do this:
- #
- # 1. Call SSLCopyPeerTrust to get hold of the trust object for this
- # connection.
- # 2. Call SecTrustGetCertificateAtIndex for index 0 to get the leaf.
- # 3. To get the CN, call SecCertificateCopyCommonName and process that
- # string so that it's of the appropriate type.
- # 4. To get the SAN, we need to do something a bit more complex:
- # a. Call SecCertificateCopyValues to get the data, requesting
- # kSecOIDSubjectAltName.
- # b. Mess about with this dictionary to try to get the SANs out.
- #
- # This is gross. Really gross. It's going to be a few hundred LoC extra
- # just to repeat something that SecureTransport can *already do*. So my
- # operating assumption at this time is that what we want to do is
- # instead to just flag to urllib3 that it shouldn't do its own hostname
- # validation when using SecureTransport.
- if not binary_form:
- raise ValueError("SecureTransport only supports dumping binary certs")
- trust = Security.SecTrustRef()
- certdata = None
- der_bytes = None
-
- try:
- # Grab the trust store.
- result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust))
- _assert_no_error(result)
- if not trust:
- # Probably we haven't done the handshake yet. No biggie.
- return None
-
- cert_count = Security.SecTrustGetCertificateCount(trust)
- if not cert_count:
- # Also a case that might happen if we haven't handshaked.
- # Handshook? Handshaken?
- return None
-
- leaf = Security.SecTrustGetCertificateAtIndex(trust, 0)
- assert leaf
-
- # Ok, now we want the DER bytes.
- certdata = Security.SecCertificateCopyData(leaf)
- assert certdata
-
- data_length = CoreFoundation.CFDataGetLength(certdata)
- data_buffer = CoreFoundation.CFDataGetBytePtr(certdata)
- der_bytes = ctypes.string_at(data_buffer, data_length)
- finally:
- if certdata:
- CoreFoundation.CFRelease(certdata)
- if trust:
- CoreFoundation.CFRelease(trust)
-
- return der_bytes
-
- def version(self):
- protocol = Security.SSLProtocol()
- result = Security.SSLGetNegotiatedProtocolVersion(
- self.context, ctypes.byref(protocol)
- )
- _assert_no_error(result)
- if protocol.value == SecurityConst.kTLSProtocol13:
- raise ssl.SSLError("SecureTransport does not support TLS 1.3")
- elif protocol.value == SecurityConst.kTLSProtocol12:
- return "TLSv1.2"
- elif protocol.value == SecurityConst.kTLSProtocol11:
- return "TLSv1.1"
- elif protocol.value == SecurityConst.kTLSProtocol1:
- return "TLSv1"
- elif protocol.value == SecurityConst.kSSLProtocol3:
- return "SSLv3"
- elif protocol.value == SecurityConst.kSSLProtocol2:
- return "SSLv2"
- else:
- raise ssl.SSLError("Unknown TLS version: %r" % protocol)
-
- def _reuse(self):
- self._makefile_refs += 1
-
- def _drop(self):
- if self._makefile_refs < 1:
- self.close()
- else:
- self._makefile_refs -= 1
-
-
-if _fileobject: # Platform-specific: Python 2
-
- def makefile(self, mode, bufsize=-1):
- self._makefile_refs += 1
- return _fileobject(self, mode, bufsize, close=True)
-
-
-else: # Platform-specific: Python 3
-
- def makefile(self, mode="r", buffering=None, *args, **kwargs):
- # We disable buffering with SecureTransport because it conflicts with
- # the buffering that ST does internally (see issue #1153 for more).
- buffering = 0
- return backport_makefile(self, mode, buffering, *args, **kwargs)
-
-
-WrappedSocket.makefile = makefile
-
-
-class SecureTransportContext(object):
- """
- I am a wrapper class for the SecureTransport library, to translate the
- interface of the standard library ``SSLContext`` object to calls into
- SecureTransport.
- """
-
- def __init__(self, protocol):
- self._min_version, self._max_version = _protocol_to_min_max[protocol]
- self._options = 0
- self._verify = False
- self._trust_bundle = None
- self._client_cert = None
- self._client_key = None
- self._client_key_passphrase = None
- self._alpn_protocols = None
-
- @property
- def check_hostname(self):
- """
- SecureTransport cannot have its hostname checking disabled. For more,
- see the comment on getpeercert() in this file.
- """
- return True
-
- @check_hostname.setter
- def check_hostname(self, value):
- """
- SecureTransport cannot have its hostname checking disabled. For more,
- see the comment on getpeercert() in this file.
- """
- pass
-
- @property
- def options(self):
- # TODO: Well, crap.
- #
- # So this is the bit of the code that is the most likely to cause us
- # trouble. Essentially we need to enumerate all of the SSL options that
- # users might want to use and try to see if we can sensibly translate
- # them, or whether we should just ignore them.
- return self._options
-
- @options.setter
- def options(self, value):
- # TODO: Update in line with above.
- self._options = value
-
- @property
- def verify_mode(self):
- return ssl.CERT_REQUIRED if self._verify else ssl.CERT_NONE
-
- @verify_mode.setter
- def verify_mode(self, value):
- self._verify = True if value == ssl.CERT_REQUIRED else False
-
- def set_default_verify_paths(self):
- # So, this has to do something a bit weird. Specifically, what it does
- # is nothing.
- #
- # This means that, if we had previously had load_verify_locations
- # called, this does not undo that. We need to do that because it turns
- # out that the rest of the urllib3 code will attempt to load the
- # default verify paths if it hasn't been told about any paths, even if
- # the context itself was sometime earlier. We resolve that by just
- # ignoring it.
- pass
-
- def load_default_certs(self):
- return self.set_default_verify_paths()
-
- def set_ciphers(self, ciphers):
- # For now, we just require the default cipher string.
- if ciphers != util.ssl_.DEFAULT_CIPHERS:
- raise ValueError("SecureTransport doesn't support custom cipher strings")
-
- def load_verify_locations(self, cafile=None, capath=None, cadata=None):
- # OK, we only really support cadata and cafile.
- if capath is not None:
- raise ValueError("SecureTransport does not support cert directories")
-
- # Raise if cafile does not exist.
- if cafile is not None:
- with open(cafile):
- pass
-
- self._trust_bundle = cafile or cadata
-
- def load_cert_chain(self, certfile, keyfile=None, password=None):
- self._client_cert = certfile
- self._client_key = keyfile
- self._client_cert_passphrase = password
-
- def set_alpn_protocols(self, protocols):
- """
- Sets the ALPN protocols that will later be set on the context.
-
- Raises a NotImplementedError if ALPN is not supported.
- """
- if not hasattr(Security, "SSLSetALPNProtocols"):
- raise NotImplementedError(
- "SecureTransport supports ALPN only in macOS 10.12+"
- )
- self._alpn_protocols = [six.ensure_binary(p) for p in protocols]
-
- def wrap_socket(
- self,
- sock,
- server_side=False,
- do_handshake_on_connect=True,
- suppress_ragged_eofs=True,
- server_hostname=None,
- ):
- # So, what do we do here? Firstly, we assert some properties. This is a
- # stripped down shim, so there is some functionality we don't support.
- # See PEP 543 for the real deal.
- assert not server_side
- assert do_handshake_on_connect
- assert suppress_ragged_eofs
-
- # Ok, we're good to go. Now we want to create the wrapped socket object
- # and store it in the appropriate place.
- wrapped_socket = WrappedSocket(sock)
-
- # Now we can handshake
- wrapped_socket.handshake(
- server_hostname,
- self._verify,
- self._trust_bundle,
- self._min_version,
- self._max_version,
- self._client_cert,
- self._client_key,
- self._client_key_passphrase,
- self._alpn_protocols,
- )
- return wrapped_socket
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/socks.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/socks.py
deleted file mode 100644
index c326e80dd1..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/contrib/socks.py
+++ /dev/null
@@ -1,216 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-This module contains provisional support for SOCKS proxies from within
-urllib3. This module supports SOCKS4, SOCKS4A (an extension of SOCKS4), and
-SOCKS5. To enable its functionality, either install PySocks or install this
-module with the ``socks`` extra.
-
-The SOCKS implementation supports the full range of urllib3 features. It also
-supports the following SOCKS features:
-
-- SOCKS4A (``proxy_url='socks4a://...``)
-- SOCKS4 (``proxy_url='socks4://...``)
-- SOCKS5 with remote DNS (``proxy_url='socks5h://...``)
-- SOCKS5 with local DNS (``proxy_url='socks5://...``)
-- Usernames and passwords for the SOCKS proxy
-
-.. note::
- It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in
- your ``proxy_url`` to ensure that DNS resolution is done from the remote
- server instead of client-side when connecting to a domain name.
-
-SOCKS4 supports IPv4 and domain names with the SOCKS4A extension. SOCKS5
-supports IPv4, IPv6, and domain names.
-
-When connecting to a SOCKS4 proxy the ``username`` portion of the ``proxy_url``
-will be sent as the ``userid`` section of the SOCKS request:
-
-.. code-block:: python
-
- proxy_url="socks4a://@proxy-host"
-
-When connecting to a SOCKS5 proxy the ``username`` and ``password`` portion
-of the ``proxy_url`` will be sent as the username/password to authenticate
-with the proxy:
-
-.. code-block:: python
-
- proxy_url="socks5h://:@proxy-host"
-
-"""
-from __future__ import absolute_import
-
-try:
- import socks
-except ImportError:
- import warnings
-
- from ..exceptions import DependencyWarning
-
- warnings.warn(
- (
- "SOCKS support in urllib3 requires the installation of optional "
- "dependencies: specifically, PySocks. For more information, see "
- "https://urllib3.readthedocs.io/en/1.26.x/contrib.html#socks-proxies"
- ),
- DependencyWarning,
- )
- raise
-
-from socket import error as SocketError
-from socket import timeout as SocketTimeout
-
-from ..connection import HTTPConnection, HTTPSConnection
-from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool
-from ..exceptions import ConnectTimeoutError, NewConnectionError
-from ..poolmanager import PoolManager
-from ..util.url import parse_url
-
-try:
- import ssl
-except ImportError:
- ssl = None
-
-
-class SOCKSConnection(HTTPConnection):
- """
- A plain-text HTTP connection that connects via a SOCKS proxy.
- """
-
- def __init__(self, *args, **kwargs):
- self._socks_options = kwargs.pop("_socks_options")
- super(SOCKSConnection, self).__init__(*args, **kwargs)
-
- def _new_conn(self):
- """
- Establish a new connection via the SOCKS proxy.
- """
- extra_kw = {}
- if self.source_address:
- extra_kw["source_address"] = self.source_address
-
- if self.socket_options:
- extra_kw["socket_options"] = self.socket_options
-
- try:
- conn = socks.create_connection(
- (self.host, self.port),
- proxy_type=self._socks_options["socks_version"],
- proxy_addr=self._socks_options["proxy_host"],
- proxy_port=self._socks_options["proxy_port"],
- proxy_username=self._socks_options["username"],
- proxy_password=self._socks_options["password"],
- proxy_rdns=self._socks_options["rdns"],
- timeout=self.timeout,
- **extra_kw
- )
-
- except SocketTimeout:
- raise ConnectTimeoutError(
- self,
- "Connection to %s timed out. (connect timeout=%s)"
- % (self.host, self.timeout),
- )
-
- except socks.ProxyError as e:
- # This is fragile as hell, but it seems to be the only way to raise
- # useful errors here.
- if e.socket_err:
- error = e.socket_err
- if isinstance(error, SocketTimeout):
- raise ConnectTimeoutError(
- self,
- "Connection to %s timed out. (connect timeout=%s)"
- % (self.host, self.timeout),
- )
- else:
- raise NewConnectionError(
- self, "Failed to establish a new connection: %s" % error
- )
- else:
- raise NewConnectionError(
- self, "Failed to establish a new connection: %s" % e
- )
-
- except SocketError as e: # Defensive: PySocks should catch all these.
- raise NewConnectionError(
- self, "Failed to establish a new connection: %s" % e
- )
-
- return conn
-
-
-# We don't need to duplicate the Verified/Unverified distinction from
-# urllib3/connection.py here because the HTTPSConnection will already have been
-# correctly set to either the Verified or Unverified form by that module. This
-# means the SOCKSHTTPSConnection will automatically be the correct type.
-class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection):
- pass
-
-
-class SOCKSHTTPConnectionPool(HTTPConnectionPool):
- ConnectionCls = SOCKSConnection
-
-
-class SOCKSHTTPSConnectionPool(HTTPSConnectionPool):
- ConnectionCls = SOCKSHTTPSConnection
-
-
-class SOCKSProxyManager(PoolManager):
- """
- A version of the urllib3 ProxyManager that routes connections via the
- defined SOCKS proxy.
- """
-
- pool_classes_by_scheme = {
- "http": SOCKSHTTPConnectionPool,
- "https": SOCKSHTTPSConnectionPool,
- }
-
- def __init__(
- self,
- proxy_url,
- username=None,
- password=None,
- num_pools=10,
- headers=None,
- **connection_pool_kw
- ):
- parsed = parse_url(proxy_url)
-
- if username is None and password is None and parsed.auth is not None:
- split = parsed.auth.split(":")
- if len(split) == 2:
- username, password = split
- if parsed.scheme == "socks5":
- socks_version = socks.PROXY_TYPE_SOCKS5
- rdns = False
- elif parsed.scheme == "socks5h":
- socks_version = socks.PROXY_TYPE_SOCKS5
- rdns = True
- elif parsed.scheme == "socks4":
- socks_version = socks.PROXY_TYPE_SOCKS4
- rdns = False
- elif parsed.scheme == "socks4a":
- socks_version = socks.PROXY_TYPE_SOCKS4
- rdns = True
- else:
- raise ValueError("Unable to determine SOCKS version from %s" % proxy_url)
-
- self.proxy_url = proxy_url
-
- socks_options = {
- "socks_version": socks_version,
- "proxy_host": parsed.host,
- "proxy_port": parsed.port,
- "username": username,
- "password": password,
- "rdns": rdns,
- }
- connection_pool_kw["_socks_options"] = socks_options
-
- super(SOCKSProxyManager, self).__init__(
- num_pools, headers, **connection_pool_kw
- )
-
- self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/exceptions.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/exceptions.py
deleted file mode 100644
index cba6f3f560..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/exceptions.py
+++ /dev/null
@@ -1,323 +0,0 @@
-from __future__ import absolute_import
-
-from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead
-
-# Base Exceptions
-
-
-class HTTPError(Exception):
- """Base exception used by this module."""
-
- pass
-
-
-class HTTPWarning(Warning):
- """Base warning used by this module."""
-
- pass
-
-
-class PoolError(HTTPError):
- """Base exception for errors caused within a pool."""
-
- def __init__(self, pool, message):
- self.pool = pool
- HTTPError.__init__(self, "%s: %s" % (pool, message))
-
- def __reduce__(self):
- # For pickling purposes.
- return self.__class__, (None, None)
-
-
-class RequestError(PoolError):
- """Base exception for PoolErrors that have associated URLs."""
-
- def __init__(self, pool, url, message):
- self.url = url
- PoolError.__init__(self, pool, message)
-
- def __reduce__(self):
- # For pickling purposes.
- return self.__class__, (None, self.url, None)
-
-
-class SSLError(HTTPError):
- """Raised when SSL certificate fails in an HTTPS connection."""
-
- pass
-
-
-class ProxyError(HTTPError):
- """Raised when the connection to a proxy fails."""
-
- def __init__(self, message, error, *args):
- super(ProxyError, self).__init__(message, error, *args)
- self.original_error = error
-
-
-class DecodeError(HTTPError):
- """Raised when automatic decoding based on Content-Type fails."""
-
- pass
-
-
-class ProtocolError(HTTPError):
- """Raised when something unexpected happens mid-request/response."""
-
- pass
-
-
-#: Renamed to ProtocolError but aliased for backwards compatibility.
-ConnectionError = ProtocolError
-
-
-# Leaf Exceptions
-
-
-class MaxRetryError(RequestError):
- """Raised when the maximum number of retries is exceeded.
-
- :param pool: The connection pool
- :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool`
- :param string url: The requested Url
- :param exceptions.Exception reason: The underlying error
-
- """
-
- def __init__(self, pool, url, reason=None):
- self.reason = reason
-
- message = "Max retries exceeded with url: %s (Caused by %r)" % (url, reason)
-
- RequestError.__init__(self, pool, url, message)
-
-
-class HostChangedError(RequestError):
- """Raised when an existing pool gets a request for a foreign host."""
-
- def __init__(self, pool, url, retries=3):
- message = "Tried to open a foreign host with url: %s" % url
- RequestError.__init__(self, pool, url, message)
- self.retries = retries
-
-
-class TimeoutStateError(HTTPError):
- """Raised when passing an invalid state to a timeout"""
-
- pass
-
-
-class TimeoutError(HTTPError):
- """Raised when a socket timeout error occurs.
-
- Catching this error will catch both :exc:`ReadTimeoutErrors
- ` and :exc:`ConnectTimeoutErrors `.
- """
-
- pass
-
-
-class ReadTimeoutError(TimeoutError, RequestError):
- """Raised when a socket timeout occurs while receiving data from a server"""
-
- pass
-
-
-# This timeout error does not have a URL attached and needs to inherit from the
-# base HTTPError
-class ConnectTimeoutError(TimeoutError):
- """Raised when a socket timeout occurs while connecting to a server"""
-
- pass
-
-
-class NewConnectionError(ConnectTimeoutError, PoolError):
- """Raised when we fail to establish a new connection. Usually ECONNREFUSED."""
-
- pass
-
-
-class EmptyPoolError(PoolError):
- """Raised when a pool runs out of connections and no more are allowed."""
-
- pass
-
-
-class ClosedPoolError(PoolError):
- """Raised when a request enters a pool after the pool has been closed."""
-
- pass
-
-
-class LocationValueError(ValueError, HTTPError):
- """Raised when there is something wrong with a given URL input."""
-
- pass
-
-
-class LocationParseError(LocationValueError):
- """Raised when get_host or similar fails to parse the URL input."""
-
- def __init__(self, location):
- message = "Failed to parse: %s" % location
- HTTPError.__init__(self, message)
-
- self.location = location
-
-
-class URLSchemeUnknown(LocationValueError):
- """Raised when a URL input has an unsupported scheme."""
-
- def __init__(self, scheme):
- message = "Not supported URL scheme %s" % scheme
- super(URLSchemeUnknown, self).__init__(message)
-
- self.scheme = scheme
-
-
-class ResponseError(HTTPError):
- """Used as a container for an error reason supplied in a MaxRetryError."""
-
- GENERIC_ERROR = "too many error responses"
- SPECIFIC_ERROR = "too many {status_code} error responses"
-
-
-class SecurityWarning(HTTPWarning):
- """Warned when performing security reducing actions"""
-
- pass
-
-
-class SubjectAltNameWarning(SecurityWarning):
- """Warned when connecting to a host with a certificate missing a SAN."""
-
- pass
-
-
-class InsecureRequestWarning(SecurityWarning):
- """Warned when making an unverified HTTPS request."""
-
- pass
-
-
-class SystemTimeWarning(SecurityWarning):
- """Warned when system time is suspected to be wrong"""
-
- pass
-
-
-class InsecurePlatformWarning(SecurityWarning):
- """Warned when certain TLS/SSL configuration is not available on a platform."""
-
- pass
-
-
-class SNIMissingWarning(HTTPWarning):
- """Warned when making a HTTPS request without SNI available."""
-
- pass
-
-
-class DependencyWarning(HTTPWarning):
- """
- Warned when an attempt is made to import a module with missing optional
- dependencies.
- """
-
- pass
-
-
-class ResponseNotChunked(ProtocolError, ValueError):
- """Response needs to be chunked in order to read it as chunks."""
-
- pass
-
-
-class BodyNotHttplibCompatible(HTTPError):
- """
- Body should be :class:`http.client.HTTPResponse` like
- (have an fp attribute which returns raw chunks) for read_chunked().
- """
-
- pass
-
-
-class IncompleteRead(HTTPError, httplib_IncompleteRead):
- """
- Response length doesn't match expected Content-Length
-
- Subclass of :class:`http.client.IncompleteRead` to allow int value
- for ``partial`` to avoid creating large objects on streamed reads.
- """
-
- def __init__(self, partial, expected):
- super(IncompleteRead, self).__init__(partial, expected)
-
- def __repr__(self):
- return "IncompleteRead(%i bytes read, %i more expected)" % (
- self.partial,
- self.expected,
- )
-
-
-class InvalidChunkLength(HTTPError, httplib_IncompleteRead):
- """Invalid chunk length in a chunked response."""
-
- def __init__(self, response, length):
- super(InvalidChunkLength, self).__init__(
- response.tell(), response.length_remaining
- )
- self.response = response
- self.length = length
-
- def __repr__(self):
- return "InvalidChunkLength(got length %r, %i bytes read)" % (
- self.length,
- self.partial,
- )
-
-
-class InvalidHeader(HTTPError):
- """The header provided was somehow invalid."""
-
- pass
-
-
-class ProxySchemeUnknown(AssertionError, URLSchemeUnknown):
- """ProxyManager does not support the supplied scheme"""
-
- # TODO(t-8ch): Stop inheriting from AssertionError in v2.0.
-
- def __init__(self, scheme):
- # 'localhost' is here because our URL parser parses
- # localhost:8080 -> scheme=localhost, remove if we fix this.
- if scheme == "localhost":
- scheme = None
- if scheme is None:
- message = "Proxy URL had no scheme, should start with http:// or https://"
- else:
- message = (
- "Proxy URL had unsupported scheme %s, should use http:// or https://"
- % scheme
- )
- super(ProxySchemeUnknown, self).__init__(message)
-
-
-class ProxySchemeUnsupported(ValueError):
- """Fetching HTTPS resources through HTTPS proxies is unsupported"""
-
- pass
-
-
-class HeaderParsingError(HTTPError):
- """Raised by assert_header_parsing, but we convert it to a log.warning statement."""
-
- def __init__(self, defects, unparsed_data):
- message = "%s, unparsed data: %r" % (defects or "Unknown", unparsed_data)
- super(HeaderParsingError, self).__init__(message)
-
-
-class UnrewindableBodyError(HTTPError):
- """urllib3 encountered an error when trying to rewind a body"""
-
- pass
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/fields.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/fields.py
deleted file mode 100644
index 9d630f491d..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/fields.py
+++ /dev/null
@@ -1,274 +0,0 @@
-from __future__ import absolute_import
-
-import email.utils
-import mimetypes
-import re
-
-from .packages import six
-
-
-def guess_content_type(filename, default="application/octet-stream"):
- """
- Guess the "Content-Type" of a file.
-
- :param filename:
- The filename to guess the "Content-Type" of using :mod:`mimetypes`.
- :param default:
- If no "Content-Type" can be guessed, default to `default`.
- """
- if filename:
- return mimetypes.guess_type(filename)[0] or default
- return default
-
-
-def format_header_param_rfc2231(name, value):
- """
- Helper function to format and quote a single header parameter using the
- strategy defined in RFC 2231.
-
- Particularly useful for header parameters which might contain
- non-ASCII values, like file names. This follows
- `RFC 2388 Section 4.4 `_.
-
- :param name:
- The name of the parameter, a string expected to be ASCII only.
- :param value:
- The value of the parameter, provided as ``bytes`` or `str``.
- :ret:
- An RFC-2231-formatted unicode string.
- """
- if isinstance(value, six.binary_type):
- value = value.decode("utf-8")
-
- if not any(ch in value for ch in '"\\\r\n'):
- result = u'%s="%s"' % (name, value)
- try:
- result.encode("ascii")
- except (UnicodeEncodeError, UnicodeDecodeError):
- pass
- else:
- return result
-
- if six.PY2: # Python 2:
- value = value.encode("utf-8")
-
- # encode_rfc2231 accepts an encoded string and returns an ascii-encoded
- # string in Python 2 but accepts and returns unicode strings in Python 3
- value = email.utils.encode_rfc2231(value, "utf-8")
- value = "%s*=%s" % (name, value)
-
- if six.PY2: # Python 2:
- value = value.decode("utf-8")
-
- return value
-
-
-_HTML5_REPLACEMENTS = {
- u"\u0022": u"%22",
- # Replace "\" with "\\".
- u"\u005C": u"\u005C\u005C",
-}
-
-# All control characters from 0x00 to 0x1F *except* 0x1B.
-_HTML5_REPLACEMENTS.update(
- {
- six.unichr(cc): u"%{:02X}".format(cc)
- for cc in range(0x00, 0x1F + 1)
- if cc not in (0x1B,)
- }
-)
-
-
-def _replace_multiple(value, needles_and_replacements):
- def replacer(match):
- return needles_and_replacements[match.group(0)]
-
- pattern = re.compile(
- r"|".join([re.escape(needle) for needle in needles_and_replacements.keys()])
- )
-
- result = pattern.sub(replacer, value)
-
- return result
-
-
-def format_header_param_html5(name, value):
- """
- Helper function to format and quote a single header parameter using the
- HTML5 strategy.
-
- Particularly useful for header parameters which might contain
- non-ASCII values, like file names. This follows the `HTML5 Working Draft
- Section 4.10.22.7`_ and matches the behavior of curl and modern browsers.
-
- .. _HTML5 Working Draft Section 4.10.22.7:
- https://w3c.github.io/html/sec-forms.html#multipart-form-data
-
- :param name:
- The name of the parameter, a string expected to be ASCII only.
- :param value:
- The value of the parameter, provided as ``bytes`` or `str``.
- :ret:
- A unicode string, stripped of troublesome characters.
- """
- if isinstance(value, six.binary_type):
- value = value.decode("utf-8")
-
- value = _replace_multiple(value, _HTML5_REPLACEMENTS)
-
- return u'%s="%s"' % (name, value)
-
-
-# For backwards-compatibility.
-format_header_param = format_header_param_html5
-
-
-class RequestField(object):
- """
- A data container for request body parameters.
-
- :param name:
- The name of this request field. Must be unicode.
- :param data:
- The data/value body.
- :param filename:
- An optional filename of the request field. Must be unicode.
- :param headers:
- An optional dict-like object of headers to initially use for the field.
- :param header_formatter:
- An optional callable that is used to encode and format the headers. By
- default, this is :func:`format_header_param_html5`.
- """
-
- def __init__(
- self,
- name,
- data,
- filename=None,
- headers=None,
- header_formatter=format_header_param_html5,
- ):
- self._name = name
- self._filename = filename
- self.data = data
- self.headers = {}
- if headers:
- self.headers = dict(headers)
- self.header_formatter = header_formatter
-
- @classmethod
- def from_tuples(cls, fieldname, value, header_formatter=format_header_param_html5):
- """
- A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters.
-
- Supports constructing :class:`~urllib3.fields.RequestField` from
- parameter of key/value strings AND key/filetuple. A filetuple is a
- (filename, data, MIME type) tuple where the MIME type is optional.
- For example::
-
- 'foo': 'bar',
- 'fakefile': ('foofile.txt', 'contents of foofile'),
- 'realfile': ('barfile.txt', open('realfile').read()),
- 'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'),
- 'nonamefile': 'contents of nonamefile field',
-
- Field names and filenames must be unicode.
- """
- if isinstance(value, tuple):
- if len(value) == 3:
- filename, data, content_type = value
- else:
- filename, data = value
- content_type = guess_content_type(filename)
- else:
- filename = None
- content_type = None
- data = value
-
- request_param = cls(
- fieldname, data, filename=filename, header_formatter=header_formatter
- )
- request_param.make_multipart(content_type=content_type)
-
- return request_param
-
- def _render_part(self, name, value):
- """
- Overridable helper function to format a single header parameter. By
- default, this calls ``self.header_formatter``.
-
- :param name:
- The name of the parameter, a string expected to be ASCII only.
- :param value:
- The value of the parameter, provided as a unicode string.
- """
-
- return self.header_formatter(name, value)
-
- def _render_parts(self, header_parts):
- """
- Helper function to format and quote a single header.
-
- Useful for single headers that are composed of multiple items. E.g.,
- 'Content-Disposition' fields.
-
- :param header_parts:
- A sequence of (k, v) tuples or a :class:`dict` of (k, v) to format
- as `k1="v1"; k2="v2"; ...`.
- """
- parts = []
- iterable = header_parts
- if isinstance(header_parts, dict):
- iterable = header_parts.items()
-
- for name, value in iterable:
- if value is not None:
- parts.append(self._render_part(name, value))
-
- return u"; ".join(parts)
-
- def render_headers(self):
- """
- Renders the headers for this request field.
- """
- lines = []
-
- sort_keys = ["Content-Disposition", "Content-Type", "Content-Location"]
- for sort_key in sort_keys:
- if self.headers.get(sort_key, False):
- lines.append(u"%s: %s" % (sort_key, self.headers[sort_key]))
-
- for header_name, header_value in self.headers.items():
- if header_name not in sort_keys:
- if header_value:
- lines.append(u"%s: %s" % (header_name, header_value))
-
- lines.append(u"\r\n")
- return u"\r\n".join(lines)
-
- def make_multipart(
- self, content_disposition=None, content_type=None, content_location=None
- ):
- """
- Makes this request field into a multipart request field.
-
- This method overrides "Content-Disposition", "Content-Type" and
- "Content-Location" headers to the request parameter.
-
- :param content_type:
- The 'Content-Type' of the request body.
- :param content_location:
- The 'Content-Location' of the request body.
-
- """
- self.headers["Content-Disposition"] = content_disposition or u"form-data"
- self.headers["Content-Disposition"] += u"; ".join(
- [
- u"",
- self._render_parts(
- ((u"name", self._name), (u"filename", self._filename))
- ),
- ]
- )
- self.headers["Content-Type"] = content_type
- self.headers["Content-Location"] = content_location
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/filepost.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/filepost.py
deleted file mode 100644
index 36c9252c64..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/filepost.py
+++ /dev/null
@@ -1,98 +0,0 @@
-from __future__ import absolute_import
-
-import binascii
-import codecs
-import os
-from io import BytesIO
-
-from .fields import RequestField
-from .packages import six
-from .packages.six import b
-
-writer = codecs.lookup("utf-8")[3]
-
-
-def choose_boundary():
- """
- Our embarrassingly-simple replacement for mimetools.choose_boundary.
- """
- boundary = binascii.hexlify(os.urandom(16))
- if not six.PY2:
- boundary = boundary.decode("ascii")
- return boundary
-
-
-def iter_field_objects(fields):
- """
- Iterate over fields.
-
- Supports list of (k, v) tuples and dicts, and lists of
- :class:`~urllib3.fields.RequestField`.
-
- """
- if isinstance(fields, dict):
- i = six.iteritems(fields)
- else:
- i = iter(fields)
-
- for field in i:
- if isinstance(field, RequestField):
- yield field
- else:
- yield RequestField.from_tuples(*field)
-
-
-def iter_fields(fields):
- """
- .. deprecated:: 1.6
-
- Iterate over fields.
-
- The addition of :class:`~urllib3.fields.RequestField` makes this function
- obsolete. Instead, use :func:`iter_field_objects`, which returns
- :class:`~urllib3.fields.RequestField` objects.
-
- Supports list of (k, v) tuples and dicts.
- """
- if isinstance(fields, dict):
- return ((k, v) for k, v in six.iteritems(fields))
-
- return ((k, v) for k, v in fields)
-
-
-def encode_multipart_formdata(fields, boundary=None):
- """
- Encode a dictionary of ``fields`` using the multipart/form-data MIME format.
-
- :param fields:
- Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`).
-
- :param boundary:
- If not specified, then a random boundary will be generated using
- :func:`urllib3.filepost.choose_boundary`.
- """
- body = BytesIO()
- if boundary is None:
- boundary = choose_boundary()
-
- for field in iter_field_objects(fields):
- body.write(b("--%s\r\n" % (boundary)))
-
- writer(body).write(field.render_headers())
- data = field.data
-
- if isinstance(data, int):
- data = str(data) # Backwards compatibility
-
- if isinstance(data, six.text_type):
- writer(body).write(data)
- else:
- body.write(data)
-
- body.write(b"\r\n")
-
- body.write(b("--%s--\r\n" % (boundary)))
-
- content_type = str("multipart/form-data; boundary=%s" % boundary)
-
- return body.getvalue(), content_type
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/__init__.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/__init__.py
deleted file mode 100644
index fce4caa65d..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from __future__ import absolute_import
-
-from . import ssl_match_hostname
-
-__all__ = ("ssl_match_hostname",)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/backports/__init__.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/backports/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/backports/makefile.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/backports/makefile.py
deleted file mode 100644
index b8fb2154b6..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/backports/makefile.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-backports.makefile
-~~~~~~~~~~~~~~~~~~
-
-Backports the Python 3 ``socket.makefile`` method for use with anything that
-wants to create a "fake" socket object.
-"""
-import io
-from socket import SocketIO
-
-
-def backport_makefile(
- self, mode="r", buffering=None, encoding=None, errors=None, newline=None
-):
- """
- Backport of ``socket.makefile`` from Python 3.5.
- """
- if not set(mode) <= {"r", "w", "b"}:
- raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,))
- writing = "w" in mode
- reading = "r" in mode or not writing
- assert reading or writing
- binary = "b" in mode
- rawmode = ""
- if reading:
- rawmode += "r"
- if writing:
- rawmode += "w"
- raw = SocketIO(self, rawmode)
- self._makefile_refs += 1
- if buffering is None:
- buffering = -1
- if buffering < 0:
- buffering = io.DEFAULT_BUFFER_SIZE
- if buffering == 0:
- if not binary:
- raise ValueError("unbuffered streams must be binary")
- return raw
- if reading and writing:
- buffer = io.BufferedRWPair(raw, raw, buffering)
- elif reading:
- buffer = io.BufferedReader(raw, buffering)
- else:
- assert writing
- buffer = io.BufferedWriter(raw, buffering)
- if binary:
- return buffer
- text = io.TextIOWrapper(buffer, encoding, errors, newline)
- text.mode = mode
- return text
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/six.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/six.py
deleted file mode 100644
index ba50acb062..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/six.py
+++ /dev/null
@@ -1,1077 +0,0 @@
-# Copyright (c) 2010-2020 Benjamin Peterson
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-"""Utilities for writing code that runs on Python 2 and 3"""
-
-from __future__ import absolute_import
-
-import functools
-import itertools
-import operator
-import sys
-import types
-
-__author__ = "Benjamin Peterson "
-__version__ = "1.16.0"
-
-
-# Useful for very coarse version differentiation.
-PY2 = sys.version_info[0] == 2
-PY3 = sys.version_info[0] == 3
-PY34 = sys.version_info[0:2] >= (3, 4)
-
-if PY3:
- string_types = (str,)
- integer_types = (int,)
- class_types = (type,)
- text_type = str
- binary_type = bytes
-
- MAXSIZE = sys.maxsize
-else:
- string_types = (basestring,)
- integer_types = (int, long)
- class_types = (type, types.ClassType)
- text_type = unicode
- binary_type = str
-
- if sys.platform.startswith("java"):
- # Jython always uses 32 bits.
- MAXSIZE = int((1 << 31) - 1)
- else:
- # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
- class X(object):
- def __len__(self):
- return 1 << 31
-
- try:
- len(X())
- except OverflowError:
- # 32-bit
- MAXSIZE = int((1 << 31) - 1)
- else:
- # 64-bit
- MAXSIZE = int((1 << 63) - 1)
- del X
-
-if PY34:
- from importlib.util import spec_from_loader
-else:
- spec_from_loader = None
-
-
-def _add_doc(func, doc):
- """Add documentation to a function."""
- func.__doc__ = doc
-
-
-def _import_module(name):
- """Import module, returning the module after the last dot."""
- __import__(name)
- return sys.modules[name]
-
-
-class _LazyDescr(object):
- def __init__(self, name):
- self.name = name
-
- def __get__(self, obj, tp):
- result = self._resolve()
- setattr(obj, self.name, result) # Invokes __set__.
- try:
- # This is a bit ugly, but it avoids running this again by
- # removing this descriptor.
- delattr(obj.__class__, self.name)
- except AttributeError:
- pass
- return result
-
-
-class MovedModule(_LazyDescr):
- def __init__(self, name, old, new=None):
- super(MovedModule, self).__init__(name)
- if PY3:
- if new is None:
- new = name
- self.mod = new
- else:
- self.mod = old
-
- def _resolve(self):
- return _import_module(self.mod)
-
- def __getattr__(self, attr):
- _module = self._resolve()
- value = getattr(_module, attr)
- setattr(self, attr, value)
- return value
-
-
-class _LazyModule(types.ModuleType):
- def __init__(self, name):
- super(_LazyModule, self).__init__(name)
- self.__doc__ = self.__class__.__doc__
-
- def __dir__(self):
- attrs = ["__doc__", "__name__"]
- attrs += [attr.name for attr in self._moved_attributes]
- return attrs
-
- # Subclasses should override this
- _moved_attributes = []
-
-
-class MovedAttribute(_LazyDescr):
- def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
- super(MovedAttribute, self).__init__(name)
- if PY3:
- if new_mod is None:
- new_mod = name
- self.mod = new_mod
- if new_attr is None:
- if old_attr is None:
- new_attr = name
- else:
- new_attr = old_attr
- self.attr = new_attr
- else:
- self.mod = old_mod
- if old_attr is None:
- old_attr = name
- self.attr = old_attr
-
- def _resolve(self):
- module = _import_module(self.mod)
- return getattr(module, self.attr)
-
-
-class _SixMetaPathImporter(object):
-
- """
- A meta path importer to import six.moves and its submodules.
-
- This class implements a PEP302 finder and loader. It should be compatible
- with Python 2.5 and all existing versions of Python3
- """
-
- def __init__(self, six_module_name):
- self.name = six_module_name
- self.known_modules = {}
-
- def _add_module(self, mod, *fullnames):
- for fullname in fullnames:
- self.known_modules[self.name + "." + fullname] = mod
-
- def _get_module(self, fullname):
- return self.known_modules[self.name + "." + fullname]
-
- def find_module(self, fullname, path=None):
- if fullname in self.known_modules:
- return self
- return None
-
- def find_spec(self, fullname, path, target=None):
- if fullname in self.known_modules:
- return spec_from_loader(fullname, self)
- return None
-
- def __get_module(self, fullname):
- try:
- return self.known_modules[fullname]
- except KeyError:
- raise ImportError("This loader does not know module " + fullname)
-
- def load_module(self, fullname):
- try:
- # in case of a reload
- return sys.modules[fullname]
- except KeyError:
- pass
- mod = self.__get_module(fullname)
- if isinstance(mod, MovedModule):
- mod = mod._resolve()
- else:
- mod.__loader__ = self
- sys.modules[fullname] = mod
- return mod
-
- def is_package(self, fullname):
- """
- Return true, if the named module is a package.
-
- We need this method to get correct spec objects with
- Python 3.4 (see PEP451)
- """
- return hasattr(self.__get_module(fullname), "__path__")
-
- def get_code(self, fullname):
- """Return None
-
- Required, if is_package is implemented"""
- self.__get_module(fullname) # eventually raises ImportError
- return None
-
- get_source = get_code # same as get_code
-
- def create_module(self, spec):
- return self.load_module(spec.name)
-
- def exec_module(self, module):
- pass
-
-
-_importer = _SixMetaPathImporter(__name__)
-
-
-class _MovedItems(_LazyModule):
-
- """Lazy loading of moved objects"""
-
- __path__ = [] # mark as package
-
-
-_moved_attributes = [
- MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
- MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
- MovedAttribute(
- "filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"
- ),
- MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
- MovedAttribute("intern", "__builtin__", "sys"),
- MovedAttribute("map", "itertools", "builtins", "imap", "map"),
- MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
- MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
- MovedAttribute("getoutput", "commands", "subprocess"),
- MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute(
- "reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"
- ),
- MovedAttribute("reduce", "__builtin__", "functools"),
- MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
- MovedAttribute("StringIO", "StringIO", "io"),
- MovedAttribute("UserDict", "UserDict", "collections"),
- MovedAttribute("UserList", "UserList", "collections"),
- MovedAttribute("UserString", "UserString", "collections"),
- MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
- MovedAttribute(
- "zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"
- ),
- MovedModule("builtins", "__builtin__"),
- MovedModule("configparser", "ConfigParser"),
- MovedModule(
- "collections_abc",
- "collections",
- "collections.abc" if sys.version_info >= (3, 3) else "collections",
- ),
- MovedModule("copyreg", "copy_reg"),
- MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
- MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"),
- MovedModule(
- "_dummy_thread",
- "dummy_thread",
- "_dummy_thread" if sys.version_info < (3, 9) else "_thread",
- ),
- MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
- MovedModule("http_cookies", "Cookie", "http.cookies"),
- MovedModule("html_entities", "htmlentitydefs", "html.entities"),
- MovedModule("html_parser", "HTMLParser", "html.parser"),
- MovedModule("http_client", "httplib", "http.client"),
- MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
- MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"),
- MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
- MovedModule(
- "email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"
- ),
- MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
- MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
- MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
- MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
- MovedModule("cPickle", "cPickle", "pickle"),
- MovedModule("queue", "Queue"),
- MovedModule("reprlib", "repr"),
- MovedModule("socketserver", "SocketServer"),
- MovedModule("_thread", "thread", "_thread"),
- MovedModule("tkinter", "Tkinter"),
- MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
- MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
- MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
- MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
- MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
- MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
- MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
- MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
- MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"),
- MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"),
- MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
- MovedModule("tkinter_font", "tkFont", "tkinter.font"),
- MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
- MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"),
- MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
- MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
- MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
- MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
- MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
- MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
-]
-# Add windows specific modules.
-if sys.platform == "win32":
- _moved_attributes += [
- MovedModule("winreg", "_winreg"),
- ]
-
-for attr in _moved_attributes:
- setattr(_MovedItems, attr.name, attr)
- if isinstance(attr, MovedModule):
- _importer._add_module(attr, "moves." + attr.name)
-del attr
-
-_MovedItems._moved_attributes = _moved_attributes
-
-moves = _MovedItems(__name__ + ".moves")
-_importer._add_module(moves, "moves")
-
-
-class Module_six_moves_urllib_parse(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_parse"""
-
-
-_urllib_parse_moved_attributes = [
- MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
- MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
- MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
- MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
- MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
- MovedAttribute("urljoin", "urlparse", "urllib.parse"),
- MovedAttribute("urlparse", "urlparse", "urllib.parse"),
- MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
- MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
- MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
- MovedAttribute("quote", "urllib", "urllib.parse"),
- MovedAttribute("quote_plus", "urllib", "urllib.parse"),
- MovedAttribute("unquote", "urllib", "urllib.parse"),
- MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
- MovedAttribute(
- "unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"
- ),
- MovedAttribute("urlencode", "urllib", "urllib.parse"),
- MovedAttribute("splitquery", "urllib", "urllib.parse"),
- MovedAttribute("splittag", "urllib", "urllib.parse"),
- MovedAttribute("splituser", "urllib", "urllib.parse"),
- MovedAttribute("splitvalue", "urllib", "urllib.parse"),
- MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
- MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
- MovedAttribute("uses_params", "urlparse", "urllib.parse"),
- MovedAttribute("uses_query", "urlparse", "urllib.parse"),
- MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
-]
-for attr in _urllib_parse_moved_attributes:
- setattr(Module_six_moves_urllib_parse, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
-
-_importer._add_module(
- Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
- "moves.urllib_parse",
- "moves.urllib.parse",
-)
-
-
-class Module_six_moves_urllib_error(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_error"""
-
-
-_urllib_error_moved_attributes = [
- MovedAttribute("URLError", "urllib2", "urllib.error"),
- MovedAttribute("HTTPError", "urllib2", "urllib.error"),
- MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
-]
-for attr in _urllib_error_moved_attributes:
- setattr(Module_six_moves_urllib_error, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
-
-_importer._add_module(
- Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
- "moves.urllib_error",
- "moves.urllib.error",
-)
-
-
-class Module_six_moves_urllib_request(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_request"""
-
-
-_urllib_request_moved_attributes = [
- MovedAttribute("urlopen", "urllib2", "urllib.request"),
- MovedAttribute("install_opener", "urllib2", "urllib.request"),
- MovedAttribute("build_opener", "urllib2", "urllib.request"),
- MovedAttribute("pathname2url", "urllib", "urllib.request"),
- MovedAttribute("url2pathname", "urllib", "urllib.request"),
- MovedAttribute("getproxies", "urllib", "urllib.request"),
- MovedAttribute("Request", "urllib2", "urllib.request"),
- MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
- MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
- MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
- MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
- MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
- MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
- MovedAttribute("FileHandler", "urllib2", "urllib.request"),
- MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
- MovedAttribute("urlretrieve", "urllib", "urllib.request"),
- MovedAttribute("urlcleanup", "urllib", "urllib.request"),
- MovedAttribute("URLopener", "urllib", "urllib.request"),
- MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
- MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
- MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
- MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
-]
-for attr in _urllib_request_moved_attributes:
- setattr(Module_six_moves_urllib_request, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
-
-_importer._add_module(
- Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
- "moves.urllib_request",
- "moves.urllib.request",
-)
-
-
-class Module_six_moves_urllib_response(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_response"""
-
-
-_urllib_response_moved_attributes = [
- MovedAttribute("addbase", "urllib", "urllib.response"),
- MovedAttribute("addclosehook", "urllib", "urllib.response"),
- MovedAttribute("addinfo", "urllib", "urllib.response"),
- MovedAttribute("addinfourl", "urllib", "urllib.response"),
-]
-for attr in _urllib_response_moved_attributes:
- setattr(Module_six_moves_urllib_response, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
-
-_importer._add_module(
- Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
- "moves.urllib_response",
- "moves.urllib.response",
-)
-
-
-class Module_six_moves_urllib_robotparser(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_robotparser"""
-
-
-_urllib_robotparser_moved_attributes = [
- MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
-]
-for attr in _urllib_robotparser_moved_attributes:
- setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_robotparser._moved_attributes = (
- _urllib_robotparser_moved_attributes
-)
-
-_importer._add_module(
- Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
- "moves.urllib_robotparser",
- "moves.urllib.robotparser",
-)
-
-
-class Module_six_moves_urllib(types.ModuleType):
-
- """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
-
- __path__ = [] # mark as package
- parse = _importer._get_module("moves.urllib_parse")
- error = _importer._get_module("moves.urllib_error")
- request = _importer._get_module("moves.urllib_request")
- response = _importer._get_module("moves.urllib_response")
- robotparser = _importer._get_module("moves.urllib_robotparser")
-
- def __dir__(self):
- return ["parse", "error", "request", "response", "robotparser"]
-
-
-_importer._add_module(
- Module_six_moves_urllib(__name__ + ".moves.urllib"), "moves.urllib"
-)
-
-
-def add_move(move):
- """Add an item to six.moves."""
- setattr(_MovedItems, move.name, move)
-
-
-def remove_move(name):
- """Remove item from six.moves."""
- try:
- delattr(_MovedItems, name)
- except AttributeError:
- try:
- del moves.__dict__[name]
- except KeyError:
- raise AttributeError("no such move, %r" % (name,))
-
-
-if PY3:
- _meth_func = "__func__"
- _meth_self = "__self__"
-
- _func_closure = "__closure__"
- _func_code = "__code__"
- _func_defaults = "__defaults__"
- _func_globals = "__globals__"
-else:
- _meth_func = "im_func"
- _meth_self = "im_self"
-
- _func_closure = "func_closure"
- _func_code = "func_code"
- _func_defaults = "func_defaults"
- _func_globals = "func_globals"
-
-
-try:
- advance_iterator = next
-except NameError:
-
- def advance_iterator(it):
- return it.next()
-
-
-next = advance_iterator
-
-
-try:
- callable = callable
-except NameError:
-
- def callable(obj):
- return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
-
-
-if PY3:
-
- def get_unbound_function(unbound):
- return unbound
-
- create_bound_method = types.MethodType
-
- def create_unbound_method(func, cls):
- return func
-
- Iterator = object
-else:
-
- def get_unbound_function(unbound):
- return unbound.im_func
-
- def create_bound_method(func, obj):
- return types.MethodType(func, obj, obj.__class__)
-
- def create_unbound_method(func, cls):
- return types.MethodType(func, None, cls)
-
- class Iterator(object):
- def next(self):
- return type(self).__next__(self)
-
- callable = callable
-_add_doc(
- get_unbound_function, """Get the function out of a possibly unbound function"""
-)
-
-
-get_method_function = operator.attrgetter(_meth_func)
-get_method_self = operator.attrgetter(_meth_self)
-get_function_closure = operator.attrgetter(_func_closure)
-get_function_code = operator.attrgetter(_func_code)
-get_function_defaults = operator.attrgetter(_func_defaults)
-get_function_globals = operator.attrgetter(_func_globals)
-
-
-if PY3:
-
- def iterkeys(d, **kw):
- return iter(d.keys(**kw))
-
- def itervalues(d, **kw):
- return iter(d.values(**kw))
-
- def iteritems(d, **kw):
- return iter(d.items(**kw))
-
- def iterlists(d, **kw):
- return iter(d.lists(**kw))
-
- viewkeys = operator.methodcaller("keys")
-
- viewvalues = operator.methodcaller("values")
-
- viewitems = operator.methodcaller("items")
-else:
-
- def iterkeys(d, **kw):
- return d.iterkeys(**kw)
-
- def itervalues(d, **kw):
- return d.itervalues(**kw)
-
- def iteritems(d, **kw):
- return d.iteritems(**kw)
-
- def iterlists(d, **kw):
- return d.iterlists(**kw)
-
- viewkeys = operator.methodcaller("viewkeys")
-
- viewvalues = operator.methodcaller("viewvalues")
-
- viewitems = operator.methodcaller("viewitems")
-
-_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
-_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
-_add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.")
-_add_doc(
- iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary."
-)
-
-
-if PY3:
-
- def b(s):
- return s.encode("latin-1")
-
- def u(s):
- return s
-
- unichr = chr
- import struct
-
- int2byte = struct.Struct(">B").pack
- del struct
- byte2int = operator.itemgetter(0)
- indexbytes = operator.getitem
- iterbytes = iter
- import io
-
- StringIO = io.StringIO
- BytesIO = io.BytesIO
- del io
- _assertCountEqual = "assertCountEqual"
- if sys.version_info[1] <= 1:
- _assertRaisesRegex = "assertRaisesRegexp"
- _assertRegex = "assertRegexpMatches"
- _assertNotRegex = "assertNotRegexpMatches"
- else:
- _assertRaisesRegex = "assertRaisesRegex"
- _assertRegex = "assertRegex"
- _assertNotRegex = "assertNotRegex"
-else:
-
- def b(s):
- return s
-
- # Workaround for standalone backslash
-
- def u(s):
- return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape")
-
- unichr = unichr
- int2byte = chr
-
- def byte2int(bs):
- return ord(bs[0])
-
- def indexbytes(buf, i):
- return ord(buf[i])
-
- iterbytes = functools.partial(itertools.imap, ord)
- import StringIO
-
- StringIO = BytesIO = StringIO.StringIO
- _assertCountEqual = "assertItemsEqual"
- _assertRaisesRegex = "assertRaisesRegexp"
- _assertRegex = "assertRegexpMatches"
- _assertNotRegex = "assertNotRegexpMatches"
-_add_doc(b, """Byte literal""")
-_add_doc(u, """Text literal""")
-
-
-def assertCountEqual(self, *args, **kwargs):
- return getattr(self, _assertCountEqual)(*args, **kwargs)
-
-
-def assertRaisesRegex(self, *args, **kwargs):
- return getattr(self, _assertRaisesRegex)(*args, **kwargs)
-
-
-def assertRegex(self, *args, **kwargs):
- return getattr(self, _assertRegex)(*args, **kwargs)
-
-
-def assertNotRegex(self, *args, **kwargs):
- return getattr(self, _assertNotRegex)(*args, **kwargs)
-
-
-if PY3:
- exec_ = getattr(moves.builtins, "exec")
-
- def reraise(tp, value, tb=None):
- try:
- if value is None:
- value = tp()
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
- finally:
- value = None
- tb = None
-
-
-else:
-
- def exec_(_code_, _globs_=None, _locs_=None):
- """Execute code in a namespace."""
- if _globs_ is None:
- frame = sys._getframe(1)
- _globs_ = frame.f_globals
- if _locs_ is None:
- _locs_ = frame.f_locals
- del frame
- elif _locs_ is None:
- _locs_ = _globs_
- exec ("""exec _code_ in _globs_, _locs_""")
-
- exec_(
- """def reraise(tp, value, tb=None):
- try:
- raise tp, value, tb
- finally:
- tb = None
-"""
- )
-
-
-if sys.version_info[:2] > (3,):
- exec_(
- """def raise_from(value, from_value):
- try:
- raise value from from_value
- finally:
- value = None
-"""
- )
-else:
-
- def raise_from(value, from_value):
- raise value
-
-
-print_ = getattr(moves.builtins, "print", None)
-if print_ is None:
-
- def print_(*args, **kwargs):
- """The new-style print function for Python 2.4 and 2.5."""
- fp = kwargs.pop("file", sys.stdout)
- if fp is None:
- return
-
- def write(data):
- if not isinstance(data, basestring):
- data = str(data)
- # If the file has an encoding, encode unicode with it.
- if (
- isinstance(fp, file)
- and isinstance(data, unicode)
- and fp.encoding is not None
- ):
- errors = getattr(fp, "errors", None)
- if errors is None:
- errors = "strict"
- data = data.encode(fp.encoding, errors)
- fp.write(data)
-
- want_unicode = False
- sep = kwargs.pop("sep", None)
- if sep is not None:
- if isinstance(sep, unicode):
- want_unicode = True
- elif not isinstance(sep, str):
- raise TypeError("sep must be None or a string")
- end = kwargs.pop("end", None)
- if end is not None:
- if isinstance(end, unicode):
- want_unicode = True
- elif not isinstance(end, str):
- raise TypeError("end must be None or a string")
- if kwargs:
- raise TypeError("invalid keyword arguments to print()")
- if not want_unicode:
- for arg in args:
- if isinstance(arg, unicode):
- want_unicode = True
- break
- if want_unicode:
- newline = unicode("\n")
- space = unicode(" ")
- else:
- newline = "\n"
- space = " "
- if sep is None:
- sep = space
- if end is None:
- end = newline
- for i, arg in enumerate(args):
- if i:
- write(sep)
- write(arg)
- write(end)
-
-
-if sys.version_info[:2] < (3, 3):
- _print = print_
-
- def print_(*args, **kwargs):
- fp = kwargs.get("file", sys.stdout)
- flush = kwargs.pop("flush", False)
- _print(*args, **kwargs)
- if flush and fp is not None:
- fp.flush()
-
-
-_add_doc(reraise, """Reraise an exception.""")
-
-if sys.version_info[0:2] < (3, 4):
- # This does exactly the same what the :func:`py3:functools.update_wrapper`
- # function does on Python versions after 3.2. It sets the ``__wrapped__``
- # attribute on ``wrapper`` object and it doesn't raise an error if any of
- # the attributes mentioned in ``assigned`` and ``updated`` are missing on
- # ``wrapped`` object.
- def _update_wrapper(
- wrapper,
- wrapped,
- assigned=functools.WRAPPER_ASSIGNMENTS,
- updated=functools.WRAPPER_UPDATES,
- ):
- for attr in assigned:
- try:
- value = getattr(wrapped, attr)
- except AttributeError:
- continue
- else:
- setattr(wrapper, attr, value)
- for attr in updated:
- getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
- wrapper.__wrapped__ = wrapped
- return wrapper
-
- _update_wrapper.__doc__ = functools.update_wrapper.__doc__
-
- def wraps(
- wrapped,
- assigned=functools.WRAPPER_ASSIGNMENTS,
- updated=functools.WRAPPER_UPDATES,
- ):
- return functools.partial(
- _update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated
- )
-
- wraps.__doc__ = functools.wraps.__doc__
-
-else:
- wraps = functools.wraps
-
-
-def with_metaclass(meta, *bases):
- """Create a base class with a metaclass."""
- # This requires a bit of explanation: the basic idea is to make a dummy
- # metaclass for one level of class instantiation that replaces itself with
- # the actual metaclass.
- class metaclass(type):
- def __new__(cls, name, this_bases, d):
- if sys.version_info[:2] >= (3, 7):
- # This version introduced PEP 560 that requires a bit
- # of extra care (we mimic what is done by __build_class__).
- resolved_bases = types.resolve_bases(bases)
- if resolved_bases is not bases:
- d["__orig_bases__"] = bases
- else:
- resolved_bases = bases
- return meta(name, resolved_bases, d)
-
- @classmethod
- def __prepare__(cls, name, this_bases):
- return meta.__prepare__(name, bases)
-
- return type.__new__(metaclass, "temporary_class", (), {})
-
-
-def add_metaclass(metaclass):
- """Class decorator for creating a class with a metaclass."""
-
- def wrapper(cls):
- orig_vars = cls.__dict__.copy()
- slots = orig_vars.get("__slots__")
- if slots is not None:
- if isinstance(slots, str):
- slots = [slots]
- for slots_var in slots:
- orig_vars.pop(slots_var)
- orig_vars.pop("__dict__", None)
- orig_vars.pop("__weakref__", None)
- if hasattr(cls, "__qualname__"):
- orig_vars["__qualname__"] = cls.__qualname__
- return metaclass(cls.__name__, cls.__bases__, orig_vars)
-
- return wrapper
-
-
-def ensure_binary(s, encoding="utf-8", errors="strict"):
- """Coerce **s** to six.binary_type.
-
- For Python 2:
- - `unicode` -> encoded to `str`
- - `str` -> `str`
-
- For Python 3:
- - `str` -> encoded to `bytes`
- - `bytes` -> `bytes`
- """
- if isinstance(s, binary_type):
- return s
- if isinstance(s, text_type):
- return s.encode(encoding, errors)
- raise TypeError("not expecting type '%s'" % type(s))
-
-
-def ensure_str(s, encoding="utf-8", errors="strict"):
- """Coerce *s* to `str`.
-
- For Python 2:
- - `unicode` -> encoded to `str`
- - `str` -> `str`
-
- For Python 3:
- - `str` -> `str`
- - `bytes` -> decoded to `str`
- """
- # Optimization: Fast return for the common case.
- if type(s) is str:
- return s
- if PY2 and isinstance(s, text_type):
- return s.encode(encoding, errors)
- elif PY3 and isinstance(s, binary_type):
- return s.decode(encoding, errors)
- elif not isinstance(s, (text_type, binary_type)):
- raise TypeError("not expecting type '%s'" % type(s))
- return s
-
-
-def ensure_text(s, encoding="utf-8", errors="strict"):
- """Coerce *s* to six.text_type.
-
- For Python 2:
- - `unicode` -> `unicode`
- - `str` -> `unicode`
-
- For Python 3:
- - `str` -> `str`
- - `bytes` -> decoded to `str`
- """
- if isinstance(s, binary_type):
- return s.decode(encoding, errors)
- elif isinstance(s, text_type):
- return s
- else:
- raise TypeError("not expecting type '%s'" % type(s))
-
-
-def python_2_unicode_compatible(klass):
- """
- A class decorator that defines __unicode__ and __str__ methods under Python 2.
- Under Python 3 it does nothing.
-
- To support Python 2 and 3 with a single code base, define a __str__ method
- returning text and apply this decorator to the class.
- """
- if PY2:
- if "__str__" not in klass.__dict__:
- raise ValueError(
- "@python_2_unicode_compatible cannot be applied "
- "to %s because it doesn't define __str__()." % klass.__name__
- )
- klass.__unicode__ = klass.__str__
- klass.__str__ = lambda self: self.__unicode__().encode("utf-8")
- return klass
-
-
-# Complete the moves implementation.
-# This code is at the end of this module to speed up module loading.
-# Turn this module into a package.
-__path__ = [] # required for PEP 302 and PEP 451
-__package__ = __name__ # see PEP 366 @ReservedAssignment
-if globals().get("__spec__") is not None:
- __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
-# Remove other six meta path importers, since they cause problems. This can
-# happen if six is removed from sys.modules and then reloaded. (Setuptools does
-# this for some reason.)
-if sys.meta_path:
- for i, importer in enumerate(sys.meta_path):
- # Here's some real nastiness: Another "instance" of the six module might
- # be floating around. Therefore, we can't use isinstance() to check for
- # the six meta path importer, since the other six instance will have
- # inserted an importer with different class.
- if (
- type(importer).__name__ == "_SixMetaPathImporter"
- and importer.name == __name__
- ):
- del sys.meta_path[i]
- break
- del i, importer
-# Finally, add the importer to the meta path import hook.
-sys.meta_path.append(_importer)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/ssl_match_hostname/__init__.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/ssl_match_hostname/__init__.py
deleted file mode 100644
index ef3fde5206..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/ssl_match_hostname/__init__.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import sys
-
-try:
- # Our match_hostname function is the same as 3.10's, so we only want to
- # import the match_hostname function if it's at least that good.
- # We also fallback on Python 3.10+ because our code doesn't emit
- # deprecation warnings and is the same as Python 3.10 otherwise.
- if sys.version_info < (3, 5) or sys.version_info >= (3, 10):
- raise ImportError("Fallback to vendored code")
-
- from ssl import CertificateError, match_hostname
-except ImportError:
- try:
- # Backport of the function from a pypi module
- from backports.ssl_match_hostname import ( # type: ignore
- CertificateError,
- match_hostname,
- )
- except ImportError:
- # Our vendored copy
- from ._implementation import CertificateError, match_hostname # type: ignore
-
-# Not needed, but documenting what we provide.
-__all__ = ("CertificateError", "match_hostname")
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/ssl_match_hostname/_implementation.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/ssl_match_hostname/_implementation.py
deleted file mode 100644
index 689208d3c6..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/packages/ssl_match_hostname/_implementation.py
+++ /dev/null
@@ -1,160 +0,0 @@
-"""The match_hostname() function from Python 3.3.3, essential when using SSL."""
-
-# Note: This file is under the PSF license as the code comes from the python
-# stdlib. http://docs.python.org/3/license.html
-
-import re
-import sys
-
-# ipaddress has been backported to 2.6+ in pypi. If it is installed on the
-# system, use it to handle IPAddress ServerAltnames (this was added in
-# python-3.5) otherwise only do DNS matching. This allows
-# backports.ssl_match_hostname to continue to be used in Python 2.7.
-try:
- import ipaddress
-except ImportError:
- ipaddress = None
-
-__version__ = "3.5.0.1"
-
-
-class CertificateError(ValueError):
- pass
-
-
-def _dnsname_match(dn, hostname, max_wildcards=1):
- """Matching according to RFC 6125, section 6.4.3
-
- http://tools.ietf.org/html/rfc6125#section-6.4.3
- """
- pats = []
- if not dn:
- return False
-
- # Ported from python3-syntax:
- # leftmost, *remainder = dn.split(r'.')
- parts = dn.split(r".")
- leftmost = parts[0]
- remainder = parts[1:]
-
- wildcards = leftmost.count("*")
- if wildcards > max_wildcards:
- # Issue #17980: avoid denials of service by refusing more
- # than one wildcard per fragment. A survey of established
- # policy among SSL implementations showed it to be a
- # reasonable choice.
- raise CertificateError(
- "too many wildcards in certificate DNS name: " + repr(dn)
- )
-
- # speed up common case w/o wildcards
- if not wildcards:
- return dn.lower() == hostname.lower()
-
- # RFC 6125, section 6.4.3, subitem 1.
- # The client SHOULD NOT attempt to match a presented identifier in which
- # the wildcard character comprises a label other than the left-most label.
- if leftmost == "*":
- # When '*' is a fragment by itself, it matches a non-empty dotless
- # fragment.
- pats.append("[^.]+")
- elif leftmost.startswith("xn--") or hostname.startswith("xn--"):
- # RFC 6125, section 6.4.3, subitem 3.
- # The client SHOULD NOT attempt to match a presented identifier
- # where the wildcard character is embedded within an A-label or
- # U-label of an internationalized domain name.
- pats.append(re.escape(leftmost))
- else:
- # Otherwise, '*' matches any dotless string, e.g. www*
- pats.append(re.escape(leftmost).replace(r"\*", "[^.]*"))
-
- # add the remaining fragments, ignore any wildcards
- for frag in remainder:
- pats.append(re.escape(frag))
-
- pat = re.compile(r"\A" + r"\.".join(pats) + r"\Z", re.IGNORECASE)
- return pat.match(hostname)
-
-
-def _to_unicode(obj):
- if isinstance(obj, str) and sys.version_info < (3,):
- obj = unicode(obj, encoding="ascii", errors="strict")
- return obj
-
-
-def _ipaddress_match(ipname, host_ip):
- """Exact matching of IP addresses.
-
- RFC 6125 explicitly doesn't define an algorithm for this
- (section 1.7.2 - "Out of Scope").
- """
- # OpenSSL may add a trailing newline to a subjectAltName's IP address
- # Divergence from upstream: ipaddress can't handle byte str
- ip = ipaddress.ip_address(_to_unicode(ipname).rstrip())
- return ip == host_ip
-
-
-def match_hostname(cert, hostname):
- """Verify that *cert* (in decoded format as returned by
- SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125
- rules are followed, but IP addresses are not accepted for *hostname*.
-
- CertificateError is raised on failure. On success, the function
- returns nothing.
- """
- if not cert:
- raise ValueError(
- "empty or no certificate, match_hostname needs a "
- "SSL socket or SSL context with either "
- "CERT_OPTIONAL or CERT_REQUIRED"
- )
- try:
- # Divergence from upstream: ipaddress can't handle byte str
- host_ip = ipaddress.ip_address(_to_unicode(hostname))
- except ValueError:
- # Not an IP address (common case)
- host_ip = None
- except UnicodeError:
- # Divergence from upstream: Have to deal with ipaddress not taking
- # byte strings. addresses should be all ascii, so we consider it not
- # an ipaddress in this case
- host_ip = None
- except AttributeError:
- # Divergence from upstream: Make ipaddress library optional
- if ipaddress is None:
- host_ip = None
- else:
- raise
- dnsnames = []
- san = cert.get("subjectAltName", ())
- for key, value in san:
- if key == "DNS":
- if host_ip is None and _dnsname_match(value, hostname):
- return
- dnsnames.append(value)
- elif key == "IP Address":
- if host_ip is not None and _ipaddress_match(value, host_ip):
- return
- dnsnames.append(value)
- if not dnsnames:
- # The subject is only checked when there is no dNSName entry
- # in subjectAltName
- for sub in cert.get("subject", ()):
- for key, value in sub:
- # XXX according to RFC 2818, the most specific Common Name
- # must be used.
- if key == "commonName":
- if _dnsname_match(value, hostname):
- return
- dnsnames.append(value)
- if len(dnsnames) > 1:
- raise CertificateError(
- "hostname %r "
- "doesn't match either of %s" % (hostname, ", ".join(map(repr, dnsnames)))
- )
- elif len(dnsnames) == 1:
- raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0]))
- else:
- raise CertificateError(
- "no appropriate commonName or subjectAltName fields were found"
- )
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/poolmanager.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/poolmanager.py
deleted file mode 100644
index 3a31a285bf..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/poolmanager.py
+++ /dev/null
@@ -1,536 +0,0 @@
-from __future__ import absolute_import
-
-import collections
-import functools
-import logging
-
-from ._collections import RecentlyUsedContainer
-from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, port_by_scheme
-from .exceptions import (
- LocationValueError,
- MaxRetryError,
- ProxySchemeUnknown,
- ProxySchemeUnsupported,
- URLSchemeUnknown,
-)
-from .packages import six
-from .packages.six.moves.urllib.parse import urljoin
-from .request import RequestMethods
-from .util.proxy import connection_requires_http_tunnel
-from .util.retry import Retry
-from .util.url import parse_url
-
-__all__ = ["PoolManager", "ProxyManager", "proxy_from_url"]
-
-
-log = logging.getLogger(__name__)
-
-SSL_KEYWORDS = (
- "key_file",
- "cert_file",
- "cert_reqs",
- "ca_certs",
- "ssl_version",
- "ca_cert_dir",
- "ssl_context",
- "key_password",
-)
-
-# All known keyword arguments that could be provided to the pool manager, its
-# pools, or the underlying connections. This is used to construct a pool key.
-_key_fields = (
- "key_scheme", # str
- "key_host", # str
- "key_port", # int
- "key_timeout", # int or float or Timeout
- "key_retries", # int or Retry
- "key_strict", # bool
- "key_block", # bool
- "key_source_address", # str
- "key_key_file", # str
- "key_key_password", # str
- "key_cert_file", # str
- "key_cert_reqs", # str
- "key_ca_certs", # str
- "key_ssl_version", # str
- "key_ca_cert_dir", # str
- "key_ssl_context", # instance of ssl.SSLContext or urllib3.util.ssl_.SSLContext
- "key_maxsize", # int
- "key_headers", # dict
- "key__proxy", # parsed proxy url
- "key__proxy_headers", # dict
- "key__proxy_config", # class
- "key_socket_options", # list of (level (int), optname (int), value (int or str)) tuples
- "key__socks_options", # dict
- "key_assert_hostname", # bool or string
- "key_assert_fingerprint", # str
- "key_server_hostname", # str
-)
-
-#: The namedtuple class used to construct keys for the connection pool.
-#: All custom key schemes should include the fields in this key at a minimum.
-PoolKey = collections.namedtuple("PoolKey", _key_fields)
-
-_proxy_config_fields = ("ssl_context", "use_forwarding_for_https")
-ProxyConfig = collections.namedtuple("ProxyConfig", _proxy_config_fields)
-
-
-def _default_key_normalizer(key_class, request_context):
- """
- Create a pool key out of a request context dictionary.
-
- According to RFC 3986, both the scheme and host are case-insensitive.
- Therefore, this function normalizes both before constructing the pool
- key for an HTTPS request. If you wish to change this behaviour, provide
- alternate callables to ``key_fn_by_scheme``.
-
- :param key_class:
- The class to use when constructing the key. This should be a namedtuple
- with the ``scheme`` and ``host`` keys at a minimum.
- :type key_class: namedtuple
- :param request_context:
- A dictionary-like object that contain the context for a request.
- :type request_context: dict
-
- :return: A namedtuple that can be used as a connection pool key.
- :rtype: PoolKey
- """
- # Since we mutate the dictionary, make a copy first
- context = request_context.copy()
- context["scheme"] = context["scheme"].lower()
- context["host"] = context["host"].lower()
-
- # These are both dictionaries and need to be transformed into frozensets
- for key in ("headers", "_proxy_headers", "_socks_options"):
- if key in context and context[key] is not None:
- context[key] = frozenset(context[key].items())
-
- # The socket_options key may be a list and needs to be transformed into a
- # tuple.
- socket_opts = context.get("socket_options")
- if socket_opts is not None:
- context["socket_options"] = tuple(socket_opts)
-
- # Map the kwargs to the names in the namedtuple - this is necessary since
- # namedtuples can't have fields starting with '_'.
- for key in list(context.keys()):
- context["key_" + key] = context.pop(key)
-
- # Default to ``None`` for keys missing from the context
- for field in key_class._fields:
- if field not in context:
- context[field] = None
-
- return key_class(**context)
-
-
-#: A dictionary that maps a scheme to a callable that creates a pool key.
-#: This can be used to alter the way pool keys are constructed, if desired.
-#: Each PoolManager makes a copy of this dictionary so they can be configured
-#: globally here, or individually on the instance.
-key_fn_by_scheme = {
- "http": functools.partial(_default_key_normalizer, PoolKey),
- "https": functools.partial(_default_key_normalizer, PoolKey),
-}
-
-pool_classes_by_scheme = {"http": HTTPConnectionPool, "https": HTTPSConnectionPool}
-
-
-class PoolManager(RequestMethods):
- """
- Allows for arbitrary requests while transparently keeping track of
- necessary connection pools for you.
-
- :param num_pools:
- Number of connection pools to cache before discarding the least
- recently used pool.
-
- :param headers:
- Headers to include with all requests, unless other headers are given
- explicitly.
-
- :param \\**connection_pool_kw:
- Additional parameters are used to create fresh
- :class:`urllib3.connectionpool.ConnectionPool` instances.
-
- Example::
-
- >>> manager = PoolManager(num_pools=2)
- >>> r = manager.request('GET', 'http://google.com/')
- >>> r = manager.request('GET', 'http://google.com/mail')
- >>> r = manager.request('GET', 'http://yahoo.com/')
- >>> len(manager.pools)
- 2
-
- """
-
- proxy = None
- proxy_config = None
-
- def __init__(self, num_pools=10, headers=None, **connection_pool_kw):
- RequestMethods.__init__(self, headers)
- self.connection_pool_kw = connection_pool_kw
- self.pools = RecentlyUsedContainer(num_pools, dispose_func=lambda p: p.close())
-
- # Locally set the pool classes and keys so other PoolManagers can
- # override them.
- self.pool_classes_by_scheme = pool_classes_by_scheme
- self.key_fn_by_scheme = key_fn_by_scheme.copy()
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.clear()
- # Return False to re-raise any potential exceptions
- return False
-
- def _new_pool(self, scheme, host, port, request_context=None):
- """
- Create a new :class:`urllib3.connectionpool.ConnectionPool` based on host, port, scheme, and
- any additional pool keyword arguments.
-
- If ``request_context`` is provided, it is provided as keyword arguments
- to the pool class used. This method is used to actually create the
- connection pools handed out by :meth:`connection_from_url` and
- companion methods. It is intended to be overridden for customization.
- """
- pool_cls = self.pool_classes_by_scheme[scheme]
- if request_context is None:
- request_context = self.connection_pool_kw.copy()
-
- # Although the context has everything necessary to create the pool,
- # this function has historically only used the scheme, host, and port
- # in the positional args. When an API change is acceptable these can
- # be removed.
- for key in ("scheme", "host", "port"):
- request_context.pop(key, None)
-
- if scheme == "http":
- for kw in SSL_KEYWORDS:
- request_context.pop(kw, None)
-
- return pool_cls(host, port, **request_context)
-
- def clear(self):
- """
- Empty our store of pools and direct them all to close.
-
- This will not affect in-flight connections, but they will not be
- re-used after completion.
- """
- self.pools.clear()
-
- def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None):
- """
- Get a :class:`urllib3.connectionpool.ConnectionPool` based on the host, port, and scheme.
-
- If ``port`` isn't given, it will be derived from the ``scheme`` using
- ``urllib3.connectionpool.port_by_scheme``. If ``pool_kwargs`` is
- provided, it is merged with the instance's ``connection_pool_kw``
- variable and used to create the new connection pool, if one is
- needed.
- """
-
- if not host:
- raise LocationValueError("No host specified.")
-
- request_context = self._merge_pool_kwargs(pool_kwargs)
- request_context["scheme"] = scheme or "http"
- if not port:
- port = port_by_scheme.get(request_context["scheme"].lower(), 80)
- request_context["port"] = port
- request_context["host"] = host
-
- return self.connection_from_context(request_context)
-
- def connection_from_context(self, request_context):
- """
- Get a :class:`urllib3.connectionpool.ConnectionPool` based on the request context.
-
- ``request_context`` must at least contain the ``scheme`` key and its
- value must be a key in ``key_fn_by_scheme`` instance variable.
- """
- scheme = request_context["scheme"].lower()
- pool_key_constructor = self.key_fn_by_scheme.get(scheme)
- if not pool_key_constructor:
- raise URLSchemeUnknown(scheme)
- pool_key = pool_key_constructor(request_context)
-
- return self.connection_from_pool_key(pool_key, request_context=request_context)
-
- def connection_from_pool_key(self, pool_key, request_context=None):
- """
- Get a :class:`urllib3.connectionpool.ConnectionPool` based on the provided pool key.
-
- ``pool_key`` should be a namedtuple that only contains immutable
- objects. At a minimum it must have the ``scheme``, ``host``, and
- ``port`` fields.
- """
- with self.pools.lock:
- # If the scheme, host, or port doesn't match existing open
- # connections, open a new ConnectionPool.
- pool = self.pools.get(pool_key)
- if pool:
- return pool
-
- # Make a fresh ConnectionPool of the desired type
- scheme = request_context["scheme"]
- host = request_context["host"]
- port = request_context["port"]
- pool = self._new_pool(scheme, host, port, request_context=request_context)
- self.pools[pool_key] = pool
-
- return pool
-
- def connection_from_url(self, url, pool_kwargs=None):
- """
- Similar to :func:`urllib3.connectionpool.connection_from_url`.
-
- If ``pool_kwargs`` is not provided and a new pool needs to be
- constructed, ``self.connection_pool_kw`` is used to initialize
- the :class:`urllib3.connectionpool.ConnectionPool`. If ``pool_kwargs``
- is provided, it is used instead. Note that if a new pool does not
- need to be created for the request, the provided ``pool_kwargs`` are
- not used.
- """
- u = parse_url(url)
- return self.connection_from_host(
- u.host, port=u.port, scheme=u.scheme, pool_kwargs=pool_kwargs
- )
-
- def _merge_pool_kwargs(self, override):
- """
- Merge a dictionary of override values for self.connection_pool_kw.
-
- This does not modify self.connection_pool_kw and returns a new dict.
- Any keys in the override dictionary with a value of ``None`` are
- removed from the merged dictionary.
- """
- base_pool_kwargs = self.connection_pool_kw.copy()
- if override:
- for key, value in override.items():
- if value is None:
- try:
- del base_pool_kwargs[key]
- except KeyError:
- pass
- else:
- base_pool_kwargs[key] = value
- return base_pool_kwargs
-
- def _proxy_requires_url_absolute_form(self, parsed_url):
- """
- Indicates if the proxy requires the complete destination URL in the
- request. Normally this is only needed when not using an HTTP CONNECT
- tunnel.
- """
- if self.proxy is None:
- return False
-
- return not connection_requires_http_tunnel(
- self.proxy, self.proxy_config, parsed_url.scheme
- )
-
- def _validate_proxy_scheme_url_selection(self, url_scheme):
- """
- Validates that were not attempting to do TLS in TLS connections on
- Python2 or with unsupported SSL implementations.
- """
- if self.proxy is None or url_scheme != "https":
- return
-
- if self.proxy.scheme != "https":
- return
-
- if six.PY2 and not self.proxy_config.use_forwarding_for_https:
- raise ProxySchemeUnsupported(
- "Contacting HTTPS destinations through HTTPS proxies "
- "'via CONNECT tunnels' is not supported in Python 2"
- )
-
- def urlopen(self, method, url, redirect=True, **kw):
- """
- Same as :meth:`urllib3.HTTPConnectionPool.urlopen`
- with custom cross-host redirect logic and only sends the request-uri
- portion of the ``url``.
-
- The given ``url`` parameter must be absolute, such that an appropriate
- :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it.
- """
- u = parse_url(url)
- self._validate_proxy_scheme_url_selection(u.scheme)
-
- conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme)
-
- kw["assert_same_host"] = False
- kw["redirect"] = False
-
- if "headers" not in kw:
- kw["headers"] = self.headers.copy()
-
- if self._proxy_requires_url_absolute_form(u):
- response = conn.urlopen(method, url, **kw)
- else:
- response = conn.urlopen(method, u.request_uri, **kw)
-
- redirect_location = redirect and response.get_redirect_location()
- if not redirect_location:
- return response
-
- # Support relative URLs for redirecting.
- redirect_location = urljoin(url, redirect_location)
-
- # RFC 7231, Section 6.4.4
- if response.status == 303:
- method = "GET"
-
- retries = kw.get("retries")
- if not isinstance(retries, Retry):
- retries = Retry.from_int(retries, redirect=redirect)
-
- # Strip headers marked as unsafe to forward to the redirected location.
- # Check remove_headers_on_redirect to avoid a potential network call within
- # conn.is_same_host() which may use socket.gethostbyname() in the future.
- if retries.remove_headers_on_redirect and not conn.is_same_host(
- redirect_location
- ):
- headers = list(six.iterkeys(kw["headers"]))
- for header in headers:
- if header.lower() in retries.remove_headers_on_redirect:
- kw["headers"].pop(header, None)
-
- try:
- retries = retries.increment(method, url, response=response, _pool=conn)
- except MaxRetryError:
- if retries.raise_on_redirect:
- response.drain_conn()
- raise
- return response
-
- kw["retries"] = retries
- kw["redirect"] = redirect
-
- log.info("Redirecting %s -> %s", url, redirect_location)
-
- response.drain_conn()
- return self.urlopen(method, redirect_location, **kw)
-
-
-class ProxyManager(PoolManager):
- """
- Behaves just like :class:`PoolManager`, but sends all requests through
- the defined proxy, using the CONNECT method for HTTPS URLs.
-
- :param proxy_url:
- The URL of the proxy to be used.
-
- :param proxy_headers:
- A dictionary containing headers that will be sent to the proxy. In case
- of HTTP they are being sent with each request, while in the
- HTTPS/CONNECT case they are sent only once. Could be used for proxy
- authentication.
-
- :param proxy_ssl_context:
- The proxy SSL context is used to establish the TLS connection to the
- proxy when using HTTPS proxies.
-
- :param use_forwarding_for_https:
- (Defaults to False) If set to True will forward requests to the HTTPS
- proxy to be made on behalf of the client instead of creating a TLS
- tunnel via the CONNECT method. **Enabling this flag means that request
- and response headers and content will be visible from the HTTPS proxy**
- whereas tunneling keeps request and response headers and content
- private. IP address, target hostname, SNI, and port are always visible
- to an HTTPS proxy even when this flag is disabled.
-
- Example:
- >>> proxy = urllib3.ProxyManager('http://localhost:3128/')
- >>> r1 = proxy.request('GET', 'http://google.com/')
- >>> r2 = proxy.request('GET', 'http://httpbin.org/')
- >>> len(proxy.pools)
- 1
- >>> r3 = proxy.request('GET', 'https://httpbin.org/')
- >>> r4 = proxy.request('GET', 'https://twitter.com/')
- >>> len(proxy.pools)
- 3
-
- """
-
- def __init__(
- self,
- proxy_url,
- num_pools=10,
- headers=None,
- proxy_headers=None,
- proxy_ssl_context=None,
- use_forwarding_for_https=False,
- **connection_pool_kw
- ):
-
- if isinstance(proxy_url, HTTPConnectionPool):
- proxy_url = "%s://%s:%i" % (
- proxy_url.scheme,
- proxy_url.host,
- proxy_url.port,
- )
- proxy = parse_url(proxy_url)
-
- if proxy.scheme not in ("http", "https"):
- raise ProxySchemeUnknown(proxy.scheme)
-
- if not proxy.port:
- port = port_by_scheme.get(proxy.scheme, 80)
- proxy = proxy._replace(port=port)
-
- self.proxy = proxy
- self.proxy_headers = proxy_headers or {}
- self.proxy_ssl_context = proxy_ssl_context
- self.proxy_config = ProxyConfig(proxy_ssl_context, use_forwarding_for_https)
-
- connection_pool_kw["_proxy"] = self.proxy
- connection_pool_kw["_proxy_headers"] = self.proxy_headers
- connection_pool_kw["_proxy_config"] = self.proxy_config
-
- super(ProxyManager, self).__init__(num_pools, headers, **connection_pool_kw)
-
- def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None):
- if scheme == "https":
- return super(ProxyManager, self).connection_from_host(
- host, port, scheme, pool_kwargs=pool_kwargs
- )
-
- return super(ProxyManager, self).connection_from_host(
- self.proxy.host, self.proxy.port, self.proxy.scheme, pool_kwargs=pool_kwargs
- )
-
- def _set_proxy_headers(self, url, headers=None):
- """
- Sets headers needed by proxies: specifically, the Accept and Host
- headers. Only sets headers not provided by the user.
- """
- headers_ = {"Accept": "*/*"}
-
- netloc = parse_url(url).netloc
- if netloc:
- headers_["Host"] = netloc
-
- if headers:
- headers_.update(headers)
- return headers_
-
- def urlopen(self, method, url, redirect=True, **kw):
- "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute."
- u = parse_url(url)
- if not connection_requires_http_tunnel(self.proxy, self.proxy_config, u.scheme):
- # For connections using HTTP CONNECT, httplib sets the necessary
- # headers on the CONNECT to the proxy. If we're not using CONNECT,
- # we'll definitely need to set 'Host' at the very least.
- headers = kw.get("headers", self.headers)
- kw["headers"] = self._set_proxy_headers(url, headers)
-
- return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw)
-
-
-def proxy_from_url(url, **kw):
- return ProxyManager(proxy_url=url, **kw)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/request.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/request.py
deleted file mode 100644
index 398386a5b9..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/request.py
+++ /dev/null
@@ -1,170 +0,0 @@
-from __future__ import absolute_import
-
-from .filepost import encode_multipart_formdata
-from .packages.six.moves.urllib.parse import urlencode
-
-__all__ = ["RequestMethods"]
-
-
-class RequestMethods(object):
- """
- Convenience mixin for classes who implement a :meth:`urlopen` method, such
- as :class:`urllib3.HTTPConnectionPool` and
- :class:`urllib3.PoolManager`.
-
- Provides behavior for making common types of HTTP request methods and
- decides which type of request field encoding to use.
-
- Specifically,
-
- :meth:`.request_encode_url` is for sending requests whose fields are
- encoded in the URL (such as GET, HEAD, DELETE).
-
- :meth:`.request_encode_body` is for sending requests whose fields are
- encoded in the *body* of the request using multipart or www-form-urlencoded
- (such as for POST, PUT, PATCH).
-
- :meth:`.request` is for making any kind of request, it will look up the
- appropriate encoding format and use one of the above two methods to make
- the request.
-
- Initializer parameters:
-
- :param headers:
- Headers to include with all requests, unless other headers are given
- explicitly.
- """
-
- _encode_url_methods = {"DELETE", "GET", "HEAD", "OPTIONS"}
-
- def __init__(self, headers=None):
- self.headers = headers or {}
-
- def urlopen(
- self,
- method,
- url,
- body=None,
- headers=None,
- encode_multipart=True,
- multipart_boundary=None,
- **kw
- ): # Abstract
- raise NotImplementedError(
- "Classes extending RequestMethods must implement "
- "their own ``urlopen`` method."
- )
-
- def request(self, method, url, fields=None, headers=None, **urlopen_kw):
- """
- Make a request using :meth:`urlopen` with the appropriate encoding of
- ``fields`` based on the ``method`` used.
-
- This is a convenience method that requires the least amount of manual
- effort. It can be used in most situations, while still having the
- option to drop down to more specific methods when necessary, such as
- :meth:`request_encode_url`, :meth:`request_encode_body`,
- or even the lowest level :meth:`urlopen`.
- """
- method = method.upper()
-
- urlopen_kw["request_url"] = url
-
- if method in self._encode_url_methods:
- return self.request_encode_url(
- method, url, fields=fields, headers=headers, **urlopen_kw
- )
- else:
- return self.request_encode_body(
- method, url, fields=fields, headers=headers, **urlopen_kw
- )
-
- def request_encode_url(self, method, url, fields=None, headers=None, **urlopen_kw):
- """
- Make a request using :meth:`urlopen` with the ``fields`` encoded in
- the url. This is useful for request methods like GET, HEAD, DELETE, etc.
- """
- if headers is None:
- headers = self.headers
-
- extra_kw = {"headers": headers}
- extra_kw.update(urlopen_kw)
-
- if fields:
- url += "?" + urlencode(fields)
-
- return self.urlopen(method, url, **extra_kw)
-
- def request_encode_body(
- self,
- method,
- url,
- fields=None,
- headers=None,
- encode_multipart=True,
- multipart_boundary=None,
- **urlopen_kw
- ):
- """
- Make a request using :meth:`urlopen` with the ``fields`` encoded in
- the body. This is useful for request methods like POST, PUT, PATCH, etc.
-
- When ``encode_multipart=True`` (default), then
- :func:`urllib3.encode_multipart_formdata` is used to encode
- the payload with the appropriate content type. Otherwise
- :func:`urllib.parse.urlencode` is used with the
- 'application/x-www-form-urlencoded' content type.
-
- Multipart encoding must be used when posting files, and it's reasonably
- safe to use it in other times too. However, it may break request
- signing, such as with OAuth.
-
- Supports an optional ``fields`` parameter of key/value strings AND
- key/filetuple. A filetuple is a (filename, data, MIME type) tuple where
- the MIME type is optional. For example::
-
- fields = {
- 'foo': 'bar',
- 'fakefile': ('foofile.txt', 'contents of foofile'),
- 'realfile': ('barfile.txt', open('realfile').read()),
- 'typedfile': ('bazfile.bin', open('bazfile').read(),
- 'image/jpeg'),
- 'nonamefile': 'contents of nonamefile field',
- }
-
- When uploading a file, providing a filename (the first parameter of the
- tuple) is optional but recommended to best mimic behavior of browsers.
-
- Note that if ``headers`` are supplied, the 'Content-Type' header will
- be overwritten because it depends on the dynamic random boundary string
- which is used to compose the body of the request. The random boundary
- string can be explicitly set with the ``multipart_boundary`` parameter.
- """
- if headers is None:
- headers = self.headers
-
- extra_kw = {"headers": {}}
-
- if fields:
- if "body" in urlopen_kw:
- raise TypeError(
- "request got values for both 'fields' and 'body', can only specify one."
- )
-
- if encode_multipart:
- body, content_type = encode_multipart_formdata(
- fields, boundary=multipart_boundary
- )
- else:
- body, content_type = (
- urlencode(fields),
- "application/x-www-form-urlencoded",
- )
-
- extra_kw["body"] = body
- extra_kw["headers"] = {"Content-Type": content_type}
-
- extra_kw["headers"].update(headers)
- extra_kw.update(urlopen_kw)
-
- return self.urlopen(method, url, **extra_kw)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/response.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/response.py
deleted file mode 100644
index 38693f4fc6..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/response.py
+++ /dev/null
@@ -1,821 +0,0 @@
-from __future__ import absolute_import
-
-import io
-import logging
-import zlib
-from contextlib import contextmanager
-from socket import error as SocketError
-from socket import timeout as SocketTimeout
-
-try:
- import brotli
-except ImportError:
- brotli = None
-
-from ._collections import HTTPHeaderDict
-from .connection import BaseSSLError, HTTPException
-from .exceptions import (
- BodyNotHttplibCompatible,
- DecodeError,
- HTTPError,
- IncompleteRead,
- InvalidChunkLength,
- InvalidHeader,
- ProtocolError,
- ReadTimeoutError,
- ResponseNotChunked,
- SSLError,
-)
-from .packages import six
-from .util.response import is_fp_closed, is_response_to_head
-
-log = logging.getLogger(__name__)
-
-
-class DeflateDecoder(object):
- def __init__(self):
- self._first_try = True
- self._data = b""
- self._obj = zlib.decompressobj()
-
- def __getattr__(self, name):
- return getattr(self._obj, name)
-
- def decompress(self, data):
- if not data:
- return data
-
- if not self._first_try:
- return self._obj.decompress(data)
-
- self._data += data
- try:
- decompressed = self._obj.decompress(data)
- if decompressed:
- self._first_try = False
- self._data = None
- return decompressed
- except zlib.error:
- self._first_try = False
- self._obj = zlib.decompressobj(-zlib.MAX_WBITS)
- try:
- return self.decompress(self._data)
- finally:
- self._data = None
-
-
-class GzipDecoderState(object):
-
- FIRST_MEMBER = 0
- OTHER_MEMBERS = 1
- SWALLOW_DATA = 2
-
-
-class GzipDecoder(object):
- def __init__(self):
- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
- self._state = GzipDecoderState.FIRST_MEMBER
-
- def __getattr__(self, name):
- return getattr(self._obj, name)
-
- def decompress(self, data):
- ret = bytearray()
- if self._state == GzipDecoderState.SWALLOW_DATA or not data:
- return bytes(ret)
- while True:
- try:
- ret += self._obj.decompress(data)
- except zlib.error:
- previous_state = self._state
- # Ignore data after the first error
- self._state = GzipDecoderState.SWALLOW_DATA
- if previous_state == GzipDecoderState.OTHER_MEMBERS:
- # Allow trailing garbage acceptable in other gzip clients
- return bytes(ret)
- raise
- data = self._obj.unused_data
- if not data:
- return bytes(ret)
- self._state = GzipDecoderState.OTHER_MEMBERS
- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
-
-
-if brotli is not None:
-
- class BrotliDecoder(object):
- # Supports both 'brotlipy' and 'Brotli' packages
- # since they share an import name. The top branches
- # are for 'brotlipy' and bottom branches for 'Brotli'
- def __init__(self):
- self._obj = brotli.Decompressor()
- if hasattr(self._obj, "decompress"):
- self.decompress = self._obj.decompress
- else:
- self.decompress = self._obj.process
-
- def flush(self):
- if hasattr(self._obj, "flush"):
- return self._obj.flush()
- return b""
-
-
-class MultiDecoder(object):
- """
- From RFC7231:
- If one or more encodings have been applied to a representation, the
- sender that applied the encodings MUST generate a Content-Encoding
- header field that lists the content codings in the order in which
- they were applied.
- """
-
- def __init__(self, modes):
- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")]
-
- def flush(self):
- return self._decoders[0].flush()
-
- def decompress(self, data):
- for d in reversed(self._decoders):
- data = d.decompress(data)
- return data
-
-
-def _get_decoder(mode):
- if "," in mode:
- return MultiDecoder(mode)
-
- if mode == "gzip":
- return GzipDecoder()
-
- if brotli is not None and mode == "br":
- return BrotliDecoder()
-
- return DeflateDecoder()
-
-
-class HTTPResponse(io.IOBase):
- """
- HTTP Response container.
-
- Backwards-compatible with :class:`http.client.HTTPResponse` but the response ``body`` is
- loaded and decoded on-demand when the ``data`` property is accessed. This
- class is also compatible with the Python standard library's :mod:`io`
- module, and can hence be treated as a readable object in the context of that
- framework.
-
- Extra parameters for behaviour not present in :class:`http.client.HTTPResponse`:
-
- :param preload_content:
- If True, the response's body will be preloaded during construction.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
-
- :param original_response:
- When this HTTPResponse wrapper is generated from an :class:`http.client.HTTPResponse`
- object, it's convenient to include the original for debug purposes. It's
- otherwise unused.
-
- :param retries:
- The retries contains the last :class:`~urllib3.util.retry.Retry` that
- was used during the request.
-
- :param enforce_content_length:
- Enforce content length checking. Body returned by server must match
- value of Content-Length header, if present. Otherwise, raise error.
- """
-
- CONTENT_DECODERS = ["gzip", "deflate"]
- if brotli is not None:
- CONTENT_DECODERS += ["br"]
- REDIRECT_STATUSES = [301, 302, 303, 307, 308]
-
- def __init__(
- self,
- body="",
- headers=None,
- status=0,
- version=0,
- reason=None,
- strict=0,
- preload_content=True,
- decode_content=True,
- original_response=None,
- pool=None,
- connection=None,
- msg=None,
- retries=None,
- enforce_content_length=False,
- request_method=None,
- request_url=None,
- auto_close=True,
- ):
-
- if isinstance(headers, HTTPHeaderDict):
- self.headers = headers
- else:
- self.headers = HTTPHeaderDict(headers)
- self.status = status
- self.version = version
- self.reason = reason
- self.strict = strict
- self.decode_content = decode_content
- self.retries = retries
- self.enforce_content_length = enforce_content_length
- self.auto_close = auto_close
-
- self._decoder = None
- self._body = None
- self._fp = None
- self._original_response = original_response
- self._fp_bytes_read = 0
- self.msg = msg
- self._request_url = request_url
-
- if body and isinstance(body, (six.string_types, bytes)):
- self._body = body
-
- self._pool = pool
- self._connection = connection
-
- if hasattr(body, "read"):
- self._fp = body
-
- # Are we using the chunked-style of transfer encoding?
- self.chunked = False
- self.chunk_left = None
- tr_enc = self.headers.get("transfer-encoding", "").lower()
- # Don't incur the penalty of creating a list and then discarding it
- encodings = (enc.strip() for enc in tr_enc.split(","))
- if "chunked" in encodings:
- self.chunked = True
-
- # Determine length of response
- self.length_remaining = self._init_length(request_method)
-
- # If requested, preload the body.
- if preload_content and not self._body:
- self._body = self.read(decode_content=decode_content)
-
- def get_redirect_location(self):
- """
- Should we redirect and where to?
-
- :returns: Truthy redirect location string if we got a redirect status
- code and valid location. ``None`` if redirect status and no
- location. ``False`` if not a redirect status code.
- """
- if self.status in self.REDIRECT_STATUSES:
- return self.headers.get("location")
-
- return False
-
- def release_conn(self):
- if not self._pool or not self._connection:
- return
-
- self._pool._put_conn(self._connection)
- self._connection = None
-
- def drain_conn(self):
- """
- Read and discard any remaining HTTP response data in the response connection.
-
- Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
- """
- try:
- self.read()
- except (HTTPError, SocketError, BaseSSLError, HTTPException):
- pass
-
- @property
- def data(self):
- # For backwards-compat with earlier urllib3 0.4 and earlier.
- if self._body:
- return self._body
-
- if self._fp:
- return self.read(cache_content=True)
-
- @property
- def connection(self):
- return self._connection
-
- def isclosed(self):
- return is_fp_closed(self._fp)
-
- def tell(self):
- """
- Obtain the number of bytes pulled over the wire so far. May differ from
- the amount of content returned by :meth:``urllib3.response.HTTPResponse.read``
- if bytes are encoded on the wire (e.g, compressed).
- """
- return self._fp_bytes_read
-
- def _init_length(self, request_method):
- """
- Set initial length value for Response content if available.
- """
- length = self.headers.get("content-length")
-
- if length is not None:
- if self.chunked:
- # This Response will fail with an IncompleteRead if it can't be
- # received as chunked. This method falls back to attempt reading
- # the response before raising an exception.
- log.warning(
- "Received response with both Content-Length and "
- "Transfer-Encoding set. This is expressly forbidden "
- "by RFC 7230 sec 3.3.2. Ignoring Content-Length and "
- "attempting to process response as Transfer-Encoding: "
- "chunked."
- )
- return None
-
- try:
- # RFC 7230 section 3.3.2 specifies multiple content lengths can
- # be sent in a single Content-Length header
- # (e.g. Content-Length: 42, 42). This line ensures the values
- # are all valid ints and that as long as the `set` length is 1,
- # all values are the same. Otherwise, the header is invalid.
- lengths = set([int(val) for val in length.split(",")])
- if len(lengths) > 1:
- raise InvalidHeader(
- "Content-Length contained multiple "
- "unmatching values (%s)" % length
- )
- length = lengths.pop()
- except ValueError:
- length = None
- else:
- if length < 0:
- length = None
-
- # Convert status to int for comparison
- # In some cases, httplib returns a status of "_UNKNOWN"
- try:
- status = int(self.status)
- except ValueError:
- status = 0
-
- # Check for responses that shouldn't include a body
- if status in (204, 304) or 100 <= status < 200 or request_method == "HEAD":
- length = 0
-
- return length
-
- def _init_decoder(self):
- """
- Set-up the _decoder attribute if necessary.
- """
- # Note: content-encoding value should be case-insensitive, per RFC 7230
- # Section 3.2
- content_encoding = self.headers.get("content-encoding", "").lower()
- if self._decoder is None:
- if content_encoding in self.CONTENT_DECODERS:
- self._decoder = _get_decoder(content_encoding)
- elif "," in content_encoding:
- encodings = [
- e.strip()
- for e in content_encoding.split(",")
- if e.strip() in self.CONTENT_DECODERS
- ]
- if len(encodings):
- self._decoder = _get_decoder(content_encoding)
-
- DECODER_ERROR_CLASSES = (IOError, zlib.error)
- if brotli is not None:
- DECODER_ERROR_CLASSES += (brotli.error,)
-
- def _decode(self, data, decode_content, flush_decoder):
- """
- Decode the data passed in and potentially flush the decoder.
- """
- if not decode_content:
- return data
-
- try:
- if self._decoder:
- data = self._decoder.decompress(data)
- except self.DECODER_ERROR_CLASSES as e:
- content_encoding = self.headers.get("content-encoding", "").lower()
- raise DecodeError(
- "Received response with content-encoding: %s, but "
- "failed to decode it." % content_encoding,
- e,
- )
- if flush_decoder:
- data += self._flush_decoder()
-
- return data
-
- def _flush_decoder(self):
- """
- Flushes the decoder. Should only be called if the decoder is actually
- being used.
- """
- if self._decoder:
- buf = self._decoder.decompress(b"")
- return buf + self._decoder.flush()
-
- return b""
-
- @contextmanager
- def _error_catcher(self):
- """
- Catch low-level python exceptions, instead re-raising urllib3
- variants, so that low-level exceptions are not leaked in the
- high-level api.
-
- On exit, release the connection back to the pool.
- """
- clean_exit = False
-
- try:
- try:
- yield
-
- except SocketTimeout:
- # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but
- # there is yet no clean way to get at it from this context.
- raise ReadTimeoutError(self._pool, None, "Read timed out.")
-
- except BaseSSLError as e:
- # FIXME: Is there a better way to differentiate between SSLErrors?
- if "read operation timed out" not in str(e):
- # SSL errors related to framing/MAC get wrapped and reraised here
- raise SSLError(e)
-
- raise ReadTimeoutError(self._pool, None, "Read timed out.")
-
- except (HTTPException, SocketError) as e:
- # This includes IncompleteRead.
- raise ProtocolError("Connection broken: %r" % e, e)
-
- # If no exception is thrown, we should avoid cleaning up
- # unnecessarily.
- clean_exit = True
- finally:
- # If we didn't terminate cleanly, we need to throw away our
- # connection.
- if not clean_exit:
- # The response may not be closed but we're not going to use it
- # anymore so close it now to ensure that the connection is
- # released back to the pool.
- if self._original_response:
- self._original_response.close()
-
- # Closing the response may not actually be sufficient to close
- # everything, so if we have a hold of the connection close that
- # too.
- if self._connection:
- self._connection.close()
-
- # If we hold the original response but it's closed now, we should
- # return the connection back to the pool.
- if self._original_response and self._original_response.isclosed():
- self.release_conn()
-
- def read(self, amt=None, decode_content=None, cache_content=False):
- """
- Similar to :meth:`http.client.HTTPResponse.read`, but with two additional
- parameters: ``decode_content`` and ``cache_content``.
-
- :param amt:
- How much of the content to read. If specified, caching is skipped
- because it doesn't make sense to cache partial content as the full
- response.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
-
- :param cache_content:
- If True, will save the returned data such that the same result is
- returned despite of the state of the underlying file object. This
- is useful if you want the ``.data`` property to continue working
- after having ``.read()`` the file object. (Overridden if ``amt`` is
- set.)
- """
- self._init_decoder()
- if decode_content is None:
- decode_content = self.decode_content
-
- if self._fp is None:
- return
-
- flush_decoder = False
- fp_closed = getattr(self._fp, "closed", False)
-
- with self._error_catcher():
- if amt is None:
- # cStringIO doesn't like amt=None
- data = self._fp.read() if not fp_closed else b""
- flush_decoder = True
- else:
- cache_content = False
- data = self._fp.read(amt) if not fp_closed else b""
- if (
- amt != 0 and not data
- ): # Platform-specific: Buggy versions of Python.
- # Close the connection when no data is returned
- #
- # This is redundant to what httplib/http.client _should_
- # already do. However, versions of python released before
- # December 15, 2012 (http://bugs.python.org/issue16298) do
- # not properly close the connection in all cases. There is
- # no harm in redundantly calling close.
- self._fp.close()
- flush_decoder = True
- if self.enforce_content_length and self.length_remaining not in (
- 0,
- None,
- ):
- # This is an edge case that httplib failed to cover due
- # to concerns of backward compatibility. We're
- # addressing it here to make sure IncompleteRead is
- # raised during streaming, so all calls with incorrect
- # Content-Length are caught.
- raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
-
- if data:
- self._fp_bytes_read += len(data)
- if self.length_remaining is not None:
- self.length_remaining -= len(data)
-
- data = self._decode(data, decode_content, flush_decoder)
-
- if cache_content:
- self._body = data
-
- return data
-
- def stream(self, amt=2 ** 16, decode_content=None):
- """
- A generator wrapper for the read() method. A call will block until
- ``amt`` bytes have been read from the connection or until the
- connection is closed.
-
- :param amt:
- How much of the content to read. The generator will return up to
- much data per iteration, but may return less. This is particularly
- likely when using compressed data. However, the empty string will
- never be returned.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
- """
- if self.chunked and self.supports_chunked_reads():
- for line in self.read_chunked(amt, decode_content=decode_content):
- yield line
- else:
- while not is_fp_closed(self._fp):
- data = self.read(amt=amt, decode_content=decode_content)
-
- if data:
- yield data
-
- @classmethod
- def from_httplib(ResponseCls, r, **response_kw):
- """
- Given an :class:`http.client.HTTPResponse` instance ``r``, return a
- corresponding :class:`urllib3.response.HTTPResponse` object.
-
- Remaining parameters are passed to the HTTPResponse constructor, along
- with ``original_response=r``.
- """
- headers = r.msg
-
- if not isinstance(headers, HTTPHeaderDict):
- if six.PY2:
- # Python 2.7
- headers = HTTPHeaderDict.from_httplib(headers)
- else:
- headers = HTTPHeaderDict(headers.items())
-
- # HTTPResponse objects in Python 3 don't have a .strict attribute
- strict = getattr(r, "strict", 0)
- resp = ResponseCls(
- body=r,
- headers=headers,
- status=r.status,
- version=r.version,
- reason=r.reason,
- strict=strict,
- original_response=r,
- **response_kw
- )
- return resp
-
- # Backwards-compatibility methods for http.client.HTTPResponse
- def getheaders(self):
- return self.headers
-
- def getheader(self, name, default=None):
- return self.headers.get(name, default)
-
- # Backwards compatibility for http.cookiejar
- def info(self):
- return self.headers
-
- # Overrides from io.IOBase
- def close(self):
- if not self.closed:
- self._fp.close()
-
- if self._connection:
- self._connection.close()
-
- if not self.auto_close:
- io.IOBase.close(self)
-
- @property
- def closed(self):
- if not self.auto_close:
- return io.IOBase.closed.__get__(self)
- elif self._fp is None:
- return True
- elif hasattr(self._fp, "isclosed"):
- return self._fp.isclosed()
- elif hasattr(self._fp, "closed"):
- return self._fp.closed
- else:
- return True
-
- def fileno(self):
- if self._fp is None:
- raise IOError("HTTPResponse has no file to get a fileno from")
- elif hasattr(self._fp, "fileno"):
- return self._fp.fileno()
- else:
- raise IOError(
- "The file-like object this HTTPResponse is wrapped "
- "around has no file descriptor"
- )
-
- def flush(self):
- if (
- self._fp is not None
- and hasattr(self._fp, "flush")
- and not getattr(self._fp, "closed", False)
- ):
- return self._fp.flush()
-
- def readable(self):
- # This method is required for `io` module compatibility.
- return True
-
- def readinto(self, b):
- # This method is required for `io` module compatibility.
- temp = self.read(len(b))
- if len(temp) == 0:
- return 0
- else:
- b[: len(temp)] = temp
- return len(temp)
-
- def supports_chunked_reads(self):
- """
- Checks if the underlying file-like object looks like a
- :class:`http.client.HTTPResponse` object. We do this by testing for
- the fp attribute. If it is present we assume it returns raw chunks as
- processed by read_chunked().
- """
- return hasattr(self._fp, "fp")
-
- def _update_chunk_length(self):
- # First, we'll figure out length of a chunk and then
- # we'll try to read it from socket.
- if self.chunk_left is not None:
- return
- line = self._fp.fp.readline()
- line = line.split(b";", 1)[0]
- try:
- self.chunk_left = int(line, 16)
- except ValueError:
- # Invalid chunked protocol response, abort.
- self.close()
- raise InvalidChunkLength(self, line)
-
- def _handle_chunk(self, amt):
- returned_chunk = None
- if amt is None:
- chunk = self._fp._safe_read(self.chunk_left)
- returned_chunk = chunk
- self._fp._safe_read(2) # Toss the CRLF at the end of the chunk.
- self.chunk_left = None
- elif amt < self.chunk_left:
- value = self._fp._safe_read(amt)
- self.chunk_left = self.chunk_left - amt
- returned_chunk = value
- elif amt == self.chunk_left:
- value = self._fp._safe_read(amt)
- self._fp._safe_read(2) # Toss the CRLF at the end of the chunk.
- self.chunk_left = None
- returned_chunk = value
- else: # amt > self.chunk_left
- returned_chunk = self._fp._safe_read(self.chunk_left)
- self._fp._safe_read(2) # Toss the CRLF at the end of the chunk.
- self.chunk_left = None
- return returned_chunk
-
- def read_chunked(self, amt=None, decode_content=None):
- """
- Similar to :meth:`HTTPResponse.read`, but with an additional
- parameter: ``decode_content``.
-
- :param amt:
- How much of the content to read. If specified, caching is skipped
- because it doesn't make sense to cache partial content as the full
- response.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
- """
- self._init_decoder()
- # FIXME: Rewrite this method and make it a class with a better structured logic.
- if not self.chunked:
- raise ResponseNotChunked(
- "Response is not chunked. "
- "Header 'transfer-encoding: chunked' is missing."
- )
- if not self.supports_chunked_reads():
- raise BodyNotHttplibCompatible(
- "Body should be http.client.HTTPResponse like. "
- "It should have have an fp attribute which returns raw chunks."
- )
-
- with self._error_catcher():
- # Don't bother reading the body of a HEAD request.
- if self._original_response and is_response_to_head(self._original_response):
- self._original_response.close()
- return
-
- # If a response is already read and closed
- # then return immediately.
- if self._fp.fp is None:
- return
-
- while True:
- self._update_chunk_length()
- if self.chunk_left == 0:
- break
- chunk = self._handle_chunk(amt)
- decoded = self._decode(
- chunk, decode_content=decode_content, flush_decoder=False
- )
- if decoded:
- yield decoded
-
- if decode_content:
- # On CPython and PyPy, we should never need to flush the
- # decoder. However, on Jython we *might* need to, so
- # lets defensively do it anyway.
- decoded = self._flush_decoder()
- if decoded: # Platform-specific: Jython.
- yield decoded
-
- # Chunk content ends with \r\n: discard it.
- while True:
- line = self._fp.fp.readline()
- if not line:
- # Some sites may not end with '\r\n'.
- break
- if line == b"\r\n":
- break
-
- # We read everything; close the "file".
- if self._original_response:
- self._original_response.close()
-
- def geturl(self):
- """
- Returns the URL that was the source of this response.
- If the request that generated this response redirected, this method
- will return the final redirect location.
- """
- if self.retries is not None and len(self.retries.history):
- return self.retries.history[-1].redirect_location
- else:
- return self._request_url
-
- def __iter__(self):
- buffer = []
- for chunk in self.stream(decode_content=True):
- if b"\n" in chunk:
- chunk = chunk.split(b"\n")
- yield b"".join(buffer) + chunk[0] + b"\n"
- for x in chunk[1:-1]:
- yield x + b"\n"
- if chunk[-1]:
- buffer = [chunk[-1]]
- else:
- buffer = []
- else:
- buffer.append(chunk)
- if buffer:
- yield b"".join(buffer)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/__init__.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/__init__.py
deleted file mode 100644
index 4547fc522b..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/__init__.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from __future__ import absolute_import
-
-# For backwards compatibility, provide imports that used to be here.
-from .connection import is_connection_dropped
-from .request import SKIP_HEADER, SKIPPABLE_HEADERS, make_headers
-from .response import is_fp_closed
-from .retry import Retry
-from .ssl_ import (
- ALPN_PROTOCOLS,
- HAS_SNI,
- IS_PYOPENSSL,
- IS_SECURETRANSPORT,
- PROTOCOL_TLS,
- SSLContext,
- assert_fingerprint,
- resolve_cert_reqs,
- resolve_ssl_version,
- ssl_wrap_socket,
-)
-from .timeout import Timeout, current_time
-from .url import Url, get_host, parse_url, split_first
-from .wait import wait_for_read, wait_for_write
-
-__all__ = (
- "HAS_SNI",
- "IS_PYOPENSSL",
- "IS_SECURETRANSPORT",
- "SSLContext",
- "PROTOCOL_TLS",
- "ALPN_PROTOCOLS",
- "Retry",
- "Timeout",
- "Url",
- "assert_fingerprint",
- "current_time",
- "is_connection_dropped",
- "is_fp_closed",
- "get_host",
- "parse_url",
- "make_headers",
- "resolve_cert_reqs",
- "resolve_ssl_version",
- "split_first",
- "ssl_wrap_socket",
- "wait_for_read",
- "wait_for_write",
- "SKIP_HEADER",
- "SKIPPABLE_HEADERS",
-)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/connection.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/connection.py
deleted file mode 100644
index bdc240c50c..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/connection.py
+++ /dev/null
@@ -1,150 +0,0 @@
-from __future__ import absolute_import
-
-import socket
-
-from urllib3.exceptions import LocationParseError
-
-from ..contrib import _appengine_environ
-from ..packages import six
-from .wait import NoWayToWaitForSocketError, wait_for_read
-
-
-def is_connection_dropped(conn): # Platform-specific
- """
- Returns True if the connection is dropped and should be closed.
-
- :param conn:
- :class:`http.client.HTTPConnection` object.
-
- Note: For platforms like AppEngine, this will always return ``False`` to
- let the platform handle connection recycling transparently for us.
- """
- sock = getattr(conn, "sock", False)
- if sock is False: # Platform-specific: AppEngine
- return False
- if sock is None: # Connection already closed (such as by httplib).
- return True
- try:
- # Returns True if readable, which here means it's been dropped
- return wait_for_read(sock, timeout=0.0)
- except NoWayToWaitForSocketError: # Platform-specific: AppEngine
- return False
-
-
-# This function is copied from socket.py in the Python 2.7 standard
-# library test suite. Added to its signature is only `socket_options`.
-# One additional modification is that we avoid binding to IPv6 servers
-# discovered in DNS if the system doesn't have IPv6 functionality.
-def create_connection(
- address,
- timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
- source_address=None,
- socket_options=None,
-):
- """Connect to *address* and return the socket object.
-
- Convenience function. Connect to *address* (a 2-tuple ``(host,
- port)``) and return the socket object. Passing the optional
- *timeout* parameter will set the timeout on the socket instance
- before attempting to connect. If no *timeout* is supplied, the
- global default timeout setting returned by :func:`socket.getdefaulttimeout`
- is used. If *source_address* is set it must be a tuple of (host, port)
- for the socket to bind as a source address before making the connection.
- An host of '' or port 0 tells the OS to use the default.
- """
-
- host, port = address
- if host.startswith("["):
- host = host.strip("[]")
- err = None
-
- # Using the value from allowed_gai_family() in the context of getaddrinfo lets
- # us select whether to work with IPv4 DNS records, IPv6 records, or both.
- # The original create_connection function always returns all records.
- family = allowed_gai_family()
-
- try:
- host.encode("idna")
- except UnicodeError:
- return six.raise_from(
- LocationParseError(u"'%s', label empty or too long" % host), None
- )
-
- for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
- af, socktype, proto, canonname, sa = res
- sock = None
- try:
- sock = socket.socket(af, socktype, proto)
-
- # If provided, set socket level options before connecting.
- _set_socket_options(sock, socket_options)
-
- if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
- sock.settimeout(timeout)
- if source_address:
- sock.bind(source_address)
- sock.connect(sa)
- return sock
-
- except socket.error as e:
- err = e
- if sock is not None:
- sock.close()
- sock = None
-
- if err is not None:
- raise err
-
- raise socket.error("getaddrinfo returns an empty list")
-
-
-def _set_socket_options(sock, options):
- if options is None:
- return
-
- for opt in options:
- sock.setsockopt(*opt)
-
-
-def allowed_gai_family():
- """This function is designed to work in the context of
- getaddrinfo, where family=socket.AF_UNSPEC is the default and
- will perform a DNS search for both IPv6 and IPv4 records."""
-
- family = socket.AF_INET
- if HAS_IPV6:
- family = socket.AF_UNSPEC
- return family
-
-
-def _has_ipv6(host):
- """Returns True if the system can bind an IPv6 address."""
- sock = None
- has_ipv6 = False
-
- # App Engine doesn't support IPV6 sockets and actually has a quota on the
- # number of sockets that can be used, so just early out here instead of
- # creating a socket needlessly.
- # See https://github.com/urllib3/urllib3/issues/1446
- if _appengine_environ.is_appengine_sandbox():
- return False
-
- if socket.has_ipv6:
- # has_ipv6 returns true if cPython was compiled with IPv6 support.
- # It does not tell us if the system has IPv6 support enabled. To
- # determine that we must bind to an IPv6 address.
- # https://github.com/urllib3/urllib3/pull/611
- # https://bugs.python.org/issue658327
- try:
- sock = socket.socket(socket.AF_INET6)
- sock.bind((host, 0))
- has_ipv6 = True
- except Exception:
- pass
-
- if sock:
- sock.close()
- return has_ipv6
-
-
-HAS_IPV6 = _has_ipv6("::1")
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/proxy.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/proxy.py
deleted file mode 100644
index 34f884d5b3..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/proxy.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from .ssl_ import create_urllib3_context, resolve_cert_reqs, resolve_ssl_version
-
-
-def connection_requires_http_tunnel(
- proxy_url=None, proxy_config=None, destination_scheme=None
-):
- """
- Returns True if the connection requires an HTTP CONNECT through the proxy.
-
- :param URL proxy_url:
- URL of the proxy.
- :param ProxyConfig proxy_config:
- Proxy configuration from poolmanager.py
- :param str destination_scheme:
- The scheme of the destination. (i.e https, http, etc)
- """
- # If we're not using a proxy, no way to use a tunnel.
- if proxy_url is None:
- return False
-
- # HTTP destinations never require tunneling, we always forward.
- if destination_scheme == "http":
- return False
-
- # Support for forwarding with HTTPS proxies and HTTPS destinations.
- if (
- proxy_url.scheme == "https"
- and proxy_config
- and proxy_config.use_forwarding_for_https
- ):
- return False
-
- # Otherwise always use a tunnel.
- return True
-
-
-def create_proxy_ssl_context(
- ssl_version, cert_reqs, ca_certs=None, ca_cert_dir=None, ca_cert_data=None
-):
- """
- Generates a default proxy ssl context if one hasn't been provided by the
- user.
- """
- ssl_context = create_urllib3_context(
- ssl_version=resolve_ssl_version(ssl_version),
- cert_reqs=resolve_cert_reqs(cert_reqs),
- )
- if (
- not ca_certs
- and not ca_cert_dir
- and not ca_cert_data
- and hasattr(ssl_context, "load_default_certs")
- ):
- ssl_context.load_default_certs()
-
- return ssl_context
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/queue.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/queue.py
deleted file mode 100644
index 41784104ee..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/queue.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import collections
-
-from ..packages import six
-from ..packages.six.moves import queue
-
-if six.PY2:
- # Queue is imported for side effects on MS Windows. See issue #229.
- import Queue as _unused_module_Queue # noqa: F401
-
-
-class LifoQueue(queue.Queue):
- def _init(self, _):
- self.queue = collections.deque()
-
- def _qsize(self, len=len):
- return len(self.queue)
-
- def _put(self, item):
- self.queue.append(item)
-
- def _get(self):
- return self.queue.pop()
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/request.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/request.py
deleted file mode 100644
index 25103383ec..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/request.py
+++ /dev/null
@@ -1,143 +0,0 @@
-from __future__ import absolute_import
-
-from base64 import b64encode
-
-from ..exceptions import UnrewindableBodyError
-from ..packages.six import b, integer_types
-
-# Pass as a value within ``headers`` to skip
-# emitting some HTTP headers that are added automatically.
-# The only headers that are supported are ``Accept-Encoding``,
-# ``Host``, and ``User-Agent``.
-SKIP_HEADER = "@@@SKIP_HEADER@@@"
-SKIPPABLE_HEADERS = frozenset(["accept-encoding", "host", "user-agent"])
-
-ACCEPT_ENCODING = "gzip,deflate"
-try:
- import brotli as _unused_module_brotli # noqa: F401
-except ImportError:
- pass
-else:
- ACCEPT_ENCODING += ",br"
-
-_FAILEDTELL = object()
-
-
-def make_headers(
- keep_alive=None,
- accept_encoding=None,
- user_agent=None,
- basic_auth=None,
- proxy_basic_auth=None,
- disable_cache=None,
-):
- """
- Shortcuts for generating request headers.
-
- :param keep_alive:
- If ``True``, adds 'connection: keep-alive' header.
-
- :param accept_encoding:
- Can be a boolean, list, or string.
- ``True`` translates to 'gzip,deflate'.
- List will get joined by comma.
- String will be used as provided.
-
- :param user_agent:
- String representing the user-agent you want, such as
- "python-urllib3/0.6"
-
- :param basic_auth:
- Colon-separated username:password string for 'authorization: basic ...'
- auth header.
-
- :param proxy_basic_auth:
- Colon-separated username:password string for 'proxy-authorization: basic ...'
- auth header.
-
- :param disable_cache:
- If ``True``, adds 'cache-control: no-cache' header.
-
- Example::
-
- >>> make_headers(keep_alive=True, user_agent="Batman/1.0")
- {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'}
- >>> make_headers(accept_encoding=True)
- {'accept-encoding': 'gzip,deflate'}
- """
- headers = {}
- if accept_encoding:
- if isinstance(accept_encoding, str):
- pass
- elif isinstance(accept_encoding, list):
- accept_encoding = ",".join(accept_encoding)
- else:
- accept_encoding = ACCEPT_ENCODING
- headers["accept-encoding"] = accept_encoding
-
- if user_agent:
- headers["user-agent"] = user_agent
-
- if keep_alive:
- headers["connection"] = "keep-alive"
-
- if basic_auth:
- headers["authorization"] = "Basic " + b64encode(b(basic_auth)).decode("utf-8")
-
- if proxy_basic_auth:
- headers["proxy-authorization"] = "Basic " + b64encode(
- b(proxy_basic_auth)
- ).decode("utf-8")
-
- if disable_cache:
- headers["cache-control"] = "no-cache"
-
- return headers
-
-
-def set_file_position(body, pos):
- """
- If a position is provided, move file to that point.
- Otherwise, we'll attempt to record a position for future use.
- """
- if pos is not None:
- rewind_body(body, pos)
- elif getattr(body, "tell", None) is not None:
- try:
- pos = body.tell()
- except (IOError, OSError):
- # This differentiates from None, allowing us to catch
- # a failed `tell()` later when trying to rewind the body.
- pos = _FAILEDTELL
-
- return pos
-
-
-def rewind_body(body, body_pos):
- """
- Attempt to rewind body to a certain position.
- Primarily used for request redirects and retries.
-
- :param body:
- File-like object that supports seek.
-
- :param int pos:
- Position to seek to in file.
- """
- body_seek = getattr(body, "seek", None)
- if body_seek is not None and isinstance(body_pos, integer_types):
- try:
- body_seek(body_pos)
- except (IOError, OSError):
- raise UnrewindableBodyError(
- "An error occurred when rewinding request body for redirect/retry."
- )
- elif body_pos is _FAILEDTELL:
- raise UnrewindableBodyError(
- "Unable to record file position for rewinding "
- "request body during a redirect/retry."
- )
- else:
- raise ValueError(
- "body_pos must be of type integer, instead it was %s." % type(body_pos)
- )
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/response.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/response.py
deleted file mode 100644
index 5ea609cced..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/response.py
+++ /dev/null
@@ -1,107 +0,0 @@
-from __future__ import absolute_import
-
-from email.errors import MultipartInvariantViolationDefect, StartBoundaryNotFoundDefect
-
-from ..exceptions import HeaderParsingError
-from ..packages.six.moves import http_client as httplib
-
-
-def is_fp_closed(obj):
- """
- Checks whether a given file-like object is closed.
-
- :param obj:
- The file-like object to check.
- """
-
- try:
- # Check `isclosed()` first, in case Python3 doesn't set `closed`.
- # GH Issue #928
- return obj.isclosed()
- except AttributeError:
- pass
-
- try:
- # Check via the official file-like-object way.
- return obj.closed
- except AttributeError:
- pass
-
- try:
- # Check if the object is a container for another file-like object that
- # gets released on exhaustion (e.g. HTTPResponse).
- return obj.fp is None
- except AttributeError:
- pass
-
- raise ValueError("Unable to determine whether fp is closed.")
-
-
-def assert_header_parsing(headers):
- """
- Asserts whether all headers have been successfully parsed.
- Extracts encountered errors from the result of parsing headers.
-
- Only works on Python 3.
-
- :param http.client.HTTPMessage headers: Headers to verify.
-
- :raises urllib3.exceptions.HeaderParsingError:
- If parsing errors are found.
- """
-
- # This will fail silently if we pass in the wrong kind of parameter.
- # To make debugging easier add an explicit check.
- if not isinstance(headers, httplib.HTTPMessage):
- raise TypeError("expected httplib.Message, got {0}.".format(type(headers)))
-
- defects = getattr(headers, "defects", None)
- get_payload = getattr(headers, "get_payload", None)
-
- unparsed_data = None
- if get_payload:
- # get_payload is actually email.message.Message.get_payload;
- # we're only interested in the result if it's not a multipart message
- if not headers.is_multipart():
- payload = get_payload()
-
- if isinstance(payload, (bytes, str)):
- unparsed_data = payload
- if defects:
- # httplib is assuming a response body is available
- # when parsing headers even when httplib only sends
- # header data to parse_headers() This results in
- # defects on multipart responses in particular.
- # See: https://github.com/urllib3/urllib3/issues/800
-
- # So we ignore the following defects:
- # - StartBoundaryNotFoundDefect:
- # The claimed start boundary was never found.
- # - MultipartInvariantViolationDefect:
- # A message claimed to be a multipart but no subparts were found.
- defects = [
- defect
- for defect in defects
- if not isinstance(
- defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect)
- )
- ]
-
- if defects or unparsed_data:
- raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data)
-
-
-def is_response_to_head(response):
- """
- Checks whether the request of a response has been a HEAD-request.
- Handles the quirks of AppEngine.
-
- :param http.client.HTTPResponse response:
- Response to check if the originating request
- used 'HEAD' as a method.
- """
- # FIXME: Can we do this somehow without accessing private httplib _method?
- method = response._method
- if isinstance(method, int): # Platform-specific: Appengine
- return method == 3
- return method.upper() == "HEAD"
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/retry.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/retry.py
deleted file mode 100644
index c7dc42f1d6..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/retry.py
+++ /dev/null
@@ -1,602 +0,0 @@
-from __future__ import absolute_import
-
-import email
-import logging
-import re
-import time
-import warnings
-from collections import namedtuple
-from itertools import takewhile
-
-from ..exceptions import (
- ConnectTimeoutError,
- InvalidHeader,
- MaxRetryError,
- ProtocolError,
- ProxyError,
- ReadTimeoutError,
- ResponseError,
-)
-from ..packages import six
-
-log = logging.getLogger(__name__)
-
-
-# Data structure for representing the metadata of requests that result in a retry.
-RequestHistory = namedtuple(
- "RequestHistory", ["method", "url", "error", "status", "redirect_location"]
-)
-
-
-# TODO: In v2 we can remove this sentinel and metaclass with deprecated options.
-_Default = object()
-
-
-class _RetryMeta(type):
- @property
- def DEFAULT_METHOD_WHITELIST(cls):
- warnings.warn(
- "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and "
- "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead",
- DeprecationWarning,
- )
- return cls.DEFAULT_ALLOWED_METHODS
-
- @DEFAULT_METHOD_WHITELIST.setter
- def DEFAULT_METHOD_WHITELIST(cls, value):
- warnings.warn(
- "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and "
- "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead",
- DeprecationWarning,
- )
- cls.DEFAULT_ALLOWED_METHODS = value
-
- @property
- def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls):
- warnings.warn(
- "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and "
- "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead",
- DeprecationWarning,
- )
- return cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT
-
- @DEFAULT_REDIRECT_HEADERS_BLACKLIST.setter
- def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls, value):
- warnings.warn(
- "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and "
- "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead",
- DeprecationWarning,
- )
- cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT = value
-
-
-@six.add_metaclass(_RetryMeta)
-class Retry(object):
- """Retry configuration.
-
- Each retry attempt will create a new Retry object with updated values, so
- they can be safely reused.
-
- Retries can be defined as a default for a pool::
-
- retries = Retry(connect=5, read=2, redirect=5)
- http = PoolManager(retries=retries)
- response = http.request('GET', 'http://example.com/')
-
- Or per-request (which overrides the default for the pool)::
-
- response = http.request('GET', 'http://example.com/', retries=Retry(10))
-
- Retries can be disabled by passing ``False``::
-
- response = http.request('GET', 'http://example.com/', retries=False)
-
- Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless
- retries are disabled, in which case the causing exception will be raised.
-
- :param int total:
- Total number of retries to allow. Takes precedence over other counts.
-
- Set to ``None`` to remove this constraint and fall back on other
- counts.
-
- Set to ``0`` to fail on the first retry.
-
- Set to ``False`` to disable and imply ``raise_on_redirect=False``.
-
- :param int connect:
- How many connection-related errors to retry on.
-
- These are errors raised before the request is sent to the remote server,
- which we assume has not triggered the server to process the request.
-
- Set to ``0`` to fail on the first retry of this type.
-
- :param int read:
- How many times to retry on read errors.
-
- These errors are raised after the request was sent to the server, so the
- request may have side-effects.
-
- Set to ``0`` to fail on the first retry of this type.
-
- :param int redirect:
- How many redirects to perform. Limit this to avoid infinite redirect
- loops.
-
- A redirect is a HTTP response with a status code 301, 302, 303, 307 or
- 308.
-
- Set to ``0`` to fail on the first retry of this type.
-
- Set to ``False`` to disable and imply ``raise_on_redirect=False``.
-
- :param int status:
- How many times to retry on bad status codes.
-
- These are retries made on responses, where status code matches
- ``status_forcelist``.
-
- Set to ``0`` to fail on the first retry of this type.
-
- :param int other:
- How many times to retry on other errors.
-
- Other errors are errors that are not connect, read, redirect or status errors.
- These errors might be raised after the request was sent to the server, so the
- request might have side-effects.
-
- Set to ``0`` to fail on the first retry of this type.
-
- If ``total`` is not set, it's a good idea to set this to 0 to account
- for unexpected edge cases and avoid infinite retry loops.
-
- :param iterable allowed_methods:
- Set of uppercased HTTP method verbs that we should retry on.
-
- By default, we only retry on methods which are considered to be
- idempotent (multiple requests with the same parameters end with the
- same state). See :attr:`Retry.DEFAULT_ALLOWED_METHODS`.
-
- Set to a ``False`` value to retry on any verb.
-
- .. warning::
-
- Previously this parameter was named ``method_whitelist``, that
- usage is deprecated in v1.26.0 and will be removed in v2.0.
-
- :param iterable status_forcelist:
- A set of integer HTTP status codes that we should force a retry on.
- A retry is initiated if the request method is in ``allowed_methods``
- and the response status code is in ``status_forcelist``.
-
- By default, this is disabled with ``None``.
-
- :param float backoff_factor:
- A backoff factor to apply between attempts after the second try
- (most errors are resolved immediately by a second try without a
- delay). urllib3 will sleep for::
-
- {backoff factor} * (2 ** ({number of total retries} - 1))
-
- seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep
- for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer
- than :attr:`Retry.BACKOFF_MAX`.
-
- By default, backoff is disabled (set to 0).
-
- :param bool raise_on_redirect: Whether, if the number of redirects is
- exhausted, to raise a MaxRetryError, or to return a response with a
- response code in the 3xx range.
-
- :param bool raise_on_status: Similar meaning to ``raise_on_redirect``:
- whether we should raise an exception, or return a response,
- if status falls in ``status_forcelist`` range and retries have
- been exhausted.
-
- :param tuple history: The history of the request encountered during
- each call to :meth:`~Retry.increment`. The list is in the order
- the requests occurred. Each list item is of class :class:`RequestHistory`.
-
- :param bool respect_retry_after_header:
- Whether to respect Retry-After header on status codes defined as
- :attr:`Retry.RETRY_AFTER_STATUS_CODES` or not.
-
- :param iterable remove_headers_on_redirect:
- Sequence of headers to remove from the request when a response
- indicating a redirect is returned before firing off the redirected
- request.
- """
-
- #: Default methods to be used for ``allowed_methods``
- DEFAULT_ALLOWED_METHODS = frozenset(
- ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"]
- )
-
- #: Default status codes to be used for ``status_forcelist``
- RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
-
- #: Default headers to be used for ``remove_headers_on_redirect``
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Authorization"])
-
- #: Maximum backoff time.
- BACKOFF_MAX = 120
-
- def __init__(
- self,
- total=10,
- connect=None,
- read=None,
- redirect=None,
- status=None,
- other=None,
- allowed_methods=_Default,
- status_forcelist=None,
- backoff_factor=0,
- raise_on_redirect=True,
- raise_on_status=True,
- history=None,
- respect_retry_after_header=True,
- remove_headers_on_redirect=_Default,
- # TODO: Deprecated, remove in v2.0
- method_whitelist=_Default,
- ):
-
- if method_whitelist is not _Default:
- if allowed_methods is not _Default:
- raise ValueError(
- "Using both 'allowed_methods' and "
- "'method_whitelist' together is not allowed. "
- "Instead only use 'allowed_methods'"
- )
- warnings.warn(
- "Using 'method_whitelist' with Retry is deprecated and "
- "will be removed in v2.0. Use 'allowed_methods' instead",
- DeprecationWarning,
- stacklevel=2,
- )
- allowed_methods = method_whitelist
- if allowed_methods is _Default:
- allowed_methods = self.DEFAULT_ALLOWED_METHODS
- if remove_headers_on_redirect is _Default:
- remove_headers_on_redirect = self.DEFAULT_REMOVE_HEADERS_ON_REDIRECT
-
- self.total = total
- self.connect = connect
- self.read = read
- self.status = status
- self.other = other
-
- if redirect is False or total is False:
- redirect = 0
- raise_on_redirect = False
-
- self.redirect = redirect
- self.status_forcelist = status_forcelist or set()
- self.allowed_methods = allowed_methods
- self.backoff_factor = backoff_factor
- self.raise_on_redirect = raise_on_redirect
- self.raise_on_status = raise_on_status
- self.history = history or tuple()
- self.respect_retry_after_header = respect_retry_after_header
- self.remove_headers_on_redirect = frozenset(
- [h.lower() for h in remove_headers_on_redirect]
- )
-
- def new(self, **kw):
- params = dict(
- total=self.total,
- connect=self.connect,
- read=self.read,
- redirect=self.redirect,
- status=self.status,
- other=self.other,
- status_forcelist=self.status_forcelist,
- backoff_factor=self.backoff_factor,
- raise_on_redirect=self.raise_on_redirect,
- raise_on_status=self.raise_on_status,
- history=self.history,
- remove_headers_on_redirect=self.remove_headers_on_redirect,
- respect_retry_after_header=self.respect_retry_after_header,
- )
-
- # TODO: If already given in **kw we use what's given to us
- # If not given we need to figure out what to pass. We decide
- # based on whether our class has the 'method_whitelist' property
- # and if so we pass the deprecated 'method_whitelist' otherwise
- # we use 'allowed_methods'. Remove in v2.0
- if "method_whitelist" not in kw and "allowed_methods" not in kw:
- if "method_whitelist" in self.__dict__:
- warnings.warn(
- "Using 'method_whitelist' with Retry is deprecated and "
- "will be removed in v2.0. Use 'allowed_methods' instead",
- DeprecationWarning,
- )
- params["method_whitelist"] = self.allowed_methods
- else:
- params["allowed_methods"] = self.allowed_methods
-
- params.update(kw)
- return type(self)(**params)
-
- @classmethod
- def from_int(cls, retries, redirect=True, default=None):
- """Backwards-compatibility for the old retries format."""
- if retries is None:
- retries = default if default is not None else cls.DEFAULT
-
- if isinstance(retries, Retry):
- return retries
-
- redirect = bool(redirect) and None
- new_retries = cls(retries, redirect=redirect)
- log.debug("Converted retries value: %r -> %r", retries, new_retries)
- return new_retries
-
- def get_backoff_time(self):
- """Formula for computing the current backoff
-
- :rtype: float
- """
- # We want to consider only the last consecutive errors sequence (Ignore redirects).
- consecutive_errors_len = len(
- list(
- takewhile(lambda x: x.redirect_location is None, reversed(self.history))
- )
- )
- if consecutive_errors_len <= 1:
- return 0
-
- backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1))
- return min(self.BACKOFF_MAX, backoff_value)
-
- def parse_retry_after(self, retry_after):
- # Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4
- if re.match(r"^\s*[0-9]+\s*$", retry_after):
- seconds = int(retry_after)
- else:
- retry_date_tuple = email.utils.parsedate_tz(retry_after)
- if retry_date_tuple is None:
- raise InvalidHeader("Invalid Retry-After header: %s" % retry_after)
- if retry_date_tuple[9] is None: # Python 2
- # Assume UTC if no timezone was specified
- # On Python2.7, parsedate_tz returns None for a timezone offset
- # instead of 0 if no timezone is given, where mktime_tz treats
- # a None timezone offset as local time.
- retry_date_tuple = retry_date_tuple[:9] + (0,) + retry_date_tuple[10:]
-
- retry_date = email.utils.mktime_tz(retry_date_tuple)
- seconds = retry_date - time.time()
-
- if seconds < 0:
- seconds = 0
-
- return seconds
-
- def get_retry_after(self, response):
- """Get the value of Retry-After in seconds."""
-
- retry_after = response.getheader("Retry-After")
-
- if retry_after is None:
- return None
-
- return self.parse_retry_after(retry_after)
-
- def sleep_for_retry(self, response=None):
- retry_after = self.get_retry_after(response)
- if retry_after:
- time.sleep(retry_after)
- return True
-
- return False
-
- def _sleep_backoff(self):
- backoff = self.get_backoff_time()
- if backoff <= 0:
- return
- time.sleep(backoff)
-
- def sleep(self, response=None):
- """Sleep between retry attempts.
-
- This method will respect a server's ``Retry-After`` response header
- and sleep the duration of the time requested. If that is not present, it
- will use an exponential backoff. By default, the backoff factor is 0 and
- this method will return immediately.
- """
-
- if self.respect_retry_after_header and response:
- slept = self.sleep_for_retry(response)
- if slept:
- return
-
- self._sleep_backoff()
-
- def _is_connection_error(self, err):
- """Errors when we're fairly sure that the server did not receive the
- request, so it should be safe to retry.
- """
- if isinstance(err, ProxyError):
- err = err.original_error
- return isinstance(err, ConnectTimeoutError)
-
- def _is_read_error(self, err):
- """Errors that occur after the request has been started, so we should
- assume that the server began processing it.
- """
- return isinstance(err, (ReadTimeoutError, ProtocolError))
-
- def _is_method_retryable(self, method):
- """Checks if a given HTTP method should be retried upon, depending if
- it is included in the allowed_methods
- """
- # TODO: For now favor if the Retry implementation sets its own method_whitelist
- # property outside of our constructor to avoid breaking custom implementations.
- if "method_whitelist" in self.__dict__:
- warnings.warn(
- "Using 'method_whitelist' with Retry is deprecated and "
- "will be removed in v2.0. Use 'allowed_methods' instead",
- DeprecationWarning,
- )
- allowed_methods = self.method_whitelist
- else:
- allowed_methods = self.allowed_methods
-
- if allowed_methods and method.upper() not in allowed_methods:
- return False
- return True
-
- def is_retry(self, method, status_code, has_retry_after=False):
- """Is this method/status code retryable? (Based on allowlists and control
- variables such as the number of total retries to allow, whether to
- respect the Retry-After header, whether this header is present, and
- whether the returned status code is on the list of status codes to
- be retried upon on the presence of the aforementioned header)
- """
- if not self._is_method_retryable(method):
- return False
-
- if self.status_forcelist and status_code in self.status_forcelist:
- return True
-
- return (
- self.total
- and self.respect_retry_after_header
- and has_retry_after
- and (status_code in self.RETRY_AFTER_STATUS_CODES)
- )
-
- def is_exhausted(self):
- """Are we out of retries?"""
- retry_counts = (
- self.total,
- self.connect,
- self.read,
- self.redirect,
- self.status,
- self.other,
- )
- retry_counts = list(filter(None, retry_counts))
- if not retry_counts:
- return False
-
- return min(retry_counts) < 0
-
- def increment(
- self,
- method=None,
- url=None,
- response=None,
- error=None,
- _pool=None,
- _stacktrace=None,
- ):
- """Return a new Retry object with incremented retry counters.
-
- :param response: A response object, or None, if the server did not
- return a response.
- :type response: :class:`~urllib3.response.HTTPResponse`
- :param Exception error: An error encountered during the request, or
- None if the response was received successfully.
-
- :return: A new ``Retry`` object.
- """
- if self.total is False and error:
- # Disabled, indicate to re-raise the error.
- raise six.reraise(type(error), error, _stacktrace)
-
- total = self.total
- if total is not None:
- total -= 1
-
- connect = self.connect
- read = self.read
- redirect = self.redirect
- status_count = self.status
- other = self.other
- cause = "unknown"
- status = None
- redirect_location = None
-
- if error and self._is_connection_error(error):
- # Connect retry?
- if connect is False:
- raise six.reraise(type(error), error, _stacktrace)
- elif connect is not None:
- connect -= 1
-
- elif error and self._is_read_error(error):
- # Read retry?
- if read is False or not self._is_method_retryable(method):
- raise six.reraise(type(error), error, _stacktrace)
- elif read is not None:
- read -= 1
-
- elif error:
- # Other retry?
- if other is not None:
- other -= 1
-
- elif response and response.get_redirect_location():
- # Redirect retry?
- if redirect is not None:
- redirect -= 1
- cause = "too many redirects"
- redirect_location = response.get_redirect_location()
- status = response.status
-
- else:
- # Incrementing because of a server error like a 500 in
- # status_forcelist and the given method is in the allowed_methods
- cause = ResponseError.GENERIC_ERROR
- if response and response.status:
- if status_count is not None:
- status_count -= 1
- cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)
- status = response.status
-
- history = self.history + (
- RequestHistory(method, url, error, status, redirect_location),
- )
-
- new_retry = self.new(
- total=total,
- connect=connect,
- read=read,
- redirect=redirect,
- status=status_count,
- other=other,
- history=history,
- )
-
- if new_retry.is_exhausted():
- raise MaxRetryError(_pool, url, error or ResponseError(cause))
-
- log.debug("Incremented Retry for (url='%s'): %r", url, new_retry)
-
- return new_retry
-
- def __repr__(self):
- return (
- "{cls.__name__}(total={self.total}, connect={self.connect}, "
- "read={self.read}, redirect={self.redirect}, status={self.status})"
- ).format(cls=type(self), self=self)
-
- def __getattr__(self, item):
- if item == "method_whitelist":
- # TODO: Remove this deprecated alias in v2.0
- warnings.warn(
- "Using 'method_whitelist' with Retry is deprecated and "
- "will be removed in v2.0. Use 'allowed_methods' instead",
- DeprecationWarning,
- )
- return self.allowed_methods
- try:
- return getattr(super(Retry, self), item)
- except AttributeError:
- return getattr(Retry, item)
-
-
-# For backwards compatibility (equivalent to pre-v1.9):
-Retry.DEFAULT = Retry(3)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/ssl_.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/ssl_.py
deleted file mode 100644
index 8f867812a5..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/ssl_.py
+++ /dev/null
@@ -1,495 +0,0 @@
-from __future__ import absolute_import
-
-import hmac
-import os
-import sys
-import warnings
-from binascii import hexlify, unhexlify
-from hashlib import md5, sha1, sha256
-
-from ..exceptions import (
- InsecurePlatformWarning,
- ProxySchemeUnsupported,
- SNIMissingWarning,
- SSLError,
-)
-from ..packages import six
-from .url import BRACELESS_IPV6_ADDRZ_RE, IPV4_RE
-
-SSLContext = None
-SSLTransport = None
-HAS_SNI = False
-IS_PYOPENSSL = False
-IS_SECURETRANSPORT = False
-ALPN_PROTOCOLS = ["http/1.1"]
-
-# Maps the length of a digest to a possible hash function producing this digest
-HASHFUNC_MAP = {32: md5, 40: sha1, 64: sha256}
-
-
-def _const_compare_digest_backport(a, b):
- """
- Compare two digests of equal length in constant time.
-
- The digests must be of type str/bytes.
- Returns True if the digests match, and False otherwise.
- """
- result = abs(len(a) - len(b))
- for left, right in zip(bytearray(a), bytearray(b)):
- result |= left ^ right
- return result == 0
-
-
-_const_compare_digest = getattr(hmac, "compare_digest", _const_compare_digest_backport)
-
-try: # Test for SSL features
- import ssl
- from ssl import CERT_REQUIRED, wrap_socket
-except ImportError:
- pass
-
-try:
- from ssl import HAS_SNI # Has SNI?
-except ImportError:
- pass
-
-try:
- from .ssltransport import SSLTransport
-except ImportError:
- pass
-
-
-try: # Platform-specific: Python 3.6
- from ssl import PROTOCOL_TLS
-
- PROTOCOL_SSLv23 = PROTOCOL_TLS
-except ImportError:
- try:
- from ssl import PROTOCOL_SSLv23 as PROTOCOL_TLS
-
- PROTOCOL_SSLv23 = PROTOCOL_TLS
- except ImportError:
- PROTOCOL_SSLv23 = PROTOCOL_TLS = 2
-
-try:
- from ssl import PROTOCOL_TLS_CLIENT
-except ImportError:
- PROTOCOL_TLS_CLIENT = PROTOCOL_TLS
-
-
-try:
- from ssl import OP_NO_COMPRESSION, OP_NO_SSLv2, OP_NO_SSLv3
-except ImportError:
- OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000
- OP_NO_COMPRESSION = 0x20000
-
-
-try: # OP_NO_TICKET was added in Python 3.6
- from ssl import OP_NO_TICKET
-except ImportError:
- OP_NO_TICKET = 0x4000
-
-
-# A secure default.
-# Sources for more information on TLS ciphers:
-#
-# - https://wiki.mozilla.org/Security/Server_Side_TLS
-# - https://www.ssllabs.com/projects/best-practices/index.html
-# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
-#
-# The general intent is:
-# - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE),
-# - prefer ECDHE over DHE for better performance,
-# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and
-# security,
-# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common,
-# - disable NULL authentication, MD5 MACs, DSS, and other
-# insecure ciphers for security reasons.
-# - NOTE: TLS 1.3 cipher suites are managed through a different interface
-# not exposed by CPython (yet!) and are enabled by default if they're available.
-DEFAULT_CIPHERS = ":".join(
- [
- "ECDHE+AESGCM",
- "ECDHE+CHACHA20",
- "DHE+AESGCM",
- "DHE+CHACHA20",
- "ECDH+AESGCM",
- "DH+AESGCM",
- "ECDH+AES",
- "DH+AES",
- "RSA+AESGCM",
- "RSA+AES",
- "!aNULL",
- "!eNULL",
- "!MD5",
- "!DSS",
- ]
-)
-
-try:
- from ssl import SSLContext # Modern SSL?
-except ImportError:
-
- class SSLContext(object): # Platform-specific: Python 2
- def __init__(self, protocol_version):
- self.protocol = protocol_version
- # Use default values from a real SSLContext
- self.check_hostname = False
- self.verify_mode = ssl.CERT_NONE
- self.ca_certs = None
- self.options = 0
- self.certfile = None
- self.keyfile = None
- self.ciphers = None
-
- def load_cert_chain(self, certfile, keyfile):
- self.certfile = certfile
- self.keyfile = keyfile
-
- def load_verify_locations(self, cafile=None, capath=None, cadata=None):
- self.ca_certs = cafile
-
- if capath is not None:
- raise SSLError("CA directories not supported in older Pythons")
-
- if cadata is not None:
- raise SSLError("CA data not supported in older Pythons")
-
- def set_ciphers(self, cipher_suite):
- self.ciphers = cipher_suite
-
- def wrap_socket(self, socket, server_hostname=None, server_side=False):
- warnings.warn(
- "A true SSLContext object is not available. This prevents "
- "urllib3 from configuring SSL appropriately and may cause "
- "certain SSL connections to fail. You can upgrade to a newer "
- "version of Python to solve this. For more information, see "
- "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html"
- "#ssl-warnings",
- InsecurePlatformWarning,
- )
- kwargs = {
- "keyfile": self.keyfile,
- "certfile": self.certfile,
- "ca_certs": self.ca_certs,
- "cert_reqs": self.verify_mode,
- "ssl_version": self.protocol,
- "server_side": server_side,
- }
- return wrap_socket(socket, ciphers=self.ciphers, **kwargs)
-
-
-def assert_fingerprint(cert, fingerprint):
- """
- Checks if given fingerprint matches the supplied certificate.
-
- :param cert:
- Certificate as bytes object.
- :param fingerprint:
- Fingerprint as string of hexdigits, can be interspersed by colons.
- """
-
- fingerprint = fingerprint.replace(":", "").lower()
- digest_length = len(fingerprint)
- hashfunc = HASHFUNC_MAP.get(digest_length)
- if not hashfunc:
- raise SSLError("Fingerprint of invalid length: {0}".format(fingerprint))
-
- # We need encode() here for py32; works on py2 and p33.
- fingerprint_bytes = unhexlify(fingerprint.encode())
-
- cert_digest = hashfunc(cert).digest()
-
- if not _const_compare_digest(cert_digest, fingerprint_bytes):
- raise SSLError(
- 'Fingerprints did not match. Expected "{0}", got "{1}".'.format(
- fingerprint, hexlify(cert_digest)
- )
- )
-
-
-def resolve_cert_reqs(candidate):
- """
- Resolves the argument to a numeric constant, which can be passed to
- the wrap_socket function/method from the ssl module.
- Defaults to :data:`ssl.CERT_REQUIRED`.
- If given a string it is assumed to be the name of the constant in the
- :mod:`ssl` module or its abbreviation.
- (So you can specify `REQUIRED` instead of `CERT_REQUIRED`.
- If it's neither `None` nor a string we assume it is already the numeric
- constant which can directly be passed to wrap_socket.
- """
- if candidate is None:
- return CERT_REQUIRED
-
- if isinstance(candidate, str):
- res = getattr(ssl, candidate, None)
- if res is None:
- res = getattr(ssl, "CERT_" + candidate)
- return res
-
- return candidate
-
-
-def resolve_ssl_version(candidate):
- """
- like resolve_cert_reqs
- """
- if candidate is None:
- return PROTOCOL_TLS
-
- if isinstance(candidate, str):
- res = getattr(ssl, candidate, None)
- if res is None:
- res = getattr(ssl, "PROTOCOL_" + candidate)
- return res
-
- return candidate
-
-
-def create_urllib3_context(
- ssl_version=None, cert_reqs=None, options=None, ciphers=None
-):
- """All arguments have the same meaning as ``ssl_wrap_socket``.
-
- By default, this function does a lot of the same work that
- ``ssl.create_default_context`` does on Python 3.4+. It:
-
- - Disables SSLv2, SSLv3, and compression
- - Sets a restricted set of server ciphers
-
- If you wish to enable SSLv3, you can do::
-
- from urllib3.util import ssl_
- context = ssl_.create_urllib3_context()
- context.options &= ~ssl_.OP_NO_SSLv3
-
- You can do the same to enable compression (substituting ``COMPRESSION``
- for ``SSLv3`` in the last line above).
-
- :param ssl_version:
- The desired protocol version to use. This will default to
- PROTOCOL_SSLv23 which will negotiate the highest protocol that both
- the server and your installation of OpenSSL support.
- :param cert_reqs:
- Whether to require the certificate verification. This defaults to
- ``ssl.CERT_REQUIRED``.
- :param options:
- Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``,
- ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``.
- :param ciphers:
- Which cipher suites to allow the server to select.
- :returns:
- Constructed SSLContext object with specified options
- :rtype: SSLContext
- """
- # PROTOCOL_TLS is deprecated in Python 3.10
- if not ssl_version or ssl_version == PROTOCOL_TLS:
- ssl_version = PROTOCOL_TLS_CLIENT
-
- context = SSLContext(ssl_version)
-
- context.set_ciphers(ciphers or DEFAULT_CIPHERS)
-
- # Setting the default here, as we may have no ssl module on import
- cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs
-
- if options is None:
- options = 0
- # SSLv2 is easily broken and is considered harmful and dangerous
- options |= OP_NO_SSLv2
- # SSLv3 has several problems and is now dangerous
- options |= OP_NO_SSLv3
- # Disable compression to prevent CRIME attacks for OpenSSL 1.0+
- # (issue #309)
- options |= OP_NO_COMPRESSION
- # TLSv1.2 only. Unless set explicitly, do not request tickets.
- # This may save some bandwidth on wire, and although the ticket is encrypted,
- # there is a risk associated with it being on wire,
- # if the server is not rotating its ticketing keys properly.
- options |= OP_NO_TICKET
-
- context.options |= options
-
- # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is
- # necessary for conditional client cert authentication with TLS 1.3.
- # The attribute is None for OpenSSL <= 1.1.0 or does not exist in older
- # versions of Python. We only enable on Python 3.7.4+ or if certificate
- # verification is enabled to work around Python issue #37428
- # See: https://bugs.python.org/issue37428
- if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr(
- context, "post_handshake_auth", None
- ) is not None:
- context.post_handshake_auth = True
-
- def disable_check_hostname():
- if (
- getattr(context, "check_hostname", None) is not None
- ): # Platform-specific: Python 3.2
- # We do our own verification, including fingerprints and alternative
- # hostnames. So disable it here
- context.check_hostname = False
-
- # The order of the below lines setting verify_mode and check_hostname
- # matter due to safe-guards SSLContext has to prevent an SSLContext with
- # check_hostname=True, verify_mode=NONE/OPTIONAL. This is made even more
- # complex because we don't know whether PROTOCOL_TLS_CLIENT will be used
- # or not so we don't know the initial state of the freshly created SSLContext.
- if cert_reqs == ssl.CERT_REQUIRED:
- context.verify_mode = cert_reqs
- disable_check_hostname()
- else:
- disable_check_hostname()
- context.verify_mode = cert_reqs
-
- # Enable logging of TLS session keys via defacto standard environment variable
- # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values.
- if hasattr(context, "keylog_filename"):
- sslkeylogfile = os.environ.get("SSLKEYLOGFILE")
- if sslkeylogfile:
- context.keylog_filename = sslkeylogfile
-
- return context
-
-
-def ssl_wrap_socket(
- sock,
- keyfile=None,
- certfile=None,
- cert_reqs=None,
- ca_certs=None,
- server_hostname=None,
- ssl_version=None,
- ciphers=None,
- ssl_context=None,
- ca_cert_dir=None,
- key_password=None,
- ca_cert_data=None,
- tls_in_tls=False,
-):
- """
- All arguments except for server_hostname, ssl_context, and ca_cert_dir have
- the same meaning as they do when using :func:`ssl.wrap_socket`.
-
- :param server_hostname:
- When SNI is supported, the expected hostname of the certificate
- :param ssl_context:
- A pre-made :class:`SSLContext` object. If none is provided, one will
- be created using :func:`create_urllib3_context`.
- :param ciphers:
- A string of ciphers we wish the client to support.
- :param ca_cert_dir:
- A directory containing CA certificates in multiple separate files, as
- supported by OpenSSL's -CApath flag or the capath argument to
- SSLContext.load_verify_locations().
- :param key_password:
- Optional password if the keyfile is encrypted.
- :param ca_cert_data:
- Optional string containing CA certificates in PEM format suitable for
- passing as the cadata parameter to SSLContext.load_verify_locations()
- :param tls_in_tls:
- Use SSLTransport to wrap the existing socket.
- """
- context = ssl_context
- if context is None:
- # Note: This branch of code and all the variables in it are no longer
- # used by urllib3 itself. We should consider deprecating and removing
- # this code.
- context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers)
-
- if ca_certs or ca_cert_dir or ca_cert_data:
- try:
- context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data)
- except (IOError, OSError) as e:
- raise SSLError(e)
-
- elif ssl_context is None and hasattr(context, "load_default_certs"):
- # try to load OS default certs; works well on Windows (require Python3.4+)
- context.load_default_certs()
-
- # Attempt to detect if we get the goofy behavior of the
- # keyfile being encrypted and OpenSSL asking for the
- # passphrase via the terminal and instead error out.
- if keyfile and key_password is None and _is_key_file_encrypted(keyfile):
- raise SSLError("Client private key is encrypted, password is required")
-
- if certfile:
- if key_password is None:
- context.load_cert_chain(certfile, keyfile)
- else:
- context.load_cert_chain(certfile, keyfile, key_password)
-
- try:
- if hasattr(context, "set_alpn_protocols"):
- context.set_alpn_protocols(ALPN_PROTOCOLS)
- except NotImplementedError: # Defensive: in CI, we always have set_alpn_protocols
- pass
-
- # If we detect server_hostname is an IP address then the SNI
- # extension should not be used according to RFC3546 Section 3.1
- use_sni_hostname = server_hostname and not is_ipaddress(server_hostname)
- # SecureTransport uses server_hostname in certificate verification.
- send_sni = (use_sni_hostname and HAS_SNI) or (
- IS_SECURETRANSPORT and server_hostname
- )
- # Do not warn the user if server_hostname is an invalid SNI hostname.
- if not HAS_SNI and use_sni_hostname:
- warnings.warn(
- "An HTTPS request has been made, but the SNI (Server Name "
- "Indication) extension to TLS is not available on this platform. "
- "This may cause the server to present an incorrect TLS "
- "certificate, which can cause validation failures. You can upgrade to "
- "a newer version of Python to solve this. For more information, see "
- "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html"
- "#ssl-warnings",
- SNIMissingWarning,
- )
-
- if send_sni:
- ssl_sock = _ssl_wrap_socket_impl(
- sock, context, tls_in_tls, server_hostname=server_hostname
- )
- else:
- ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls)
- return ssl_sock
-
-
-def is_ipaddress(hostname):
- """Detects whether the hostname given is an IPv4 or IPv6 address.
- Also detects IPv6 addresses with Zone IDs.
-
- :param str hostname: Hostname to examine.
- :return: True if the hostname is an IP address, False otherwise.
- """
- if not six.PY2 and isinstance(hostname, bytes):
- # IDN A-label bytes are ASCII compatible.
- hostname = hostname.decode("ascii")
- return bool(IPV4_RE.match(hostname) or BRACELESS_IPV6_ADDRZ_RE.match(hostname))
-
-
-def _is_key_file_encrypted(key_file):
- """Detects if a key file is encrypted or not."""
- with open(key_file, "r") as f:
- for line in f:
- # Look for Proc-Type: 4,ENCRYPTED
- if "ENCRYPTED" in line:
- return True
-
- return False
-
-
-def _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname=None):
- if tls_in_tls:
- if not SSLTransport:
- # Import error, ssl is not available.
- raise ProxySchemeUnsupported(
- "TLS in TLS requires support for the 'ssl' module"
- )
-
- SSLTransport._validate_ssl_context_for_tls_in_tls(ssl_context)
- return SSLTransport(sock, ssl_context, server_hostname)
-
- if server_hostname:
- return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
- else:
- return ssl_context.wrap_socket(sock)
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/ssltransport.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/ssltransport.py
deleted file mode 100644
index c2186bced9..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/ssltransport.py
+++ /dev/null
@@ -1,221 +0,0 @@
-import io
-import socket
-import ssl
-
-from urllib3.exceptions import ProxySchemeUnsupported
-from urllib3.packages import six
-
-SSL_BLOCKSIZE = 16384
-
-
-class SSLTransport:
- """
- The SSLTransport wraps an existing socket and establishes an SSL connection.
-
- Contrary to Python's implementation of SSLSocket, it allows you to chain
- multiple TLS connections together. It's particularly useful if you need to
- implement TLS within TLS.
-
- The class supports most of the socket API operations.
- """
-
- @staticmethod
- def _validate_ssl_context_for_tls_in_tls(ssl_context):
- """
- Raises a ProxySchemeUnsupported if the provided ssl_context can't be used
- for TLS in TLS.
-
- The only requirement is that the ssl_context provides the 'wrap_bio'
- methods.
- """
-
- if not hasattr(ssl_context, "wrap_bio"):
- if six.PY2:
- raise ProxySchemeUnsupported(
- "TLS in TLS requires SSLContext.wrap_bio() which isn't "
- "supported on Python 2"
- )
- else:
- raise ProxySchemeUnsupported(
- "TLS in TLS requires SSLContext.wrap_bio() which isn't "
- "available on non-native SSLContext"
- )
-
- def __init__(
- self, socket, ssl_context, server_hostname=None, suppress_ragged_eofs=True
- ):
- """
- Create an SSLTransport around socket using the provided ssl_context.
- """
- self.incoming = ssl.MemoryBIO()
- self.outgoing = ssl.MemoryBIO()
-
- self.suppress_ragged_eofs = suppress_ragged_eofs
- self.socket = socket
-
- self.sslobj = ssl_context.wrap_bio(
- self.incoming, self.outgoing, server_hostname=server_hostname
- )
-
- # Perform initial handshake.
- self._ssl_io_loop(self.sslobj.do_handshake)
-
- def __enter__(self):
- return self
-
- def __exit__(self, *_):
- self.close()
-
- def fileno(self):
- return self.socket.fileno()
-
- def read(self, len=1024, buffer=None):
- return self._wrap_ssl_read(len, buffer)
-
- def recv(self, len=1024, flags=0):
- if flags != 0:
- raise ValueError("non-zero flags not allowed in calls to recv")
- return self._wrap_ssl_read(len)
-
- def recv_into(self, buffer, nbytes=None, flags=0):
- if flags != 0:
- raise ValueError("non-zero flags not allowed in calls to recv_into")
- if buffer and (nbytes is None):
- nbytes = len(buffer)
- elif nbytes is None:
- nbytes = 1024
- return self.read(nbytes, buffer)
-
- def sendall(self, data, flags=0):
- if flags != 0:
- raise ValueError("non-zero flags not allowed in calls to sendall")
- count = 0
- with memoryview(data) as view, view.cast("B") as byte_view:
- amount = len(byte_view)
- while count < amount:
- v = self.send(byte_view[count:])
- count += v
-
- def send(self, data, flags=0):
- if flags != 0:
- raise ValueError("non-zero flags not allowed in calls to send")
- response = self._ssl_io_loop(self.sslobj.write, data)
- return response
-
- def makefile(
- self, mode="r", buffering=None, encoding=None, errors=None, newline=None
- ):
- """
- Python's httpclient uses makefile and buffered io when reading HTTP
- messages and we need to support it.
-
- This is unfortunately a copy and paste of socket.py makefile with small
- changes to point to the socket directly.
- """
- if not set(mode) <= {"r", "w", "b"}:
- raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,))
-
- writing = "w" in mode
- reading = "r" in mode or not writing
- assert reading or writing
- binary = "b" in mode
- rawmode = ""
- if reading:
- rawmode += "r"
- if writing:
- rawmode += "w"
- raw = socket.SocketIO(self, rawmode)
- self.socket._io_refs += 1
- if buffering is None:
- buffering = -1
- if buffering < 0:
- buffering = io.DEFAULT_BUFFER_SIZE
- if buffering == 0:
- if not binary:
- raise ValueError("unbuffered streams must be binary")
- return raw
- if reading and writing:
- buffer = io.BufferedRWPair(raw, raw, buffering)
- elif reading:
- buffer = io.BufferedReader(raw, buffering)
- else:
- assert writing
- buffer = io.BufferedWriter(raw, buffering)
- if binary:
- return buffer
- text = io.TextIOWrapper(buffer, encoding, errors, newline)
- text.mode = mode
- return text
-
- def unwrap(self):
- self._ssl_io_loop(self.sslobj.unwrap)
-
- def close(self):
- self.socket.close()
-
- def getpeercert(self, binary_form=False):
- return self.sslobj.getpeercert(binary_form)
-
- def version(self):
- return self.sslobj.version()
-
- def cipher(self):
- return self.sslobj.cipher()
-
- def selected_alpn_protocol(self):
- return self.sslobj.selected_alpn_protocol()
-
- def selected_npn_protocol(self):
- return self.sslobj.selected_npn_protocol()
-
- def shared_ciphers(self):
- return self.sslobj.shared_ciphers()
-
- def compression(self):
- return self.sslobj.compression()
-
- def settimeout(self, value):
- self.socket.settimeout(value)
-
- def gettimeout(self):
- return self.socket.gettimeout()
-
- def _decref_socketios(self):
- self.socket._decref_socketios()
-
- def _wrap_ssl_read(self, len, buffer=None):
- try:
- return self._ssl_io_loop(self.sslobj.read, len, buffer)
- except ssl.SSLError as e:
- if e.errno == ssl.SSL_ERROR_EOF and self.suppress_ragged_eofs:
- return 0 # eof, return 0.
- else:
- raise
-
- def _ssl_io_loop(self, func, *args):
- """Performs an I/O loop between incoming/outgoing and the socket."""
- should_loop = True
- ret = None
-
- while should_loop:
- errno = None
- try:
- ret = func(*args)
- except ssl.SSLError as e:
- if e.errno not in (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE):
- # WANT_READ, and WANT_WRITE are expected, others are not.
- raise e
- errno = e.errno
-
- buf = self.outgoing.read()
- self.socket.sendall(buf)
-
- if errno is None:
- should_loop = False
- elif errno == ssl.SSL_ERROR_WANT_READ:
- buf = self.socket.recv(SSL_BLOCKSIZE)
- if buf:
- self.incoming.write(buf)
- else:
- self.incoming.write_eof()
- return ret
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/timeout.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/timeout.py
deleted file mode 100644
index ff69593b05..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/timeout.py
+++ /dev/null
@@ -1,268 +0,0 @@
-from __future__ import absolute_import
-
-import time
-
-# The default socket timeout, used by httplib to indicate that no timeout was
-# specified by the user
-from socket import _GLOBAL_DEFAULT_TIMEOUT
-
-from ..exceptions import TimeoutStateError
-
-# A sentinel value to indicate that no timeout was specified by the user in
-# urllib3
-_Default = object()
-
-
-# Use time.monotonic if available.
-current_time = getattr(time, "monotonic", time.time)
-
-
-class Timeout(object):
- """Timeout configuration.
-
- Timeouts can be defined as a default for a pool:
-
- .. code-block:: python
-
- timeout = Timeout(connect=2.0, read=7.0)
- http = PoolManager(timeout=timeout)
- response = http.request('GET', 'http://example.com/')
-
- Or per-request (which overrides the default for the pool):
-
- .. code-block:: python
-
- response = http.request('GET', 'http://example.com/', timeout=Timeout(10))
-
- Timeouts can be disabled by setting all the parameters to ``None``:
-
- .. code-block:: python
-
- no_timeout = Timeout(connect=None, read=None)
- response = http.request('GET', 'http://example.com/, timeout=no_timeout)
-
-
- :param total:
- This combines the connect and read timeouts into one; the read timeout
- will be set to the time leftover from the connect attempt. In the
- event that both a connect timeout and a total are specified, or a read
- timeout and a total are specified, the shorter timeout will be applied.
-
- Defaults to None.
-
- :type total: int, float, or None
-
- :param connect:
- The maximum amount of time (in seconds) to wait for a connection
- attempt to a server to succeed. Omitting the parameter will default the
- connect timeout to the system default, probably `the global default
- timeout in socket.py
- `_.
- None will set an infinite timeout for connection attempts.
-
- :type connect: int, float, or None
-
- :param read:
- The maximum amount of time (in seconds) to wait between consecutive
- read operations for a response from the server. Omitting the parameter
- will default the read timeout to the system default, probably `the
- global default timeout in socket.py
- `_.
- None will set an infinite timeout.
-
- :type read: int, float, or None
-
- .. note::
-
- Many factors can affect the total amount of time for urllib3 to return
- an HTTP response.
-
- For example, Python's DNS resolver does not obey the timeout specified
- on the socket. Other factors that can affect total request time include
- high CPU load, high swap, the program running at a low priority level,
- or other behaviors.
-
- In addition, the read and total timeouts only measure the time between
- read operations on the socket connecting the client and the server,
- not the total amount of time for the request to return a complete
- response. For most requests, the timeout is raised because the server
- has not sent the first byte in the specified time. This is not always
- the case; if a server streams one byte every fifteen seconds, a timeout
- of 20 seconds will not trigger, even though the request will take
- several minutes to complete.
-
- If your goal is to cut off any request after a set amount of wall clock
- time, consider having a second "watcher" thread to cut off a slow
- request.
- """
-
- #: A sentinel object representing the default timeout value
- DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT
-
- def __init__(self, total=None, connect=_Default, read=_Default):
- self._connect = self._validate_timeout(connect, "connect")
- self._read = self._validate_timeout(read, "read")
- self.total = self._validate_timeout(total, "total")
- self._start_connect = None
-
- def __repr__(self):
- return "%s(connect=%r, read=%r, total=%r)" % (
- type(self).__name__,
- self._connect,
- self._read,
- self.total,
- )
-
- # __str__ provided for backwards compatibility
- __str__ = __repr__
-
- @classmethod
- def _validate_timeout(cls, value, name):
- """Check that a timeout attribute is valid.
-
- :param value: The timeout value to validate
- :param name: The name of the timeout attribute to validate. This is
- used to specify in error messages.
- :return: The validated and casted version of the given value.
- :raises ValueError: If it is a numeric value less than or equal to
- zero, or the type is not an integer, float, or None.
- """
- if value is _Default:
- return cls.DEFAULT_TIMEOUT
-
- if value is None or value is cls.DEFAULT_TIMEOUT:
- return value
-
- if isinstance(value, bool):
- raise ValueError(
- "Timeout cannot be a boolean value. It must "
- "be an int, float or None."
- )
- try:
- float(value)
- except (TypeError, ValueError):
- raise ValueError(
- "Timeout value %s was %s, but it must be an "
- "int, float or None." % (name, value)
- )
-
- try:
- if value <= 0:
- raise ValueError(
- "Attempted to set %s timeout to %s, but the "
- "timeout cannot be set to a value less "
- "than or equal to 0." % (name, value)
- )
- except TypeError:
- # Python 3
- raise ValueError(
- "Timeout value %s was %s, but it must be an "
- "int, float or None." % (name, value)
- )
-
- return value
-
- @classmethod
- def from_float(cls, timeout):
- """Create a new Timeout from a legacy timeout value.
-
- The timeout value used by httplib.py sets the same timeout on the
- connect(), and recv() socket requests. This creates a :class:`Timeout`
- object that sets the individual timeouts to the ``timeout`` value
- passed to this function.
-
- :param timeout: The legacy timeout value.
- :type timeout: integer, float, sentinel default object, or None
- :return: Timeout object
- :rtype: :class:`Timeout`
- """
- return Timeout(read=timeout, connect=timeout)
-
- def clone(self):
- """Create a copy of the timeout object
-
- Timeout properties are stored per-pool but each request needs a fresh
- Timeout object to ensure each one has its own start/stop configured.
-
- :return: a copy of the timeout object
- :rtype: :class:`Timeout`
- """
- # We can't use copy.deepcopy because that will also create a new object
- # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to
- # detect the user default.
- return Timeout(connect=self._connect, read=self._read, total=self.total)
-
- def start_connect(self):
- """Start the timeout clock, used during a connect() attempt
-
- :raises urllib3.exceptions.TimeoutStateError: if you attempt
- to start a timer that has been started already.
- """
- if self._start_connect is not None:
- raise TimeoutStateError("Timeout timer has already been started.")
- self._start_connect = current_time()
- return self._start_connect
-
- def get_connect_duration(self):
- """Gets the time elapsed since the call to :meth:`start_connect`.
-
- :return: Elapsed time in seconds.
- :rtype: float
- :raises urllib3.exceptions.TimeoutStateError: if you attempt
- to get duration for a timer that hasn't been started.
- """
- if self._start_connect is None:
- raise TimeoutStateError(
- "Can't get connect duration for timer that has not started."
- )
- return current_time() - self._start_connect
-
- @property
- def connect_timeout(self):
- """Get the value to use when setting a connection timeout.
-
- This will be a positive float or integer, the value None
- (never timeout), or the default system timeout.
-
- :return: Connect timeout.
- :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None
- """
- if self.total is None:
- return self._connect
-
- if self._connect is None or self._connect is self.DEFAULT_TIMEOUT:
- return self.total
-
- return min(self._connect, self.total)
-
- @property
- def read_timeout(self):
- """Get the value for the read timeout.
-
- This assumes some time has elapsed in the connection timeout and
- computes the read timeout appropriately.
-
- If self.total is set, the read timeout is dependent on the amount of
- time taken by the connect timeout. If the connection time has not been
- established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be
- raised.
-
- :return: Value to use for the read timeout.
- :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None
- :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect`
- has not yet been called on this object.
- """
- if (
- self.total is not None
- and self.total is not self.DEFAULT_TIMEOUT
- and self._read is not None
- and self._read is not self.DEFAULT_TIMEOUT
- ):
- # In case the connect timeout has not yet been established.
- if self._start_connect is None:
- return self._read
- return max(0, min(self.total - self.get_connect_duration(), self._read))
- elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT:
- return max(0, self.total - self.get_connect_duration())
- else:
- return self._read
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/url.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/url.py
deleted file mode 100644
index 81a03da9e3..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/url.py
+++ /dev/null
@@ -1,432 +0,0 @@
-from __future__ import absolute_import
-
-import re
-from collections import namedtuple
-
-from ..exceptions import LocationParseError
-from ..packages import six
-
-url_attrs = ["scheme", "auth", "host", "port", "path", "query", "fragment"]
-
-# We only want to normalize urls with an HTTP(S) scheme.
-# urllib3 infers URLs without a scheme (None) to be http.
-NORMALIZABLE_SCHEMES = ("http", "https", None)
-
-# Almost all of these patterns were derived from the
-# 'rfc3986' module: https://github.com/python-hyper/rfc3986
-PERCENT_RE = re.compile(r"%[a-fA-F0-9]{2}")
-SCHEME_RE = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+-]*:|/)")
-URI_RE = re.compile(
- r"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):)?"
- r"(?://([^\\/?#]*))?"
- r"([^?#]*)"
- r"(?:\?([^#]*))?"
- r"(?:#(.*))?$",
- re.UNICODE | re.DOTALL,
-)
-
-IPV4_PAT = r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}"
-HEX_PAT = "[0-9A-Fa-f]{1,4}"
-LS32_PAT = "(?:{hex}:{hex}|{ipv4})".format(hex=HEX_PAT, ipv4=IPV4_PAT)
-_subs = {"hex": HEX_PAT, "ls32": LS32_PAT}
-_variations = [
- # 6( h16 ":" ) ls32
- "(?:%(hex)s:){6}%(ls32)s",
- # "::" 5( h16 ":" ) ls32
- "::(?:%(hex)s:){5}%(ls32)s",
- # [ h16 ] "::" 4( h16 ":" ) ls32
- "(?:%(hex)s)?::(?:%(hex)s:){4}%(ls32)s",
- # [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
- "(?:(?:%(hex)s:)?%(hex)s)?::(?:%(hex)s:){3}%(ls32)s",
- # [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
- "(?:(?:%(hex)s:){0,2}%(hex)s)?::(?:%(hex)s:){2}%(ls32)s",
- # [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
- "(?:(?:%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s",
- # [ *4( h16 ":" ) h16 ] "::" ls32
- "(?:(?:%(hex)s:){0,4}%(hex)s)?::%(ls32)s",
- # [ *5( h16 ":" ) h16 ] "::" h16
- "(?:(?:%(hex)s:){0,5}%(hex)s)?::%(hex)s",
- # [ *6( h16 ":" ) h16 ] "::"
- "(?:(?:%(hex)s:){0,6}%(hex)s)?::",
-]
-
-UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._!\-~"
-IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")"
-ZONE_ID_PAT = "(?:%25|%)(?:[" + UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+"
-IPV6_ADDRZ_PAT = r"\[" + IPV6_PAT + r"(?:" + ZONE_ID_PAT + r")?\]"
-REG_NAME_PAT = r"(?:[^\[\]%:/?#]|%[a-fA-F0-9]{2})*"
-TARGET_RE = re.compile(r"^(/[^?#]*)(?:\?([^#]*))?(?:#.*)?$")
-
-IPV4_RE = re.compile("^" + IPV4_PAT + "$")
-IPV6_RE = re.compile("^" + IPV6_PAT + "$")
-IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT + "$")
-BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT[2:-2] + "$")
-ZONE_ID_RE = re.compile("(" + ZONE_ID_PAT + r")\]$")
-
-_HOST_PORT_PAT = ("^(%s|%s|%s)(?::([0-9]{0,5}))?$") % (
- REG_NAME_PAT,
- IPV4_PAT,
- IPV6_ADDRZ_PAT,
-)
-_HOST_PORT_RE = re.compile(_HOST_PORT_PAT, re.UNICODE | re.DOTALL)
-
-UNRESERVED_CHARS = set(
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-~"
-)
-SUB_DELIM_CHARS = set("!$&'()*+,;=")
-USERINFO_CHARS = UNRESERVED_CHARS | SUB_DELIM_CHARS | {":"}
-PATH_CHARS = USERINFO_CHARS | {"@", "/"}
-QUERY_CHARS = FRAGMENT_CHARS = PATH_CHARS | {"?"}
-
-
-class Url(namedtuple("Url", url_attrs)):
- """
- Data structure for representing an HTTP URL. Used as a return value for
- :func:`parse_url`. Both the scheme and host are normalized as they are
- both case-insensitive according to RFC 3986.
- """
-
- __slots__ = ()
-
- def __new__(
- cls,
- scheme=None,
- auth=None,
- host=None,
- port=None,
- path=None,
- query=None,
- fragment=None,
- ):
- if path and not path.startswith("/"):
- path = "/" + path
- if scheme is not None:
- scheme = scheme.lower()
- return super(Url, cls).__new__(
- cls, scheme, auth, host, port, path, query, fragment
- )
-
- @property
- def hostname(self):
- """For backwards-compatibility with urlparse. We're nice like that."""
- return self.host
-
- @property
- def request_uri(self):
- """Absolute path including the query string."""
- uri = self.path or "/"
-
- if self.query is not None:
- uri += "?" + self.query
-
- return uri
-
- @property
- def netloc(self):
- """Network location including host and port"""
- if self.port:
- return "%s:%d" % (self.host, self.port)
- return self.host
-
- @property
- def url(self):
- """
- Convert self into a url
-
- This function should more or less round-trip with :func:`.parse_url`. The
- returned url may not be exactly the same as the url inputted to
- :func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls
- with a blank port will have : removed).
-
- Example: ::
-
- >>> U = parse_url('http://google.com/mail/')
- >>> U.url
- 'http://google.com/mail/'
- >>> Url('http', 'username:password', 'host.com', 80,
- ... '/path', 'query', 'fragment').url
- 'http://username:password@host.com:80/path?query#fragment'
- """
- scheme, auth, host, port, path, query, fragment = self
- url = u""
-
- # We use "is not None" we want things to happen with empty strings (or 0 port)
- if scheme is not None:
- url += scheme + u"://"
- if auth is not None:
- url += auth + u"@"
- if host is not None:
- url += host
- if port is not None:
- url += u":" + str(port)
- if path is not None:
- url += path
- if query is not None:
- url += u"?" + query
- if fragment is not None:
- url += u"#" + fragment
-
- return url
-
- def __str__(self):
- return self.url
-
-
-def split_first(s, delims):
- """
- .. deprecated:: 1.25
-
- Given a string and an iterable of delimiters, split on the first found
- delimiter. Return two split parts and the matched delimiter.
-
- If not found, then the first part is the full input string.
-
- Example::
-
- >>> split_first('foo/bar?baz', '?/=')
- ('foo', 'bar?baz', '/')
- >>> split_first('foo/bar?baz', '123')
- ('foo/bar?baz', '', None)
-
- Scales linearly with number of delims. Not ideal for large number of delims.
- """
- min_idx = None
- min_delim = None
- for d in delims:
- idx = s.find(d)
- if idx < 0:
- continue
-
- if min_idx is None or idx < min_idx:
- min_idx = idx
- min_delim = d
-
- if min_idx is None or min_idx < 0:
- return s, "", None
-
- return s[:min_idx], s[min_idx + 1 :], min_delim
-
-
-def _encode_invalid_chars(component, allowed_chars, encoding="utf-8"):
- """Percent-encodes a URI component without reapplying
- onto an already percent-encoded component.
- """
- if component is None:
- return component
-
- component = six.ensure_text(component)
-
- # Normalize existing percent-encoded bytes.
- # Try to see if the component we're encoding is already percent-encoded
- # so we can skip all '%' characters but still encode all others.
- component, percent_encodings = PERCENT_RE.subn(
- lambda match: match.group(0).upper(), component
- )
-
- uri_bytes = component.encode("utf-8", "surrogatepass")
- is_percent_encoded = percent_encodings == uri_bytes.count(b"%")
- encoded_component = bytearray()
-
- for i in range(0, len(uri_bytes)):
- # Will return a single character bytestring on both Python 2 & 3
- byte = uri_bytes[i : i + 1]
- byte_ord = ord(byte)
- if (is_percent_encoded and byte == b"%") or (
- byte_ord < 128 and byte.decode() in allowed_chars
- ):
- encoded_component += byte
- continue
- encoded_component.extend(b"%" + (hex(byte_ord)[2:].encode().zfill(2).upper()))
-
- return encoded_component.decode(encoding)
-
-
-def _remove_path_dot_segments(path):
- # See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code
- segments = path.split("/") # Turn the path into a list of segments
- output = [] # Initialize the variable to use to store output
-
- for segment in segments:
- # '.' is the current directory, so ignore it, it is superfluous
- if segment == ".":
- continue
- # Anything other than '..', should be appended to the output
- elif segment != "..":
- output.append(segment)
- # In this case segment == '..', if we can, we should pop the last
- # element
- elif output:
- output.pop()
-
- # If the path starts with '/' and the output is empty or the first string
- # is non-empty
- if path.startswith("/") and (not output or output[0]):
- output.insert(0, "")
-
- # If the path starts with '/.' or '/..' ensure we add one more empty
- # string to add a trailing '/'
- if path.endswith(("/.", "/..")):
- output.append("")
-
- return "/".join(output)
-
-
-def _normalize_host(host, scheme):
- if host:
- if isinstance(host, six.binary_type):
- host = six.ensure_str(host)
-
- if scheme in NORMALIZABLE_SCHEMES:
- is_ipv6 = IPV6_ADDRZ_RE.match(host)
- if is_ipv6:
- match = ZONE_ID_RE.search(host)
- if match:
- start, end = match.span(1)
- zone_id = host[start:end]
-
- if zone_id.startswith("%25") and zone_id != "%25":
- zone_id = zone_id[3:]
- else:
- zone_id = zone_id[1:]
- zone_id = "%" + _encode_invalid_chars(zone_id, UNRESERVED_CHARS)
- return host[:start].lower() + zone_id + host[end:]
- else:
- return host.lower()
- elif not IPV4_RE.match(host):
- return six.ensure_str(
- b".".join([_idna_encode(label) for label in host.split(".")])
- )
- return host
-
-
-def _idna_encode(name):
- if name and any([ord(x) > 128 for x in name]):
- try:
- import idna
- except ImportError:
- six.raise_from(
- LocationParseError("Unable to parse URL without the 'idna' module"),
- None,
- )
- try:
- return idna.encode(name.lower(), strict=True, std3_rules=True)
- except idna.IDNAError:
- six.raise_from(
- LocationParseError(u"Name '%s' is not a valid IDNA label" % name), None
- )
- return name.lower().encode("ascii")
-
-
-def _encode_target(target):
- """Percent-encodes a request target so that there are no invalid characters"""
- path, query = TARGET_RE.match(target).groups()
- target = _encode_invalid_chars(path, PATH_CHARS)
- query = _encode_invalid_chars(query, QUERY_CHARS)
- if query is not None:
- target += "?" + query
- return target
-
-
-def parse_url(url):
- """
- Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is
- performed to parse incomplete urls. Fields not provided will be None.
- This parser is RFC 3986 compliant.
-
- The parser logic and helper functions are based heavily on
- work done in the ``rfc3986`` module.
-
- :param str url: URL to parse into a :class:`.Url` namedtuple.
-
- Partly backwards-compatible with :mod:`urlparse`.
-
- Example::
-
- >>> parse_url('http://google.com/mail/')
- Url(scheme='http', host='google.com', port=None, path='/mail/', ...)
- >>> parse_url('google.com:80')
- Url(scheme=None, host='google.com', port=80, path=None, ...)
- >>> parse_url('/foo?bar')
- Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...)
- """
- if not url:
- # Empty
- return Url()
-
- source_url = url
- if not SCHEME_RE.search(url):
- url = "//" + url
-
- try:
- scheme, authority, path, query, fragment = URI_RE.match(url).groups()
- normalize_uri = scheme is None or scheme.lower() in NORMALIZABLE_SCHEMES
-
- if scheme:
- scheme = scheme.lower()
-
- if authority:
- auth, _, host_port = authority.rpartition("@")
- auth = auth or None
- host, port = _HOST_PORT_RE.match(host_port).groups()
- if auth and normalize_uri:
- auth = _encode_invalid_chars(auth, USERINFO_CHARS)
- if port == "":
- port = None
- else:
- auth, host, port = None, None, None
-
- if port is not None:
- port = int(port)
- if not (0 <= port <= 65535):
- raise LocationParseError(url)
-
- host = _normalize_host(host, scheme)
-
- if normalize_uri and path:
- path = _remove_path_dot_segments(path)
- path = _encode_invalid_chars(path, PATH_CHARS)
- if normalize_uri and query:
- query = _encode_invalid_chars(query, QUERY_CHARS)
- if normalize_uri and fragment:
- fragment = _encode_invalid_chars(fragment, FRAGMENT_CHARS)
-
- except (ValueError, AttributeError):
- return six.raise_from(LocationParseError(source_url), None)
-
- # For the sake of backwards compatibility we put empty
- # string values for path if there are any defined values
- # beyond the path in the URL.
- # TODO: Remove this when we break backwards compatibility.
- if not path:
- if query is not None or fragment is not None:
- path = ""
- else:
- path = None
-
- # Ensure that each part of the URL is a `str` for
- # backwards compatibility.
- if isinstance(url, six.text_type):
- ensure_func = six.ensure_text
- else:
- ensure_func = six.ensure_str
-
- def ensure_type(x):
- return x if x is None else ensure_func(x)
-
- return Url(
- scheme=ensure_type(scheme),
- auth=ensure_type(auth),
- host=ensure_type(host),
- port=port,
- path=ensure_type(path),
- query=ensure_type(query),
- fragment=ensure_type(fragment),
- )
-
-
-def get_host(url):
- """
- Deprecated. Use :func:`parse_url` instead.
- """
- p = parse_url(url)
- return p.scheme or "http", p.hostname, p.port
diff --git a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/wait.py b/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/wait.py
deleted file mode 100644
index c280646c7b..0000000000
--- a/server_addon/fusion/client/ayon_fusion/vendor/urllib3/util/wait.py
+++ /dev/null
@@ -1,153 +0,0 @@
-import errno
-import select
-import sys
-from functools import partial
-
-try:
- from time import monotonic
-except ImportError:
- from time import time as monotonic
-
-__all__ = ["NoWayToWaitForSocketError", "wait_for_read", "wait_for_write"]
-
-
-class NoWayToWaitForSocketError(Exception):
- pass
-
-
-# How should we wait on sockets?
-#
-# There are two types of APIs you can use for waiting on sockets: the fancy
-# modern stateful APIs like epoll/kqueue, and the older stateless APIs like
-# select/poll. The stateful APIs are more efficient when you have a lots of
-# sockets to keep track of, because you can set them up once and then use them
-# lots of times. But we only ever want to wait on a single socket at a time
-# and don't want to keep track of state, so the stateless APIs are actually
-# more efficient. So we want to use select() or poll().
-#
-# Now, how do we choose between select() and poll()? On traditional Unixes,
-# select() has a strange calling convention that makes it slow, or fail
-# altogether, for high-numbered file descriptors. The point of poll() is to fix
-# that, so on Unixes, we prefer poll().
-#
-# On Windows, there is no poll() (or at least Python doesn't provide a wrapper
-# for it), but that's OK, because on Windows, select() doesn't have this
-# strange calling convention; plain select() works fine.
-#
-# So: on Windows we use select(), and everywhere else we use poll(). We also
-# fall back to select() in case poll() is somehow broken or missing.
-
-if sys.version_info >= (3, 5):
- # Modern Python, that retries syscalls by default
- def _retry_on_intr(fn, timeout):
- return fn(timeout)
-
-
-else:
- # Old and broken Pythons.
- def _retry_on_intr(fn, timeout):
- if timeout is None:
- deadline = float("inf")
- else:
- deadline = monotonic() + timeout
-
- while True:
- try:
- return fn(timeout)
- # OSError for 3 <= pyver < 3.5, select.error for pyver <= 2.7
- except (OSError, select.error) as e:
- # 'e.args[0]' incantation works for both OSError and select.error
- if e.args[0] != errno.EINTR:
- raise
- else:
- timeout = deadline - monotonic()
- if timeout < 0:
- timeout = 0
- if timeout == float("inf"):
- timeout = None
- continue
-
-
-def select_wait_for_socket(sock, read=False, write=False, timeout=None):
- if not read and not write:
- raise RuntimeError("must specify at least one of read=True, write=True")
- rcheck = []
- wcheck = []
- if read:
- rcheck.append(sock)
- if write:
- wcheck.append(sock)
- # When doing a non-blocking connect, most systems signal success by
- # marking the socket writable. Windows, though, signals success by marked
- # it as "exceptional". We paper over the difference by checking the write
- # sockets for both conditions. (The stdlib selectors module does the same
- # thing.)
- fn = partial(select.select, rcheck, wcheck, wcheck)
- rready, wready, xready = _retry_on_intr(fn, timeout)
- return bool(rready or wready or xready)
-
-
-def poll_wait_for_socket(sock, read=False, write=False, timeout=None):
- if not read and not write:
- raise RuntimeError("must specify at least one of read=True, write=True")
- mask = 0
- if read:
- mask |= select.POLLIN
- if write:
- mask |= select.POLLOUT
- poll_obj = select.poll()
- poll_obj.register(sock, mask)
-
- # For some reason, poll() takes timeout in milliseconds
- def do_poll(t):
- if t is not None:
- t *= 1000
- return poll_obj.poll(t)
-
- return bool(_retry_on_intr(do_poll, timeout))
-
-
-def null_wait_for_socket(*args, **kwargs):
- raise NoWayToWaitForSocketError("no select-equivalent available")
-
-
-def _have_working_poll():
- # Apparently some systems have a select.poll that fails as soon as you try
- # to use it, either due to strange configuration or broken monkeypatching
- # from libraries like eventlet/greenlet.
- try:
- poll_obj = select.poll()
- _retry_on_intr(poll_obj.poll, 0)
- except (AttributeError, OSError):
- return False
- else:
- return True
-
-
-def wait_for_socket(*args, **kwargs):
- # We delay choosing which implementation to use until the first time we're
- # called. We could do it at import time, but then we might make the wrong
- # decision if someone goes wild with monkeypatching select.poll after
- # we're imported.
- global wait_for_socket
- if _have_working_poll():
- wait_for_socket = poll_wait_for_socket
- elif hasattr(select, "select"):
- wait_for_socket = select_wait_for_socket
- else: # Platform-specific: Appengine.
- wait_for_socket = null_wait_for_socket
- return wait_for_socket(*args, **kwargs)
-
-
-def wait_for_read(sock, timeout=None):
- """Waits for reading to be available on a given socket.
- Returns True if the socket is readable, or False if the timeout expired.
- """
- return wait_for_socket(sock, read=True, timeout=timeout)
-
-
-def wait_for_write(sock, timeout=None):
- """Waits for writing to be available on a given socket.
- Returns True if the socket is readable, or False if the timeout expired.
- """
- return wait_for_socket(sock, write=True, timeout=timeout)
diff --git a/server_addon/fusion/client/ayon_fusion/version.py b/server_addon/fusion/client/ayon_fusion/version.py
deleted file mode 100644
index 209eddcdb6..0000000000
--- a/server_addon/fusion/client/ayon_fusion/version.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-"""Package declaring AYON addon 'fusion' version."""
-__version__ = "0.2.0"
diff --git a/server_addon/fusion/package.py b/server_addon/fusion/package.py
deleted file mode 100644
index e82e9bf0f6..0000000000
--- a/server_addon/fusion/package.py
+++ /dev/null
@@ -1,10 +0,0 @@
-name = "fusion"
-title = "Fusion"
-version = "0.2.0"
-
-client_dir = "ayon_fusion"
-
-ayon_required_addons = {
- "core": ">0.3.2",
-}
-ayon_compatible_addons = {}
diff --git a/server_addon/fusion/server/__init__.py b/server_addon/fusion/server/__init__.py
deleted file mode 100644
index 0456cfd5ee..0000000000
--- a/server_addon/fusion/server/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Type
-
-from ayon_server.addons import BaseServerAddon
-
-from .settings import FusionSettings, DEFAULT_VALUES
-
-
-class FusionAddon(BaseServerAddon):
- settings_model: Type[FusionSettings] = FusionSettings
-
- async def get_default_settings(self):
- settings_model_cls = self.get_settings_model()
- return settings_model_cls(**DEFAULT_VALUES)
diff --git a/server_addon/fusion/server/imageio.py b/server_addon/fusion/server/imageio.py
deleted file mode 100644
index 4d4688e269..0000000000
--- a/server_addon/fusion/server/imageio.py
+++ /dev/null
@@ -1,63 +0,0 @@
-from pydantic import validator
-from ayon_server.settings import BaseSettingsModel, SettingsField
-from ayon_server.settings.validators import ensure_unique_names
-
-
-class ImageIOConfigModel(BaseSettingsModel):
- """[DEPRECATED] Addon OCIO config settings. Please set the OCIO config
- path in the Core addon profiles here
- (ayon+settings://core/imageio/ocio_config_profiles).
- """
-
- override_global_config: bool = SettingsField(
- False,
- title="Override global OCIO config",
- description=(
- "DEPRECATED functionality. Please set the OCIO config path in the "
- "Core addon profiles here (ayon+settings://core/imageio/"
- "ocio_config_profiles)."
- ),
- )
- filepath: list[str] = SettingsField(
- default_factory=list,
- title="Config path",
- description=(
- "DEPRECATED functionality. Please set the OCIO config path in the "
- "Core addon profiles here (ayon+settings://core/imageio/"
- "ocio_config_profiles)."
- ),
- )
-
-
-class ImageIOFileRuleModel(BaseSettingsModel):
- name: str = SettingsField("", title="Rule name")
- pattern: str = SettingsField("", title="Regex pattern")
- colorspace: str = SettingsField("", title="Colorspace name")
- ext: str = SettingsField("", title="File extension")
-
-
-class ImageIOFileRulesModel(BaseSettingsModel):
- activate_host_rules: bool = SettingsField(False)
- rules: list[ImageIOFileRuleModel] = SettingsField(
- default_factory=list,
- title="Rules"
- )
-
- @validator("rules")
- def validate_unique_outputs(cls, value):
- ensure_unique_names(value)
- return value
-
-
-class FusionImageIOModel(BaseSettingsModel):
- activate_host_color_management: bool = SettingsField(
- True, title="Enable Color Management"
- )
- ocio_config: ImageIOConfigModel = SettingsField(
- default_factory=ImageIOConfigModel,
- title="OCIO config"
- )
- file_rules: ImageIOFileRulesModel = SettingsField(
- default_factory=ImageIOFileRulesModel,
- title="File Rules"
- )
diff --git a/server_addon/fusion/server/settings.py b/server_addon/fusion/server/settings.py
deleted file mode 100644
index f16ae6e3e7..0000000000
--- a/server_addon/fusion/server/settings.py
+++ /dev/null
@@ -1,185 +0,0 @@
-from ayon_server.settings import (
- BaseSettingsModel,
- SettingsField,
-)
-
-from .imageio import FusionImageIOModel
-
-
-class CopyFusionSettingsModel(BaseSettingsModel):
- copy_path: str = SettingsField("", title="Local Fusion profile directory")
- copy_status: bool = SettingsField(title="Copy profile on first launch")
- force_sync: bool = SettingsField(title="Resync profile on each launch")
-
-
-def _create_saver_instance_attributes_enum():
- return [
- {
- "value": "reviewable",
- "label": "Reviewable"
- },
- {
- "value": "farm_rendering",
- "label": "Farm rendering"
- }
- ]
-
-
-def _image_format_enum():
- return [
- {"value": "exr", "label": "exr"},
- {"value": "tga", "label": "tga"},
- {"value": "png", "label": "png"},
- {"value": "tif", "label": "tif"},
- {"value": "jpg", "label": "jpg"},
- ]
-
-
-def _frame_range_options_enum():
- return [
- {"value": "asset_db", "label": "Current asset context"},
- {"value": "render_range", "label": "From render in/out"},
- {"value": "comp_range", "label": "From composition timeline"},
- ]
-
-
-class CreateSaverPluginModel(BaseSettingsModel):
- _isGroup = True
- temp_rendering_path_template: str = SettingsField(
- "", title="Temporary rendering path template"
- )
- default_variants: list[str] = SettingsField(
- default_factory=list,
- title="Default variants"
- )
- instance_attributes: list[str] = SettingsField(
- default_factory=list,
- enum_resolver=_create_saver_instance_attributes_enum,
- title="Instance attributes"
- )
- image_format: str = SettingsField(
- enum_resolver=_image_format_enum,
- title="Output Image Format"
- )
-
-
-class HookOptionalModel(BaseSettingsModel):
- enabled: bool = SettingsField(
- True,
- title="Enabled"
- )
-
-
-class HooksModel(BaseSettingsModel):
- InstallPySideToFusion: HookOptionalModel = SettingsField(
- default_factory=HookOptionalModel,
- title="Install PySide2"
- )
- FusionLaunchMenuHook: HookOptionalModel = SettingsField(
- default_factory=HookOptionalModel,
- title="Launch AYON Menu on Fusion Start",
- description="Launch the AYON menu on Fusion application startup. "
- "This is only supported for Fusion 18+"
- )
-
-
-class CreateSaverModel(CreateSaverPluginModel):
- default_frame_range_option: str = SettingsField(
- default="asset_db",
- enum_resolver=_frame_range_options_enum,
- title="Default frame range source"
- )
-
-
-class CreateImageSaverModel(CreateSaverPluginModel):
- default_frame: int = SettingsField(
- 0,
- title="Default rendered frame"
- )
-
-
-class CreatPluginsModel(BaseSettingsModel):
- CreateSaver: CreateSaverModel = SettingsField(
- default_factory=CreateSaverModel,
- title="Create Saver",
- description="Creator for render product type (eg. sequence)"
- )
- CreateImageSaver: CreateImageSaverModel = SettingsField(
- default_factory=CreateImageSaverModel,
- title="Create Image Saver",
- description="Creator for image product type (eg. single)"
- )
-
-
-class FusionSettings(BaseSettingsModel):
- imageio: FusionImageIOModel = SettingsField(
- default_factory=FusionImageIOModel,
- title="Color Management (ImageIO)"
- )
- copy_fusion_settings: CopyFusionSettingsModel = SettingsField(
- default_factory=CopyFusionSettingsModel,
- title="Local Fusion profile settings"
- )
- hooks: HooksModel = SettingsField(
- default_factory=HooksModel,
- title="Hooks"
- )
- create: CreatPluginsModel = SettingsField(
- default_factory=CreatPluginsModel,
- title="Creator plugins"
- )
-
-
-DEFAULT_VALUES = {
- "imageio": {
- "ocio_config": {
- "enabled": False,
- "filepath": []
- },
- "file_rules": {
- "enabled": False,
- "rules": []
- }
- },
- "copy_fusion_settings": {
- "copy_path": "~/.openpype/hosts/fusion/profiles",
- "copy_status": False,
- "force_sync": False
- },
- "hooks": {
- "InstallPySideToFusion": {
- "enabled": True
- },
- "FusionLaunchMenuHook": {
- "enabled": False
- }
- },
- "create": {
- "CreateSaver": {
- "temp_rendering_path_template": "{workdir}/renders/fusion/{product[name]}/{product[name]}.{frame}.{ext}",
- "default_variants": [
- "Main",
- "Mask"
- ],
- "instance_attributes": [
- "reviewable",
- "farm_rendering"
- ],
- "image_format": "exr",
- "default_frame_range_option": "asset_db"
- },
- "CreateImageSaver": {
- "temp_rendering_path_template": "{workdir}/renders/fusion/{product[name]}/{product[name]}.{ext}",
- "default_variants": [
- "Main",
- "Mask"
- ],
- "instance_attributes": [
- "reviewable",
- "farm_rendering"
- ],
- "image_format": "exr",
- "default_frame": 0
- }
- }
-}