[ie/twitter:spaces] Support video spaces (#10789)
[yt-dlp3.git] / pyproject.toml
blobd5480e1c6d73f193ab8290e74b756bc5007c0f13
1 [build-system]
2 requires = ["hatchling"]
3 build-backend = "hatchling.build"
5 [project]
6 name = "yt-dlp"
7 maintainers = [
8     {name = "pukkandan", email = "pukkandan.ytdlp@gmail.com"},
9     {name = "Grub4K", email = "contact@grub4k.xyz"},
10     {name = "bashonly", email = "bashonly@protonmail.com"},
11     {name = "coletdjnz", email = "coletdjnz@protonmail.com"},
12     {name = "sepro", email = "sepro@sepr0.com"},
14 description = "A feature-rich command-line audio/video downloader"
15 readme = "README.md"
16 requires-python = ">=3.8"
17 keywords = [
18     "youtube-dl",
19     "video-downloader",
20     "youtube-downloader",
21     "sponsorblock",
22     "youtube-dlc",
23     "yt-dlp",
25 license = {file = "LICENSE"}
26 classifiers = [
27     "Topic :: Multimedia :: Video",
28     "Development Status :: 5 - Production/Stable",
29     "Environment :: Console",
30     "Programming Language :: Python",
31     "Programming Language :: Python :: 3 :: Only",
32     "Programming Language :: Python :: 3.8",
33     "Programming Language :: Python :: 3.9",
34     "Programming Language :: Python :: 3.10",
35     "Programming Language :: Python :: 3.11",
36     "Programming Language :: Python :: 3.12",
37     "Programming Language :: Python :: Implementation",
38     "Programming Language :: Python :: Implementation :: CPython",
39     "Programming Language :: Python :: Implementation :: PyPy",
40     "License :: OSI Approved :: The Unlicense (Unlicense)",
41     "Operating System :: OS Independent",
43 dynamic = ["version"]
44 dependencies = [
45     "brotli; implementation_name=='cpython'",
46     "brotlicffi; implementation_name!='cpython'",
47     "certifi",
48     "mutagen",
49     "pycryptodomex",
50     "requests>=2.32.2,<3",
51     "urllib3>=1.26.17,<3",
52     "websockets>=12.0",
55 [project.optional-dependencies]
56 default = []
57 curl-cffi = [
58     "curl-cffi==0.5.10; os_name=='nt' and implementation_name=='cpython'",
59     "curl-cffi>=0.5.10,!=0.6.*,<0.8; os_name!='nt' and implementation_name=='cpython'",
61 secretstorage = [
62     "cffi",
63     "secretstorage",
65 build = [
66     "build",
67     "hatchling",
68     "pip",
69     "setuptools>=71.0.2",  # 71.0.0 broke pyinstaller
70     "wheel",
72 dev = [
73     "pre-commit",
74     "yt-dlp[static-analysis]",
75     "yt-dlp[test]",
77 static-analysis = [
78     "autopep8~=2.0",
79     "ruff~=0.5.0",
81 test = [
82     "pytest~=8.1",
84 pyinstaller = [
85     "pyinstaller>=6.7.0",  # for compat with setuptools>=70
87 py2exe = [
88     "py2exe>=0.12",
91 [project.urls]
92 Documentation = "https://github.com/yt-dlp/yt-dlp#readme"
93 Repository = "https://github.com/yt-dlp/yt-dlp"
94 Tracker = "https://github.com/yt-dlp/yt-dlp/issues"
95 Funding = "https://github.com/yt-dlp/yt-dlp/blob/master/Collaborators.md#collaborators"
97 [project.scripts]
98 yt-dlp = "yt_dlp:main"
100 [project.entry-points.pyinstaller40]
101 hook-dirs = "yt_dlp.__pyinstaller:get_hook_dirs"
103 [tool.hatch.build.targets.sdist]
104 include = [
105     "/yt_dlp",
106     "/devscripts",
107     "/test",
108     "/.gitignore",  # included by default, needed for auto-excludes
109     "/Changelog.md",
110     "/LICENSE",  # included as license
111     "/pyproject.toml",  # included by default
112     "/README.md",  # included as readme
113     "/setup.cfg",
114     "/supportedsites.md",
116 artifacts = [
117     "/yt_dlp/extractor/lazy_extractors.py",
118     "/completions",
119     "/AUTHORS",  # included by default
120     "/README.txt",
121     "/yt-dlp.1",
124 [tool.hatch.build.targets.wheel]
125 packages = ["yt_dlp"]
126 artifacts = ["/yt_dlp/extractor/lazy_extractors.py"]
128 [tool.hatch.build.targets.wheel.shared-data]
129 "completions/bash/yt-dlp" = "share/bash-completion/completions/yt-dlp"
130 "completions/zsh/_yt-dlp" = "share/zsh/site-functions/_yt-dlp"
131 "completions/fish/yt-dlp.fish" = "share/fish/vendor_completions.d/yt-dlp.fish"
132 "README.txt" = "share/doc/yt_dlp/README.txt"
133 "yt-dlp.1" = "share/man/man1/yt-dlp.1"
135 [tool.hatch.version]
136 path = "yt_dlp/version.py"
137 pattern = "_pkg_version = '(?P<version>[^']+)'"
139 [tool.hatch.envs.default]
140 features = ["curl-cffi", "default"]
141 dependencies = ["pre-commit"]
142 path = ".venv"
143 installer = "uv"
145 [tool.hatch.envs.default.scripts]
146 setup = "pre-commit install --config .pre-commit-hatch.yaml"
147 yt-dlp = "python -Werror -Xdev -m yt_dlp {args}"
149 [tool.hatch.envs.hatch-static-analysis]
150 detached = true
151 features = ["static-analysis"]
152 dependencies = []  # override hatch ruff version
153 config-path = "pyproject.toml"
155 [tool.hatch.envs.hatch-static-analysis.scripts]
156 format-check = "autopep8 --diff {args:.}"
157 format-fix = "autopep8 --in-place {args:.}"
158 lint-check = "ruff check {args:.}"
159 lint-fix = "ruff check --fix {args:.}"
161 [tool.hatch.envs.hatch-test]
162 features = ["test"]
163 dependencies = [
164     "pytest-randomly~=3.15",
165     "pytest-rerunfailures~=14.0",
166     "pytest-xdist[psutil]~=3.5",
169 [tool.hatch.envs.hatch-test.scripts]
170 run = "python -m devscripts.run_tests {args}"
171 run-cov = "echo Code coverage not implemented && exit 1"
173 [[tool.hatch.envs.hatch-test.matrix]]
174 python = [
175     "3.8",
176     "3.9",
177     "3.10",
178     "3.11",
179     "3.12",
180     "pypy3.8",
181     "pypy3.9",
182     "pypy3.10",
185 [tool.ruff]
186 line-length = 120
188 [tool.ruff.lint]
189 ignore = [
190     "E402",    # module-import-not-at-top-of-file
191     "E501",    # line-too-long
192     "E731",    # lambda-assignment
193     "E741",    # ambiguous-variable-name
194     "UP036",   # outdated-version-block
195     "B006",    # mutable-argument-default
196     "B008",    # function-call-in-default-argument
197     "B011",    # assert-false
198     "B017",    # assert-raises-exception
199     "B023",    # function-uses-loop-variable (false positives)
200     "B028",    # no-explicit-stacklevel
201     "B904",    # raise-without-from-inside-except
202     "C401",    # unnecessary-generator-set
203     "C402",    # unnecessary-generator-dict
204     "PIE790",  # unnecessary-placeholder
205     "SIM102",  # collapsible-if
206     "SIM108",  # if-else-block-instead-of-if-exp
207     "SIM112",  # uncapitalized-environment-variables
208     "SIM113",  # enumerate-for-loop
209     "SIM114",  # if-with-same-arms
210     "SIM115",  # open-file-with-context-handler
211     "SIM117",  # multiple-with-statements
212     "SIM223",  # expr-and-false
213     "SIM300",  # yoda-conditions
214     "TD001",   # invalid-todo-tag
215     "TD002",   # missing-todo-author
216     "TD003",   # missing-todo-link
217     "PLE0604", # invalid-all-object (false positives)
218     "PLE0643", # potential-index-error (false positives)
219     "PLW0603", # global-statement
220     "PLW1510", # subprocess-run-without-check
221     "PLW2901", # redefined-loop-name
222     "RUF001",  # ambiguous-unicode-character-string
223     "RUF012",  # mutable-class-default
224     "RUF100",  # unused-noqa (flake8 has slightly different behavior)
226 select = [
227     "E",      # pycodestyle Error
228     "W",      # pycodestyle Warning
229     "F",      # Pyflakes
230     "I",      # isort
231     "Q",      # flake8-quotes
232     "N803",   # invalid-argument-name
233     "N804",   # invalid-first-argument-name-for-class-method
234     "UP",     # pyupgrade
235     "B",      # flake8-bugbear
236     "A",      # flake8-builtins
237     "COM",    # flake8-commas
238     "C4",     # flake8-comprehensions
239     "FA",     # flake8-future-annotations
240     "ISC",    # flake8-implicit-str-concat
241     "ICN003", # banned-import-from
242     "PIE",    # flake8-pie
243     "T20",    # flake8-print
244     "RSE",    # flake8-raise
245     "RET504", # unnecessary-assign
246     "SIM",    # flake8-simplify
247     "TID251", # banned-api
248     "TD",     # flake8-todos
249     "PLC",    # Pylint Convention
250     "PLE",    # Pylint Error
251     "PLW",    # Pylint Warning
252     "RUF",    # Ruff-specific rules
255 [tool.ruff.lint.per-file-ignores]
256 "devscripts/lazy_load_template.py" = [
257     "F401",   # unused-import
259 "!yt_dlp/extractor/**.py" = [
260     "I",      # isort
261     "ICN003", # banned-import-from
262     "T20",    # flake8-print
263     "A002",   # builtin-argument-shadowing
264     "C408",   # unnecessary-collection-call
266 "yt_dlp/jsinterp.py" = [
267     "UP031",  # printf-string-formatting
270 [tool.ruff.lint.isort]
271 known-first-party = [
272     "bundle",
273     "devscripts",
274     "test",
276 relative-imports-order = "closest-to-furthest"
278 [tool.ruff.lint.flake8-quotes]
279 docstring-quotes = "double"
280 multiline-quotes = "single"
281 inline-quotes = "single"
282 avoid-escape = false
284 [tool.ruff.lint.pep8-naming]
285 classmethod-decorators = [
286     "yt_dlp.utils.classproperty",
289 [tool.ruff.lint.flake8-import-conventions]
290 banned-from = [
291     "base64",
292     "datetime",
293     "functools",
294     "glob",
295     "hashlib",
296     "itertools",
297     "json",
298     "math",
299     "os",
300     "pathlib",
301     "random",
302     "re",
303     "string",
304     "sys",
305     "time",
306     "urllib.parse",
307     "uuid",
308     "xml",
311 [tool.ruff.lint.flake8-tidy-imports.banned-api]
312 "yt_dlp.compat.compat_str".msg = "Use `str` instead."
313 "yt_dlp.compat.compat_b64decode".msg = "Use `base64.b64decode` instead."
314 "yt_dlp.compat.compat_urlparse".msg = "Use `urllib.parse` instead."
315 "yt_dlp.compat.compat_parse_qs".msg = "Use `urllib.parse.parse_qs` instead."
316 "yt_dlp.compat.compat_urllib_parse_unquote".msg = "Use `urllib.parse.unquote` instead."
317 "yt_dlp.compat.compat_urllib_parse_urlencode".msg = "Use `urllib.parse.urlencode` instead."
318 "yt_dlp.compat.compat_urllib_parse_urlparse".msg = "Use `urllib.parse.urlparse` instead."
319 "yt_dlp.compat.compat_shlex_quote".msg = "Use `yt_dlp.utils.shell_quote` instead."
320 "yt_dlp.utils.error_to_compat_str".msg = "Use `str` instead."
322 [tool.autopep8]
323 max_line_length = 120
324 recursive = true
325 exit-code = true
326 jobs = 0
327 select = [
328     "E101",
329     "E112",
330     "E113",
331     "E115",
332     "E116",
333     "E117",
334     "E121",
335     "E122",
336     "E123",
337     "E124",
338     "E125",
339     "E126",
340     "E127",
341     "E128",
342     "E129",
343     "E131",
344     "E201",
345     "E202",
346     "E203",
347     "E211",
348     "E221",
349     "E222",
350     "E223",
351     "E224",
352     "E225",
353     "E226",
354     "E227",
355     "E228",
356     "E231",
357     "E241",
358     "E242",
359     "E251",
360     "E252",
361     "E261",
362     "E262",
363     "E265",
364     "E266",
365     "E271",
366     "E272",
367     "E273",
368     "E274",
369     "E275",
370     "E301",
371     "E302",
372     "E303",
373     "E304",
374     "E305",
375     "E306",
376     "E502",
377     "E701",
378     "E702",
379     "E704",
380     "W391",
381     "W504",
384 [tool.pytest.ini_options]
385 addopts = "-ra -v --strict-markers"
386 markers = [
387     "download",