diff options
author | Jesús <heckyel@hyperbola.info> | 2022-12-01 23:33:30 +0800 |
---|---|---|
committer | Jesús <heckyel@hyperbola.info> | 2022-12-01 23:33:30 +0800 |
commit | ef1a420d6de7876b7b6732abc8ab78351c5a2bfc (patch) | |
tree | 9ba7d8409aa5baa696f5fb10db5d395c2f050276 /devscripts | |
parent | 16e8548f6a720a78679e417a20a300db2036bf6c (diff) | |
parent | ddf1e22d48530819d60220d0bdc36e20f5b8483b (diff) | |
download | hypervideo-pre-ef1a420d6de7876b7b6732abc8ab78351c5a2bfc.tar.lz hypervideo-pre-ef1a420d6de7876b7b6732abc8ab78351c5a2bfc.tar.xz hypervideo-pre-ef1a420d6de7876b7b6732abc8ab78351c5a2bfc.zip |
update from upstream 2022-12-01 UTC+8
Diffstat (limited to 'devscripts')
-rw-r--r-- | devscripts/__init__.py | 1 | ||||
-rw-r--r-- | devscripts/lazy_load_template.py | 15 | ||||
-rw-r--r-- | devscripts/make_lazy_extractors.py | 42 | ||||
-rw-r--r-- | devscripts/make_readme.py | 27 | ||||
-rw-r--r-- | devscripts/make_supportedsites.py | 12 | ||||
-rw-r--r-- | devscripts/prepare_manpage.py | 41 | ||||
-rwxr-xr-x | devscripts/run_tests.sh | 8 | ||||
-rw-r--r-- | devscripts/set-variant.py | 36 | ||||
-rw-r--r-- | devscripts/utils.py | 35 |
9 files changed, 148 insertions, 69 deletions
diff --git a/devscripts/__init__.py b/devscripts/__init__.py new file mode 100644 index 000000000..750dbdca7 --- /dev/null +++ b/devscripts/__init__.py @@ -0,0 +1 @@ +# Empty file needed to make devscripts.utils properly importable from outside diff --git a/devscripts/lazy_load_template.py b/devscripts/lazy_load_template.py index cdafaf1ef..c8815e01b 100644 --- a/devscripts/lazy_load_template.py +++ b/devscripts/lazy_load_template.py @@ -9,14 +9,19 @@ from ..utils import ( write_string, ) +# These bloat the lazy_extractors, so allow them to passthrough silently +ALLOWED_CLASSMETHODS = {'extract_from_webpage', 'get_testcases', 'get_webpage_testcases'} +_WARNED = False + class LazyLoadMetaClass(type): def __getattr__(cls, name): - # "_TESTS" bloat the lazy_extractors - if '_real_class' not in cls.__dict__ and name != 'get_testcases': - write_string( - 'WARNING: Falling back to normal extractor since lazy extractor ' - f'{cls.__name__} does not have attribute {name}{bug_reports_message()}\n') + global _WARNED + if ('_real_class' not in cls.__dict__ + and name not in ALLOWED_CLASSMETHODS and not _WARNED): + _WARNED = True + write_string('WARNING: Falling back to normal extractor since lazy extractor ' + f'{cls.__name__} does not have attribute {name}{bug_reports_message()}\n') return getattr(cls.real_class, name) diff --git a/devscripts/make_lazy_extractors.py b/devscripts/make_lazy_extractors.py index 785d66a6a..c502bdf89 100644 --- a/devscripts/make_lazy_extractors.py +++ b/devscripts/make_lazy_extractors.py @@ -2,34 +2,39 @@ # Allow direct execution import os +import shutil import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -import optparse from inspect import getsource +from devscripts.utils import get_filename_args, read_file, write_file + NO_ATTR = object() -STATIC_CLASS_PROPERTIES = ['IE_NAME', 'IE_DESC', 'SEARCH_KEY', '_WORKING', '_NETRC_MACHINE', 'age_limit'] +STATIC_CLASS_PROPERTIES = [ + 'IE_NAME', '_ENABLED', '_VALID_URL', # Used for URL matching + '_WORKING', 'IE_DESC', '_NETRC_MACHINE', 'SEARCH_KEY', # Used for --extractor-descriptions + 'age_limit', # Used for --age-limit (evaluated) + '_RETURN_TYPE', # Accessed in CLI only with instance (evaluated) +] CLASS_METHODS = [ - 'ie_key', 'working', 'description', 'suitable', '_match_valid_url', '_match_id', 'get_temp_id', 'is_suitable' + 'ie_key', 'suitable', '_match_valid_url', # Used for URL matching + 'working', 'get_temp_id', '_match_id', # Accessed just before instance creation + 'description', # Used for --extractor-descriptions + 'is_suitable', # Used for --age-limit + 'supports_login', 'is_single_video', # Accessed in CLI only with instance ] IE_TEMPLATE = ''' class {name}({bases}): _module = {module!r} ''' -with open('devscripts/lazy_load_template.py', encoding='utf-8') as f: - MODULE_TEMPLATE = f.read() +MODULE_TEMPLATE = read_file('devscripts/lazy_load_template.py') def main(): - parser = optparse.OptionParser(usage='%prog [OUTFILE.py]') - args = parser.parse_args()[1] or ['yt_dlp/extractor/lazy_extractors.py'] - if len(args) != 1: - parser.error('Expected only an output filename') - - lazy_extractors_filename = args[0] + lazy_extractors_filename = get_filename_args(default_outfile='yt_dlp/extractor/lazy_extractors.py') if os.path.exists(lazy_extractors_filename): os.remove(lazy_extractors_filename) @@ -46,20 +51,20 @@ def main(): *build_ies(_ALL_CLASSES, (InfoExtractor, SearchInfoExtractor), DummyInfoExtractor), )) - with open(lazy_extractors_filename, 'wt', encoding='utf-8') as f: - f.write(f'{module_src}\n') + write_file(lazy_extractors_filename, f'{module_src}\n') def get_all_ies(): PLUGINS_DIRNAME = 'ytdlp_plugins' BLOCKED_DIRNAME = f'{PLUGINS_DIRNAME}_blocked' if os.path.exists(PLUGINS_DIRNAME): - os.rename(PLUGINS_DIRNAME, BLOCKED_DIRNAME) + # os.rename cannot be used, e.g. in Docker. See https://github.com/yt-dlp/yt-dlp/pull/4958 + shutil.move(PLUGINS_DIRNAME, BLOCKED_DIRNAME) try: from yt_dlp.extractor.extractors import _ALL_CLASSES finally: if os.path.exists(BLOCKED_DIRNAME): - os.rename(BLOCKED_DIRNAME, PLUGINS_DIRNAME) + shutil.move(BLOCKED_DIRNAME, PLUGINS_DIRNAME) return _ALL_CLASSES @@ -94,7 +99,7 @@ def sort_ies(ies, ignored_bases): for c in classes[:]: bases = set(c.__bases__) - {object, *ignored_bases} restart = False - for b in bases: + for b in sorted(bases, key=lambda x: x.__name__): if b not in classes and b not in returned_classes: assert b.__name__ != 'GenericIE', 'Cannot inherit from GenericIE' classes.insert(0, b) @@ -116,11 +121,6 @@ def build_lazy_ie(ie, name, attr_base): }.get(base.__name__, base.__name__) for base in ie.__bases__) s = IE_TEMPLATE.format(name=name, module=ie.__module__, bases=bases) - valid_url = getattr(ie, '_VALID_URL', None) - if not valid_url and hasattr(ie, '_make_valid_url'): - valid_url = ie._make_valid_url() - if valid_url: - s += f' _VALID_URL = {valid_url!r}\n' return s + '\n'.join(extra_ie_code(ie, attr_base)) diff --git a/devscripts/make_readme.py b/devscripts/make_readme.py index f2e08d7c6..fad993a19 100644 --- a/devscripts/make_readme.py +++ b/devscripts/make_readme.py @@ -5,10 +5,17 @@ yt-dlp --help | make_readme.py This must be run in a console of correct width """ +# Allow direct execution +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + import functools import re -import sys + +from devscripts.utils import read_file, write_file README_FILE = 'README.md' @@ -38,6 +45,10 @@ switch_col_width = len(re.search(r'(?m)^\s{5,}', options).group()) delim = f'\n{" " * switch_col_width}' PATCHES = ( + ( # Standardize update message + r'(?m)^( -U, --update\s+).+(\n \s.+)*$', + r'\1Update this program to the latest version', + ), ( # Headings r'(?m)^ (\w.+\n)( (?=\w))?', r'## \1' @@ -63,12 +74,10 @@ PATCHES = ( ), ) -with open(README_FILE, encoding='utf-8') as f: - readme = f.read() +readme = read_file(README_FILE) -with open(README_FILE, 'w', encoding='utf-8') as f: - f.write(''.join(( - take_section(readme, end=f'## {OPTIONS_START}'), - functools.reduce(apply_patch, PATCHES, options), - take_section(readme, f'# {OPTIONS_END}'), - ))) +write_file(README_FILE, ''.join(( + take_section(readme, end=f'## {OPTIONS_START}'), + functools.reduce(apply_patch, PATCHES, options), + take_section(readme, f'# {OPTIONS_END}'), +))) diff --git a/devscripts/make_supportedsites.py b/devscripts/make_supportedsites.py index e46f7af56..01548ef97 100644 --- a/devscripts/make_supportedsites.py +++ b/devscripts/make_supportedsites.py @@ -7,21 +7,13 @@ import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -import optparse - +from devscripts.utils import get_filename_args, write_file from yt_dlp.extractor import list_extractor_classes def main(): - parser = optparse.OptionParser(usage='%prog OUTFILE.md') - _, args = parser.parse_args() - if len(args) != 1: - parser.error('Expected an output filename') - out = '\n'.join(ie.description() for ie in list_extractor_classes() if ie.IE_DESC is not False) - - with open(args[0], 'w', encoding='utf-8') as outf: - outf.write(f'# Supported sites\n{out}\n') + write_file(get_filename_args(), f'# Supported sites\n{out}\n') if __name__ == '__main__': diff --git a/devscripts/prepare_manpage.py b/devscripts/prepare_manpage.py index d12ff4947..a393d33e1 100644 --- a/devscripts/prepare_manpage.py +++ b/devscripts/prepare_manpage.py @@ -1,9 +1,22 @@ #!/usr/bin/env python3 -import optparse +# Allow direct execution +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + + import os.path import re +from devscripts.utils import ( + compose_functions, + get_filename_args, + read_file, + write_file, +) + ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) README_FILE = os.path.join(ROOT_DIR, 'README.md') @@ -22,25 +35,6 @@ yt\-dlp \- A youtube-dl fork with additional features and patches ''' -def main(): - parser = optparse.OptionParser(usage='%prog OUTFILE.md') - _, args = parser.parse_args() - if len(args) != 1: - parser.error('Expected an output filename') - - outfile, = args - - with open(README_FILE, encoding='utf-8') as f: - readme = f.read() - - readme = filter_excluded_sections(readme) - readme = move_sections(readme) - readme = filter_options(readme) - - with open(outfile, 'w', encoding='utf-8') as outf: - outf.write(PREFIX + readme) - - def filter_excluded_sections(readme): EXCLUDED_SECTION_BEGIN_STRING = re.escape('<!-- MANPAGE: BEGIN EXCLUDED SECTION -->') EXCLUDED_SECTION_END_STRING = re.escape('<!-- MANPAGE: END EXCLUDED SECTION -->') @@ -92,5 +86,12 @@ def filter_options(readme): return readme.replace(section, options, 1) +TRANSFORM = compose_functions(filter_excluded_sections, move_sections, filter_options) + + +def main(): + write_file(get_filename_args(), PREFIX + TRANSFORM(read_file(README_FILE))) + + if __name__ == '__main__': main() diff --git a/devscripts/run_tests.sh b/devscripts/run_tests.sh index d496a092b..faa642e96 100755 --- a/devscripts/run_tests.sh +++ b/devscripts/run_tests.sh @@ -1,13 +1,13 @@ #!/usr/bin/env sh -if [ -z $1 ]; then +if [ -z "$1" ]; then test_set='test' -elif [ $1 = 'core' ]; then +elif [ "$1" = 'core' ]; then test_set="-m not download" -elif [ $1 = 'download' ]; then +elif [ "$1" = 'download' ]; then test_set="-m download" else - echo 'Invalid test type "'$1'". Use "core" | "download"' + echo 'Invalid test type "'"$1"'". Use "core" | "download"' exit 1 fi diff --git a/devscripts/set-variant.py b/devscripts/set-variant.py new file mode 100644 index 000000000..10341e744 --- /dev/null +++ b/devscripts/set-variant.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +# Allow direct execution +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + + +import argparse +import functools +import re + +from devscripts.utils import compose_functions, read_file, write_file + +VERSION_FILE = 'yt_dlp/version.py' + + +def parse_options(): + parser = argparse.ArgumentParser(description='Set the build variant of the package') + parser.add_argument('variant', help='Name of the variant') + parser.add_argument('-M', '--update-message', default=None, help='Message to show in -U') + return parser.parse_args() + + +def property_setter(name, value): + return functools.partial(re.sub, rf'(?m)^{name}\s*=\s*.+$', f'{name} = {value!r}') + + +opts = parse_options() +transform = compose_functions( + property_setter('VARIANT', opts.variant), + property_setter('UPDATE_HINT', opts.update_message) +) + +write_file(VERSION_FILE, transform(read_file(VERSION_FILE))) diff --git a/devscripts/utils.py b/devscripts/utils.py new file mode 100644 index 000000000..b91b8e65a --- /dev/null +++ b/devscripts/utils.py @@ -0,0 +1,35 @@ +import argparse +import functools + + +def read_file(fname): + with open(fname, encoding='utf-8') as f: + return f.read() + + +def write_file(fname, content, mode='w'): + with open(fname, mode, encoding='utf-8') as f: + return f.write(content) + + +# Get the version without importing the package +def read_version(fname='yt_dlp/version.py'): + exec(compile(read_file(fname), fname, 'exec')) + return locals()['__version__'] + + +def get_filename_args(has_infile=False, default_outfile=None): + parser = argparse.ArgumentParser() + if has_infile: + parser.add_argument('infile', help='Input file') + kwargs = {'nargs': '?', 'default': default_outfile} if default_outfile else {} + parser.add_argument('outfile', **kwargs, help='Output file') + + opts = parser.parse_args() + if has_infile: + return opts.infile, opts.outfile + return opts.outfile + + +def compose_functions(*functions): + return lambda x: functools.reduce(lambda y, f: f(y), functions, x) |