[cookies] Fix cookie load error handling (#11140)
[yt-dlp3.git] / pyproject.toml
blob200a9c99aefb96a4bc7090fc5017b7bbfd46abbc
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>=13.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.7.2; 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.6.0",
81 test = [
82     "pytest~=8.1",
83     "pytest-rerunfailures~=14.0",
85 pyinstaller = [
86     "pyinstaller>=6.10.0",  # Windows temp cleanup fixed in 6.10.0
88 py2exe = [
89     "py2exe>=0.12",
92 [project.urls]
93 Documentation = "https://github.com/yt-dlp/yt-dlp#readme"
94 Repository = "https://github.com/yt-dlp/yt-dlp"
95 Tracker = "https://github.com/yt-dlp/yt-dlp/issues"
96 Funding = "https://github.com/yt-dlp/yt-dlp/blob/master/Collaborators.md#collaborators"
98 [project.scripts]
99 yt-dlp = "yt_dlp:main"
101 [project.entry-points.pyinstaller40]
102 hook-dirs = "yt_dlp.__pyinstaller:get_hook_dirs"
104 [tool.hatch.build.targets.sdist]
105 include = [
106     "/yt_dlp",
107     "/devscripts",
108     "/test",
109     "/.gitignore",  # included by default, needed for auto-excludes
110     "/Changelog.md",
111     "/LICENSE",  # included as license
112     "/pyproject.toml",  # included by default
113     "/README.md",  # included as readme
114     "/setup.cfg",
115     "/supportedsites.md",
117 artifacts = [
118     "/yt_dlp/extractor/lazy_extractors.py",
119     "/completions",
120     "/AUTHORS",  # included by default
121     "/README.txt",
122     "/yt-dlp.1",
125 [tool.hatch.build.targets.wheel]
126 packages = ["yt_dlp"]
127 artifacts = ["/yt_dlp/extractor/lazy_extractors.py"]
129 [tool.hatch.build.targets.wheel.shared-data]
130 "completions/bash/yt-dlp" = "share/bash-completion/completions/yt-dlp"
131 "completions/zsh/_yt-dlp" = "share/zsh/site-functions/_yt-dlp"
132 "completions/fish/yt-dlp.fish" = "share/fish/vendor_completions.d/yt-dlp.fish"
133 "README.txt" = "share/doc/yt_dlp/README.txt"
134 "yt-dlp.1" = "share/man/man1/yt-dlp.1"
136 [tool.hatch.version]
137 path = "yt_dlp/version.py"
138 pattern = "_pkg_version = '(?P<version>[^']+)'"
140 [tool.hatch.envs.default]
141 features = ["curl-cffi", "default"]
142 dependencies = ["pre-commit"]
143 path = ".venv"
144 installer = "uv"
146 [tool.hatch.envs.default.scripts]
147 setup = "pre-commit install --config .pre-commit-hatch.yaml"
148 yt-dlp = "python -Werror -Xdev -m yt_dlp {args}"
150 [tool.hatch.envs.hatch-static-analysis]
151 detached = true
152 features = ["static-analysis"]
153 dependencies = []  # override hatch ruff version
154 config-path = "pyproject.toml"
156 [tool.hatch.envs.hatch-static-analysis.scripts]
157 format-check = "autopep8 --diff {args:.}"
158 format-fix = "autopep8 --in-place {args:.}"
159 lint-check = "ruff check {args:.}"
160 lint-fix = "ruff check --fix {args:.}"
162 [tool.hatch.envs.hatch-test]
163 features = ["test"]
164 dependencies = [
165     "pytest-randomly~=3.15",
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",