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