mirror of
https://github.com/yt-dlp/yt-dlp
synced 2024-12-26 21:59:08 +01:00
[core] Fix support for upcoming Python 3.12 (#8130)
This also adds the following test runners: - `3.12-dev` on `ubuntu-latest` - `3.12-dev` on `windows-latest` - `pypy-3.10` on `ubuntu-latest` Authored by: Grub4K
This commit is contained in:
parent
94389b225d
commit
836e06d246
10 changed files with 23 additions and 16 deletions
5
.github/workflows/core.yml
vendored
5
.github/workflows/core.yml
vendored
|
@ -13,13 +13,16 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
# CPython 3.11 is in quick-test
|
# CPython 3.11 is in quick-test
|
||||||
python-version: ['3.8', '3.9', '3.10', pypy-3.7, pypy-3.8]
|
python-version: ['3.8', '3.9', '3.10', '3.12-dev', pypy-3.7, pypy-3.8, pypy-3.10]
|
||||||
run-tests-ext: [sh]
|
run-tests-ext: [sh]
|
||||||
include:
|
include:
|
||||||
# atleast one of each CPython/PyPy tests must be in windows
|
# atleast one of each CPython/PyPy tests must be in windows
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: '3.7'
|
python-version: '3.7'
|
||||||
run-tests-ext: bat
|
run-tests-ext: bat
|
||||||
|
- os: windows-latest
|
||||||
|
python-version: '3.12-dev'
|
||||||
|
run-tests-ext: bat
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: pypy-3.9
|
python-version: pypy-3.9
|
||||||
run-tests-ext: bat
|
run-tests-ext: bat
|
||||||
|
|
|
@ -10,14 +10,14 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
import argparse
|
import argparse
|
||||||
import contextlib
|
import contextlib
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from devscripts.utils import read_version, run_process, write_file
|
from devscripts.utils import read_version, run_process, write_file
|
||||||
|
|
||||||
|
|
||||||
def get_new_version(version, revision):
|
def get_new_version(version, revision):
|
||||||
if not version:
|
if not version:
|
||||||
version = datetime.utcnow().strftime('%Y.%m.%d')
|
version = datetime.now(timezone.utc).strftime('%Y.%m.%d')
|
||||||
|
|
||||||
if revision:
|
if revision:
|
||||||
assert revision.isdigit(), 'Revision must be a number'
|
assert revision.isdigit(), 'Revision must be a number'
|
||||||
|
|
|
@ -2591,7 +2591,7 @@ class YoutubeDL:
|
||||||
# Working around out-of-range timestamp values (e.g. negative ones on Windows,
|
# Working around out-of-range timestamp values (e.g. negative ones on Windows,
|
||||||
# see http://bugs.python.org/issue1646728)
|
# see http://bugs.python.org/issue1646728)
|
||||||
with contextlib.suppress(ValueError, OverflowError, OSError):
|
with contextlib.suppress(ValueError, OverflowError, OSError):
|
||||||
upload_date = datetime.datetime.utcfromtimestamp(info_dict[ts_key])
|
upload_date = datetime.datetime.fromtimestamp(info_dict[ts_key], datetime.timezone.utc)
|
||||||
info_dict[date_key] = upload_date.strftime('%Y%m%d')
|
info_dict[date_key] = upload_date.strftime('%Y%m%d')
|
||||||
|
|
||||||
live_keys = ('is_live', 'was_live')
|
live_keys = ('is_live', 'was_live')
|
||||||
|
|
|
@ -12,7 +12,7 @@ class AWSIE(InfoExtractor): # XXX: Conventionally, base classes should end with
|
||||||
|
|
||||||
def _aws_execute_api(self, aws_dict, video_id, query=None):
|
def _aws_execute_api(self, aws_dict, video_id, query=None):
|
||||||
query = query or {}
|
query = query or {}
|
||||||
amz_date = datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%SZ')
|
amz_date = datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%SZ')
|
||||||
date = amz_date[:8]
|
date = amz_date[:8]
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
|
|
@ -383,9 +383,9 @@ class AwsIdp:
|
||||||
months = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
months = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||||
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
||||||
|
|
||||||
time_now = datetime.datetime.utcnow()
|
time_now = datetime.datetime.now(datetime.timezone.utc)
|
||||||
format_string = "{} {} {} %H:%M:%S UTC %Y".format(days[time_now.weekday()], months[time_now.month], time_now.day)
|
format_string = "{} {} {} %H:%M:%S UTC %Y".format(days[time_now.weekday()], months[time_now.month], time_now.day)
|
||||||
time_string = datetime.datetime.utcnow().strftime(format_string)
|
time_string = time_now.strftime(format_string)
|
||||||
return time_string
|
return time_string
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
@ -151,7 +151,7 @@ class MotherlessIE(InfoExtractor):
|
||||||
'd': 'days',
|
'd': 'days',
|
||||||
}
|
}
|
||||||
kwargs = {_AGO_UNITS.get(uploaded_ago[-1]): delta}
|
kwargs = {_AGO_UNITS.get(uploaded_ago[-1]): delta}
|
||||||
upload_date = (datetime.datetime.utcnow() - datetime.timedelta(**kwargs)).strftime('%Y%m%d')
|
upload_date = (datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(**kwargs)).strftime('%Y%m%d')
|
||||||
|
|
||||||
comment_count = len(re.findall(r'''class\s*=\s*['"]media-comment-contents\b''', webpage))
|
comment_count = len(re.findall(r'''class\s*=\s*['"]media-comment-contents\b''', webpage))
|
||||||
uploader_id = self._html_search_regex(
|
uploader_id = self._html_search_regex(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import calendar
|
import calendar
|
||||||
import json
|
import json
|
||||||
import functools
|
import functools
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
from random import random
|
from random import random
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
|
@ -243,7 +243,7 @@ class PanoptoIE(PanoptoBaseIE):
|
||||||
invocation_id = delivery_info.get('InvocationId')
|
invocation_id = delivery_info.get('InvocationId')
|
||||||
stream_id = traverse_obj(delivery_info, ('Delivery', 'Streams', ..., 'PublicID'), get_all=False, expected_type=str)
|
stream_id = traverse_obj(delivery_info, ('Delivery', 'Streams', ..., 'PublicID'), get_all=False, expected_type=str)
|
||||||
if invocation_id and stream_id and duration:
|
if invocation_id and stream_id and duration:
|
||||||
timestamp_str = f'/Date({calendar.timegm(datetime.utcnow().timetuple())}000)/'
|
timestamp_str = f'/Date({calendar.timegm(datetime.now(timezone.utc).timetuple())}000)/'
|
||||||
data = {
|
data = {
|
||||||
'streamRequests': [
|
'streamRequests': [
|
||||||
{
|
{
|
||||||
|
|
|
@ -429,7 +429,7 @@ class UrllibRH(RequestHandler, InstanceStoreMixin):
|
||||||
except urllib.error.HTTPError as e:
|
except urllib.error.HTTPError as e:
|
||||||
if isinstance(e.fp, (http.client.HTTPResponse, urllib.response.addinfourl)):
|
if isinstance(e.fp, (http.client.HTTPResponse, urllib.response.addinfourl)):
|
||||||
# Prevent file object from being closed when urllib.error.HTTPError is destroyed.
|
# Prevent file object from being closed when urllib.error.HTTPError is destroyed.
|
||||||
e._closer.file = None
|
e._closer.close_called = True
|
||||||
raise HTTPError(UrllibResponseAdapter(e.fp), redirect_loop='redirect error' in str(e)) from e
|
raise HTTPError(UrllibResponseAdapter(e.fp), redirect_loop='redirect error' in str(e)) from e
|
||||||
raise # unexpected
|
raise # unexpected
|
||||||
except urllib.error.URLError as e:
|
except urllib.error.URLError as e:
|
||||||
|
|
|
@ -115,7 +115,7 @@ class _CompatHTTPError(urllib.error.HTTPError, HTTPError):
|
||||||
hdrs=http_error.response.headers,
|
hdrs=http_error.response.headers,
|
||||||
fp=http_error.response
|
fp=http_error.response
|
||||||
)
|
)
|
||||||
self._closer.file = None # Disable auto close
|
self._closer.close_called = True # Disable auto close
|
||||||
self._http_error = http_error
|
self._http_error = http_error
|
||||||
HTTPError.__init__(self, http_error.response, redirect_loop=http_error.redirect_loop)
|
HTTPError.__init__(self, http_error.response, redirect_loop=http_error.redirect_loop)
|
||||||
|
|
||||||
|
|
|
@ -669,6 +669,7 @@ def sanitize_filename(s, restricted=False, is_id=NO_DEFAULT):
|
||||||
|
|
||||||
def sanitize_path(s, force=False):
|
def sanitize_path(s, force=False):
|
||||||
"""Sanitizes and normalizes path on Windows"""
|
"""Sanitizes and normalizes path on Windows"""
|
||||||
|
# XXX: this handles drive relative paths (c:sth) incorrectly
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
force = False
|
force = False
|
||||||
drive_or_unc, _ = os.path.splitdrive(s)
|
drive_or_unc, _ = os.path.splitdrive(s)
|
||||||
|
@ -687,7 +688,10 @@ def sanitize_path(s, force=False):
|
||||||
sanitized_path.insert(0, drive_or_unc + os.path.sep)
|
sanitized_path.insert(0, drive_or_unc + os.path.sep)
|
||||||
elif force and s and s[0] == os.path.sep:
|
elif force and s and s[0] == os.path.sep:
|
||||||
sanitized_path.insert(0, os.path.sep)
|
sanitized_path.insert(0, os.path.sep)
|
||||||
return os.path.join(*sanitized_path)
|
# TODO: Fix behavioral differences <3.12
|
||||||
|
# The workaround using `normpath` only superficially passes tests
|
||||||
|
# Ref: https://github.com/python/cpython/pull/100351
|
||||||
|
return os.path.normpath(os.path.join(*sanitized_path))
|
||||||
|
|
||||||
|
|
||||||
def sanitize_url(url, *, scheme='http'):
|
def sanitize_url(url, *, scheme='http'):
|
||||||
|
@ -1256,7 +1260,7 @@ def datetime_from_str(date_str, precision='auto', format='%Y%m%d'):
|
||||||
if precision == 'auto':
|
if precision == 'auto':
|
||||||
auto_precision = True
|
auto_precision = True
|
||||||
precision = 'microsecond'
|
precision = 'microsecond'
|
||||||
today = datetime_round(datetime.datetime.utcnow(), precision)
|
today = datetime_round(datetime.datetime.now(datetime.timezone.utc), precision)
|
||||||
if date_str in ('now', 'today'):
|
if date_str in ('now', 'today'):
|
||||||
return today
|
return today
|
||||||
if date_str == 'yesterday':
|
if date_str == 'yesterday':
|
||||||
|
@ -1319,8 +1323,8 @@ def datetime_round(dt, precision='day'):
|
||||||
'second': 1,
|
'second': 1,
|
||||||
}
|
}
|
||||||
roundto = lambda x, n: ((x + n / 2) // n) * n
|
roundto = lambda x, n: ((x + n / 2) // n) * n
|
||||||
timestamp = calendar.timegm(dt.timetuple())
|
timestamp = roundto(calendar.timegm(dt.timetuple()), unit_seconds[precision])
|
||||||
return datetime.datetime.utcfromtimestamp(roundto(timestamp, unit_seconds[precision]))
|
return datetime.datetime.fromtimestamp(timestamp, datetime.timezone.utc)
|
||||||
|
|
||||||
|
|
||||||
def hyphenate_date(date_str):
|
def hyphenate_date(date_str):
|
||||||
|
|
Loading…
Reference in a new issue