Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ precommit.shell = "poe format && poe lint && poe coverage"
[tool.poetry.dependencies]
python = ">=3.8,<3.15"
requests = "*"
defusedxml = "^0.7.1"
defusedxml = { version = "^0.7.1", python = "<3.11" }

[tool.poetry.group.test]
optional = true
Expand Down Expand Up @@ -93,4 +93,4 @@ exclude_lines = [
"@abstractclassmethod",
"@abstractstaticmethod"
]
show_missing = true
show_missing = true
6 changes: 5 additions & 1 deletion youtube_transcript_api/_transcripts.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
from dataclasses import dataclass, asdict
from enum import Enum
from itertools import chain
import sys

from html import unescape
from typing import List, Dict, Iterator, Iterable, Pattern, Optional

from defusedxml import ElementTree
if sys.version_info < (3, 11):
from defusedxml import ElementTree
else:
from xml.etree import ElementTree

import re

Expand Down
39 changes: 39 additions & 0 deletions youtube_transcript_api/test/test_api.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import importlib
import pytest
import os
import sys
import types
from pathlib import Path
from unittest import TestCase
from unittest.mock import patch
from urllib.parse import urlparse, parse_qs

import requests
import responses
import youtube_transcript_api._transcripts as transcripts_module

from youtube_transcript_api import (
YouTubeTranscriptApi,
Expand Down Expand Up @@ -97,6 +101,41 @@ def test_fetch(self):
self.ref_transcript,
)

def test_fetch__uses_expected_xml_backend_for_python_version(self):
expected_backend = (
"defusedxml.ElementTree"
if sys.version_info < (3, 11)
else "xml.etree.ElementTree"
)

self.assertEqual(transcripts_module.ElementTree.__name__, expected_backend)

def test_fetch__uses_defusedxml_backend_for_python_3_10_and_older(self):
fake_element_tree = object()
fake_defusedxml = types.ModuleType("defusedxml")
fake_defusedxml.ElementTree = fake_element_tree

with patch.object(sys, "version_info", (3, 10)):
with patch.dict(sys.modules, {"defusedxml": fake_defusedxml}):
spec = importlib.util.spec_from_file_location(
"youtube_transcript_api._transcripts_py310",
transcripts_module.__file__,
)
reloaded_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(reloaded_module)

self.assertIs(reloaded_module.ElementTree, fake_element_tree)

def test_fetch__uses_stdlib_xml_backend_for_python_3_11_and_newer(self):
with patch.object(sys, "version_info", (3, 11)):
spec = importlib.util.spec_from_file_location(
"youtube_transcript_api._transcripts_py311", transcripts_module.__file__
)
reloaded_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(reloaded_module)

self.assertEqual(reloaded_module.ElementTree.__name__, "xml.etree.ElementTree")

def test_fetch_formatted(self):
transcript = YouTubeTranscriptApi().fetch(
"GJLlxj_dtq8", preserve_formatting=True
Expand Down
Loading