From f6a765ceb59c55aea06921880c1c87d1ff36e5de Mon Sep 17 00:00:00 2001 From: pukkandan Date: Tue, 7 Feb 2023 03:22:29 +0530 Subject: [dependencies] Standardize `Cryptodome` imports --- yt_dlp/dependencies/Cryptodome.py | 38 ++++++++++++++++++ yt_dlp/dependencies/__init__.py | 83 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 yt_dlp/dependencies/Cryptodome.py create mode 100644 yt_dlp/dependencies/__init__.py (limited to 'yt_dlp/dependencies') diff --git a/yt_dlp/dependencies/Cryptodome.py b/yt_dlp/dependencies/Cryptodome.py new file mode 100644 index 000000000..b95f45d72 --- /dev/null +++ b/yt_dlp/dependencies/Cryptodome.py @@ -0,0 +1,38 @@ +import importlib + +from ..compat import functools +from ..compat.compat_utils import EnhancedModule, passthrough_module + +EnhancedModule(__name__) + +try: + import Cryptodome as _parent +except ImportError: + try: + import Crypto as _parent + except (ImportError, SyntaxError): # Old Crypto gives SyntaxError in newer Python + _parent = EnhancedModule('Cryptodome') + __bool__ = lambda: False + + +@functools.cache +def __getattr__(name): + try: + submodule = importlib.import_module(f'.{name}', _parent.__name__) + except ImportError: + return getattr(_parent, name) + return passthrough_module(f'{__name__}.{name}', submodule) + + +@property +@functools.cache +def _yt_dlp__identifier(): + if _parent.__name__ == 'Crypto': + from Crypto.Cipher import AES + try: + # In pycrypto, mode defaults to ECB. See: + # https://www.pycryptodome.org/en/latest/src/vs_pycrypto.html#:~:text=not%20have%20ECB%20as%20default%20mode + AES.new(b'abcdefghijklmnop') + except TypeError: + return 'pycrypto' + return _parent.__name__ diff --git a/yt_dlp/dependencies/__init__.py b/yt_dlp/dependencies/__init__.py new file mode 100644 index 000000000..c2214e6db --- /dev/null +++ b/yt_dlp/dependencies/__init__.py @@ -0,0 +1,83 @@ +# flake8: noqa: F401 +"""Imports all optional dependencies for the project. +An attribute "_yt_dlp__identifier" may be inserted into the module if it uses an ambiguous namespace""" + +try: + import brotlicffi as brotli +except ImportError: + try: + import brotli + except ImportError: + brotli = None + + +try: + import certifi +except ImportError: + certifi = None +else: + from os.path import exists as _path_exists + + # The certificate may not be bundled in executable + if not _path_exists(certifi.where()): + certifi = None + + +try: + import mutagen +except ImportError: + mutagen = None + + +secretstorage = None +try: + import secretstorage + _SECRETSTORAGE_UNAVAILABLE_REASON = None +except ImportError: + _SECRETSTORAGE_UNAVAILABLE_REASON = ( + 'as the `secretstorage` module is not installed. ' + 'Please install by running `python3 -m pip install secretstorage`') +except Exception as _err: + _SECRETSTORAGE_UNAVAILABLE_REASON = f'as the `secretstorage` module could not be initialized. {_err}' + + +try: + import sqlite3 +except ImportError: + # although sqlite3 is part of the standard library, it is possible to compile python without + # sqlite support. See: https://github.com/yt-dlp/yt-dlp/issues/544 + sqlite3 = None + + +try: + import websockets +except (ImportError, SyntaxError): + # websockets 3.10 on python 3.6 causes SyntaxError + # See https://github.com/yt-dlp/yt-dlp/issues/2633 + websockets = None + + +try: + import xattr # xattr or pyxattr +except ImportError: + xattr = None +else: + if hasattr(xattr, 'set'): # pyxattr + xattr._yt_dlp__identifier = 'pyxattr' + + +from . import Cryptodome + +all_dependencies = {k: v for k, v in globals().items() if not k.startswith('_')} +available_dependencies = {k: v for k, v in all_dependencies.items() if v} + + +# Deprecated +Cryptodome_AES = Cryptodome.Cipher.AES if Cryptodome else None + + +__all__ = [ + 'all_dependencies', + 'available_dependencies', + *all_dependencies.keys(), +] -- cgit v1.2.3 From 88426d9446758c707fb511408f2d6f56de952db4 Mon Sep 17 00:00:00 2001 From: pukkandan Date: Wed, 8 Feb 2023 08:14:36 +0530 Subject: [compat_utils] Improve `passthrough_module` --- yt_dlp/dependencies/Cryptodome.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'yt_dlp/dependencies') diff --git a/yt_dlp/dependencies/Cryptodome.py b/yt_dlp/dependencies/Cryptodome.py index b95f45d72..580ce0753 100644 --- a/yt_dlp/dependencies/Cryptodome.py +++ b/yt_dlp/dependencies/Cryptodome.py @@ -1,10 +1,6 @@ -import importlib - from ..compat import functools from ..compat.compat_utils import EnhancedModule, passthrough_module -EnhancedModule(__name__) - try: import Cryptodome as _parent except ImportError: @@ -14,14 +10,8 @@ except ImportError: _parent = EnhancedModule('Cryptodome') __bool__ = lambda: False - -@functools.cache -def __getattr__(name): - try: - submodule = importlib.import_module(f'.{name}', _parent.__name__) - except ImportError: - return getattr(_parent, name) - return passthrough_module(f'{__name__}.{name}', submodule) +passthrough_module(__name__, _parent, (..., '__version__')) +del passthrough_module, EnhancedModule @property -- cgit v1.2.3 From 768a00178109508893488e53a0e720b117fbccf6 Mon Sep 17 00:00:00 2001 From: pukkandan Date: Thu, 9 Feb 2023 01:34:39 +0530 Subject: [compat_utils] Simplify `EnhancedModule` --- yt_dlp/dependencies/Cryptodome.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'yt_dlp/dependencies') diff --git a/yt_dlp/dependencies/Cryptodome.py b/yt_dlp/dependencies/Cryptodome.py index 580ce0753..2adc51374 100644 --- a/yt_dlp/dependencies/Cryptodome.py +++ b/yt_dlp/dependencies/Cryptodome.py @@ -1,5 +1,7 @@ +import types + from ..compat import functools -from ..compat.compat_utils import EnhancedModule, passthrough_module +from ..compat.compat_utils import passthrough_module try: import Cryptodome as _parent @@ -7,11 +9,11 @@ except ImportError: try: import Crypto as _parent except (ImportError, SyntaxError): # Old Crypto gives SyntaxError in newer Python - _parent = EnhancedModule('Cryptodome') + _parent = types.ModuleType('no_Cryptodome') __bool__ = lambda: False passthrough_module(__name__, _parent, (..., '__version__')) -del passthrough_module, EnhancedModule +del passthrough_module @property -- cgit v1.2.3 From 65f6e807804d2af5e00f2aecd72bfc43af19324a Mon Sep 17 00:00:00 2001 From: pukkandan Date: Tue, 28 Feb 2023 23:10:54 +0530 Subject: [dependencies] Simplify `Cryptodome` Closes #6292, closes #6272, closes #6338 --- yt_dlp/dependencies/Cryptodome.py | 48 +++++++++++++++++++++++++-------------- yt_dlp/dependencies/__init__.py | 2 +- 2 files changed, 32 insertions(+), 18 deletions(-) (limited to 'yt_dlp/dependencies') diff --git a/yt_dlp/dependencies/Cryptodome.py b/yt_dlp/dependencies/Cryptodome.py index 2adc51374..a50bce4d4 100644 --- a/yt_dlp/dependencies/Cryptodome.py +++ b/yt_dlp/dependencies/Cryptodome.py @@ -1,8 +1,5 @@ import types -from ..compat import functools -from ..compat.compat_utils import passthrough_module - try: import Cryptodome as _parent except ImportError: @@ -12,19 +9,36 @@ except ImportError: _parent = types.ModuleType('no_Cryptodome') __bool__ = lambda: False -passthrough_module(__name__, _parent, (..., '__version__')) -del passthrough_module +__version__ = '' +AES = PKCS1_v1_5 = Blowfish = PKCS1_OAEP = SHA1 = CMAC = RSA = None +try: + if _parent.__name__ == 'Cryptodome': + from Cryptodome import __version__ + from Cryptodome.Cipher import AES + from Cryptodome.Cipher import PKCS1_v1_5 + from Cryptodome.Cipher import Blowfish + from Cryptodome.Cipher import PKCS1_OAEP + from Cryptodome.Hash import SHA1 + from Cryptodome.Hash import CMAC + from Cryptodome.PublicKey import RSA + elif _parent.__name__ == 'Crypto': + from Crypto import __version__ + from Crypto.Cipher import AES + from Crypto.Cipher import PKCS1_v1_5 + from Crypto.Cipher import Blowfish + from Crypto.Cipher import PKCS1_OAEP + from Crypto.Hash import SHA1 + from Crypto.Hash import CMAC + from Crypto.PublicKey import RSA +except ImportError: + __version__ = f'broken {__version__}'.strip() -@property -@functools.cache -def _yt_dlp__identifier(): - if _parent.__name__ == 'Crypto': - from Crypto.Cipher import AES - try: - # In pycrypto, mode defaults to ECB. See: - # https://www.pycryptodome.org/en/latest/src/vs_pycrypto.html#:~:text=not%20have%20ECB%20as%20default%20mode - AES.new(b'abcdefghijklmnop') - except TypeError: - return 'pycrypto' - return _parent.__name__ +_yt_dlp__identifier = _parent.__name__ +if AES and _yt_dlp__identifier == 'Crypto': + try: + # In pycrypto, mode defaults to ECB. See: + # https://www.pycryptodome.org/en/latest/src/vs_pycrypto.html#:~:text=not%20have%20ECB%20as%20default%20mode + AES.new(b'abcdefghijklmnop') + except TypeError: + _yt_dlp__identifier = 'pycrypto' diff --git a/yt_dlp/dependencies/__init__.py b/yt_dlp/dependencies/__init__.py index c2214e6db..6e7d29c5c 100644 --- a/yt_dlp/dependencies/__init__.py +++ b/yt_dlp/dependencies/__init__.py @@ -73,7 +73,7 @@ available_dependencies = {k: v for k, v in all_dependencies.items() if v} # Deprecated -Cryptodome_AES = Cryptodome.Cipher.AES if Cryptodome else None +Cryptodome_AES = Cryptodome.AES __all__ = [ -- cgit v1.2.3 From 5b28cef72db3b531680d89c121631c73ae05354f Mon Sep 17 00:00:00 2001 From: pukkandan Date: Tue, 28 Feb 2023 23:31:02 +0530 Subject: [cleanup] Misc --- yt_dlp/dependencies/Cryptodome.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'yt_dlp/dependencies') diff --git a/yt_dlp/dependencies/Cryptodome.py b/yt_dlp/dependencies/Cryptodome.py index a50bce4d4..74ab6575c 100644 --- a/yt_dlp/dependencies/Cryptodome.py +++ b/yt_dlp/dependencies/Cryptodome.py @@ -14,22 +14,14 @@ AES = PKCS1_v1_5 = Blowfish = PKCS1_OAEP = SHA1 = CMAC = RSA = None try: if _parent.__name__ == 'Cryptodome': from Cryptodome import __version__ - from Cryptodome.Cipher import AES - from Cryptodome.Cipher import PKCS1_v1_5 - from Cryptodome.Cipher import Blowfish - from Cryptodome.Cipher import PKCS1_OAEP - from Cryptodome.Hash import SHA1 - from Cryptodome.Hash import CMAC + from Cryptodome.Cipher import AES, PKCS1_OAEP, Blowfish, PKCS1_v1_5 + from Cryptodome.Hash import CMAC, SHA1 from Cryptodome.PublicKey import RSA elif _parent.__name__ == 'Crypto': from Crypto import __version__ - from Crypto.Cipher import AES - from Crypto.Cipher import PKCS1_v1_5 - from Crypto.Cipher import Blowfish - from Crypto.Cipher import PKCS1_OAEP - from Crypto.Hash import SHA1 - from Crypto.Hash import CMAC - from Crypto.PublicKey import RSA + from Crypto.Cipher import AES, PKCS1_OAEP, Blowfish, PKCS1_v1_5 # noqa: F401 + from Crypto.Hash import CMAC, SHA1 # noqa: F401 + from Crypto.PublicKey import RSA # noqa: F401 except ImportError: __version__ = f'broken {__version__}'.strip() -- cgit v1.2.3 From 98ac902c4979e4529b166e873473bef42baa2e3e Mon Sep 17 00:00:00 2001 From: pukkandan Date: Mon, 13 Mar 2023 05:19:13 +0530 Subject: [dependencies/Cryptodome] Fix `__bool__` Bug in 65f6e807804d2af5e00f2aecd72bfc43af19324a --- yt_dlp/dependencies/Cryptodome.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'yt_dlp/dependencies') diff --git a/yt_dlp/dependencies/Cryptodome.py b/yt_dlp/dependencies/Cryptodome.py index 74ab6575c..2cfa4c952 100644 --- a/yt_dlp/dependencies/Cryptodome.py +++ b/yt_dlp/dependencies/Cryptodome.py @@ -1,4 +1,4 @@ -import types +from ..compat.compat_utils import passthrough_module try: import Cryptodome as _parent @@ -6,9 +6,11 @@ except ImportError: try: import Crypto as _parent except (ImportError, SyntaxError): # Old Crypto gives SyntaxError in newer Python - _parent = types.ModuleType('no_Cryptodome') + _parent = passthrough_module(__name__, 'no_Cryptodome') __bool__ = lambda: False +del passthrough_module + __version__ = '' AES = PKCS1_v1_5 = Blowfish = PKCS1_OAEP = SHA1 = CMAC = RSA = None try: -- cgit v1.2.3