From 6573034dcc8498f5788904e5895743318c249606 Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 16:51:21 +0200 Subject: [PATCH 01/10] Paths that have no CommentStyle are also not commentable This was a really weird design choice. Signed-off-by: Carmen Bianca BAKKER --- src/reuse/_util.py | 21 +++++++++++++++++---- src/reuse/comment.py | 4 ++++ src/reuse/header.py | 18 ++++++++++-------- src/reuse/project.py | 5 +++-- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/reuse/_util.py b/src/reuse/_util.py index d58cea386..26fe3f123 100644 --- a/src/reuse/_util.py +++ b/src/reuse/_util.py @@ -298,12 +298,25 @@ def _get_comment_style(path: StrPath) -> Optional[Type[CommentStyle]]: return style +def _is_uncommentable(path: Path) -> bool: + """*path*'s extension has the UncommentableCommentStyle.""" + return _get_comment_style(path) == UncommentableCommentStyle + + +def _has_style(path: Path) -> bool: + """*path*'s extension has a CommentStyle.""" + return _get_comment_style(path) is not None + + def _is_commentable(path: Path) -> bool: - """Determines if *path* is commentable, e.g., the file is a not a binary nor - registered as an UncommentableCommentStyle. + """Determines if *path* is commentable. Commentable files: + + - have a CommentStyle that isn't UncommentableCommentStyle; + - are not binary. """ - is_uncommentable = _get_comment_style(path) == UncommentableCommentStyle - return not (is_uncommentable or is_binary(str(path))) + return not ( + _is_uncommentable(path) or not _has_style(path) or is_binary(str(path)) + ) def merge_copyright_lines(copyright_lines: Set[str]) -> Set[str]: diff --git a/src/reuse/comment.py b/src/reuse/comment.py index aae60cb18..73880f13b 100644 --- a/src/reuse/comment.py +++ b/src/reuse/comment.py @@ -617,6 +617,8 @@ class XQueryCommentStyle(CommentStyle): ".jinja": JinjaCommentStyle, ".jinja2": JinjaCommentStyle, ".jl": JuliaCommentStyle, + ".jpg": UncommentableCommentStyle, + ".jpeg": UncommentableCommentStyle, ".js": CCommentStyle, ".json": UncommentableCommentStyle, ".jsp": AspxCommentStyle, @@ -663,6 +665,7 @@ class XQueryCommentStyle(CommentStyle): ".php5": CCommentStyle, ".pl": PythonCommentStyle, ".plantuml": PlantUmlCommentStyle, + ".png": UncommentableCommentStyle, ".po": PythonCommentStyle, ".pod": PythonCommentStyle, ".pot": PythonCommentStyle, @@ -732,6 +735,7 @@ class XQueryCommentStyle(CommentStyle): ".vsh": CCommentStyle, # V-Lang script ".vtl": VelocityCommentStyle, ".vue": HtmlCommentStyle, + ".webp": UncommentableCommentStyle, ".xls": UncommentableCommentStyle, ".xlsx": UncommentableCommentStyle, ".xml": HtmlCommentStyle, diff --git a/src/reuse/header.py b/src/reuse/header.py index 5e70dbda8..9d5b8c341 100644 --- a/src/reuse/header.py +++ b/src/reuse/header.py @@ -49,6 +49,7 @@ _determine_license_path, _determine_license_suffix_path, _get_comment_style, + _has_style, _is_commentable, contains_reuse_info, detect_line_endings, @@ -410,11 +411,7 @@ def _verify_paths_comment_style( unrecognised_files = [] for path in paths: - style = _get_comment_style(path) - commentable = _is_commentable(path) - - # TODO: This check is duplicated. - if style is None and commentable: + if not _has_style(path): unrecognised_files.append(path) if unrecognised_files: @@ -791,10 +788,15 @@ def run(args: Namespace, project: Project, out: IO[str] = sys.stdout) -> int: result = 0 for path in paths: - uncommentable = not _is_commentable(path) - if uncommentable or args.force_dot_license: + commentable = _is_commentable(path) + if not _has_style(path) and not args.force_dot_license: + # TODO: This is an awful check. + _LOGGER.debug( + _("{path} has no style, skipping it.").format(path=path) + ) + elif not commentable or args.force_dot_license: new_path = _determine_license_suffix_path(path) - if uncommentable: + if not commentable: _LOGGER.info( _( "'{path}' is a binary, therefore using '{new_path}'" diff --git a/src/reuse/project.py b/src/reuse/project.py index 356e01754..c7a68ca81 100644 --- a/src/reuse/project.py +++ b/src/reuse/project.py @@ -16,6 +16,7 @@ from pathlib import Path from typing import Dict, Iterator, List, Optional, Union, cast +from binaryornot.check import is_binary from boolean.boolean import ParseError from debian.copyright import Copyright from debian.copyright import Error as DebianError @@ -39,7 +40,7 @@ _contains_snippet, _copyright_from_dep5, _determine_license_path, - _is_commentable, + _is_uncommentable, decoded_text_from_binary, extract_reuse_info, ) @@ -187,7 +188,7 @@ def reuse_info_of(self, path: StrPath) -> List[ReuseInfo]: _("'{path}' covered by .reuse/dep5").format(path=path) ) - if not _is_commentable(path): + if _is_uncommentable(path) or is_binary(str(path)): _LOGGER.info( _( "'{path}' was detected as a binary file or its extension is" From 03da2994d042d97a5b10d39b74b324258dc15003 Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 17:07:07 +0200 Subject: [PATCH 02/10] Move stuff out of annotate's run() Signed-off-by: Carmen Bianca BAKKER --- CHANGELOG.md | 2 + src/reuse/_main.py | 2 +- src/reuse/comment.py | 2 +- src/reuse/header.py | 227 +++++++++++++++++++----------------- tests/test_main_annotate.py | 42 ------- 5 files changed, 123 insertions(+), 152 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19b371b3d..721be4b23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,8 @@ CLI command and its behaviour. There are no guarantees of stability for the ### Removed +- Removed deprecated `--explicit-license`. (#TODO) + ### Fixed - Reduced python-debian minimum version to 0.1.34. (#808) diff --git a/src/reuse/_main.py b/src/reuse/_main.py index 9d1df0395..9ecde8d06 100644 --- a/src/reuse/_main.py +++ b/src/reuse/_main.py @@ -145,7 +145,7 @@ def parser() -> argparse.ArgumentParser: " '--template mytemplate'. Read the online documentation on" " how to use this feature.\n" "\n" - "If a binary file is detected, or if --explicit-license is" + "If a binary file is detected, or if --force-dot-license is" " specified, the header is placed in a .license file." ) ), diff --git a/src/reuse/comment.py b/src/reuse/comment.py index 73880f13b..218d2305e 100644 --- a/src/reuse/comment.py +++ b/src/reuse/comment.py @@ -491,7 +491,7 @@ class TexCommentStyle(CommentStyle): class UncommentableCommentStyle(EmptyCommentStyle): """A pseudo comment style to indicate that this file is uncommentable. This - results in an external .license file as for binaries or --explicit-license. + results in an external .license file for binaries and --force-dot-license. """ diff --git a/src/reuse/header.py b/src/reuse/header.py index 9d5b8c341..c70679367 100644 --- a/src/reuse/header.py +++ b/src/reuse/header.py @@ -15,7 +15,6 @@ """Functions for manipulating the comment headers of files.""" -import argparse import datetime import logging import os @@ -542,6 +541,112 @@ def _add_header_to_file( return result +def _addheader_deprecation_warning(args: Namespace) -> None: + if "addheader" in args.parser.prog.split(): + _LOGGER.warning( + _( + "'reuse addheader' has been deprecated in favour of" + " 'reuse annotate'" + ) + ) + + +def _style_and_unrecognised_warning(args: Namespace) -> None: + if args.style is not None and args.skip_unrecognised: + _LOGGER.warning( + _( + "--skip-unrecognised has no effect when used together with" + " --style" + ) + ) + + +def _test_args(args: Namespace) -> None: + def _test_new_value_required() -> None: + if not any((args.contributor, args.copyright, args.license)): + args.parser.error( + _("option --contributor, --copyright or --license is required") + ) + + _test_new_value_required() + + +def _all_paths(args: Namespace, project: Project) -> Set[Path]: + if args.recursive: + paths: Set[Path] = set() + all_files = [path.resolve() for path in project.all_files()] + for path in args.path: + if path.is_file(): + paths.add(path) + else: + paths |= { + child + for child in all_files + if path.resolve() in child.parents + } + else: + paths = args.path + paths = {_determine_license_path(path) for path in paths} + return paths + + +def _get_template(args: Namespace, project: Project) -> Tuple[Template, bool]: + commented = False + try: + template = cast(Template, _find_template(project, args.template)) + except TemplateNotFound: + args.parser.error( + _("template {template} could not be found").format( + template=args.template + ) + ) + # This code is never reached, but mypy is not aware that + # parser.error quits the program. + raise + + if ".commented" in Path(cast(str, template.name)).suffixes: + commented = True + return template, commented + + +def _get_year(args: Namespace) -> Optional[str]: + year = None + if not args.exclude_year: + if args.year and len(args.year) > 1: + year = f"{min(args.year)} - {max(args.year)}" + elif args.year: + year = args.year.pop() + else: + year = str(datetime.date.today().year) + return year + + +def _get_reuse_info(args: Namespace, year: Optional[str]) -> ReuseInfo: + expressions = set(args.license) if args.license is not None else set() + copyright_style = ( + args.copyright_style if args.copyright_style is not None else "spdx" + ) + copyright_lines = ( + { + make_copyright_line( + item, year=year, copyright_style=copyright_style + ) + for item in args.copyright + } + if args.copyright is not None + else set() + ) + contributors = ( + set(args.contributor) if args.contributor is not None else set() + ) + + return ReuseInfo( + spdx_expressions=expressions, + copyright_lines=copyright_lines, + contributor_lines=contributors, + ) + + def _verify_write_access( paths: Iterable[StrPath], parser: ArgumentParser ) -> None: @@ -576,7 +681,8 @@ def add_arguments(parser: ArgumentParser) -> None: type=str, help=_("file contributor, repeatable"), ) - parser.add_argument( + year_mutex_group = parser.add_mutually_exclusive_group() + year_mutex_group.add_argument( "--year", "-y", action="append", @@ -604,7 +710,7 @@ def add_arguments(parser: ArgumentParser) -> None: type=str, help=_("name of template to use, optional"), ) - parser.add_argument( + year_mutex_group.add_argument( "--exclude-year", action="store_true", help=_("do not include year in statement"), @@ -614,21 +720,17 @@ def add_arguments(parser: ArgumentParser) -> None: action="store_true", help=_("merge copyright lines if copyright statements are identical"), ) - parser.add_argument( + line_mutex_group = parser.add_mutually_exclusive_group() + line_mutex_group.add_argument( "--single-line", action="store_true", help=_("force single-line comment style, optional"), ) - parser.add_argument( + line_mutex_group.add_argument( "--multi-line", action="store_true", help=_("force multi-line comment style, optional"), ) - parser.add_argument( - "--explicit-license", - action="store_true", - help=argparse.SUPPRESS, - ) parser.add_argument( "--force-dot-license", action="store_true", @@ -664,62 +766,13 @@ def add_arguments(parser: ArgumentParser) -> None: def run(args: Namespace, project: Project, out: IO[str] = sys.stdout) -> int: """Add headers to files.""" - # pylint: disable=too-many-branches,too-many-locals,too-many-statements - if "addheader" in args.parser.prog.split(): - _LOGGER.warning( - _( - "'reuse addheader' has been deprecated in favour of" - " 'reuse annotate'" - ) - ) + _addheader_deprecation_warning(args) - if not any((args.contributor, args.copyright, args.license)): - args.parser.error( - _("option --contributor, --copyright or --license is required") - ) - - if args.exclude_year and args.year: - args.parser.error( - _("option --exclude-year and --year are mutually exclusive") - ) + _test_args(args) - if args.single_line and args.multi_line: - args.parser.error( - _("option --single-line and --multi-line are mutually exclusive") - ) + _style_and_unrecognised_warning(args) - if args.style is not None and args.skip_unrecognised: - _LOGGER.warning( - _( - "--skip-unrecognised has no effect when used together with" - " --style" - ) - ) - if args.explicit_license: - _LOGGER.warning( - _( - "--explicit-license has been deprecated in favour of" - " --force-dot-license" - ) - ) - args.force_dot_license = True - - if args.recursive: - paths: Set[Path] = set() - all_files = [path.resolve() for path in project.all_files()] - for path in args.path: - if path.is_file(): - paths.add(path) - else: - paths |= { - child - for child in all_files - if path.resolve() in child.parents - } - else: - paths = args.path - - paths = {_determine_license_path(path) for path in paths} + paths = _all_paths(args, project) if not args.force_dot_license: _verify_write_access(paths, args.parser) @@ -738,53 +791,11 @@ def run(args: Namespace, project: Project, out: IO[str] = sys.stdout) -> int: template: Optional[Template] = None commented = False if args.template: - try: - template = cast(Template, _find_template(project, args.template)) - except TemplateNotFound: - args.parser.error( - _("template {template} could not be found").format( - template=args.template - ) - ) - # This code is never reached, but mypy is not aware that - # parser.error quits the program. - raise + template, commented = _get_template(args, project) - if ".commented" in Path(cast(str, template.name)).suffixes: - commented = True + year = _get_year(args) - year = None - if not args.exclude_year: - if args.year and len(args.year) > 1: - year = f"{min(args.year)} - {max(args.year)}" - elif args.year: - year = args.year.pop() - else: - year = str(datetime.date.today().year) - - expressions = set(args.license) if args.license is not None else set() - copyright_style = ( - args.copyright_style if args.copyright_style is not None else "spdx" - ) - copyright_lines = ( - { - make_copyright_line( - item, year=year, copyright_style=copyright_style - ) - for item in args.copyright - } - if args.copyright is not None - else set() - ) - contributors = ( - set(args.contributor) if args.contributor is not None else set() - ) - - reuse_info = ReuseInfo( - spdx_expressions=expressions, - copyright_lines=copyright_lines, - contributor_lines=contributors, - ) + reuse_info = _get_reuse_info(args, year) result = 0 for path in paths: diff --git a/tests/test_main_annotate.py b/tests/test_main_annotate.py index d054fa086..a95b49aa2 100644 --- a/tests/test_main_annotate.py +++ b/tests/test_main_annotate.py @@ -818,48 +818,6 @@ def test_annotate_force_dot_license(fake_repository, stringio, mock_date_today): assert simple_file.read_text() == "pass" -def test_annotate_force_dot_license_identical_to_explicit_license( - fake_repository, stringio, mock_date_today -): - """For backwards compatibility, --force-dot-license should have identical - results as --explicit-license. - """ - files = [ - fake_repository / "foo.py", - fake_repository / "bar.py", - ] - for path in files: - path.write_text("pass") - expected = cleandoc( - """ - SPDX-FileCopyrightText: 2018 Jane Doe - - SPDX-License-Identifier: GPL-3.0-or-later - """ - ) - - for arg, path in zip(("--force-dot-license", "--explicit-license"), files): - main( - [ - "annotate", - "--license", - "GPL-3.0-or-later", - "--copyright", - "Jane Doe", - arg, - str(path), - ], - out=stringio, - ) - - for path in files: - assert ( - path.with_name(f"{path.name}.license").read_text().strip() - == expected - ) - assert path.read_text() == "pass" - - def test_annotate_force_dot_license_double( fake_repository, stringio, mock_date_today ): From c2b194b98a3441435447286622c005cfddea11f7 Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 19:17:39 +0200 Subject: [PATCH 03/10] Refactor CLI parts of header.py into annotate.py Signed-off-by: Carmen Bianca BAKKER --- src/reuse/_main.py | 10 +- src/reuse/annotate.py | 505 ++++++++++++++++++++++++++++++++++++++++++ src/reuse/header.py | 492 +--------------------------------------- 3 files changed, 512 insertions(+), 495 deletions(-) create mode 100644 src/reuse/annotate.py diff --git a/src/reuse/_main.py b/src/reuse/_main.py index 9ecde8d06..5c0cf0ca8 100644 --- a/src/reuse/_main.py +++ b/src/reuse/_main.py @@ -16,8 +16,8 @@ from . import ( __REUSE_version__, __version__, + annotate, download, - header, init, lint, spdx, @@ -108,8 +108,8 @@ def parser() -> argparse.ArgumentParser: add_command( subparsers, "annotate", - header.add_arguments, - header.run, + annotate.add_arguments, + annotate.run, help=_("add copyright and licensing into the header of files"), description=fill_all( _( @@ -154,8 +154,8 @@ def parser() -> argparse.ArgumentParser: add_command( subparsers, "addheader", - header.add_arguments, - header.run, + annotate.add_arguments, + annotate.run, # TRANSLATORS: Do not translate annotate. help=_("deprecated in favor of annotate"), ) diff --git a/src/reuse/annotate.py b/src/reuse/annotate.py new file mode 100644 index 000000000..dd6669a05 --- /dev/null +++ b/src/reuse/annotate.py @@ -0,0 +1,505 @@ +# SPDX-FileCopyrightText: 2019 Free Software Foundation Europe e.V. +# SPDX-FileCopyrightText: 2019 Stefan Bakker +# SPDX-FileCopyrightText: 2019 Kirill Elagin +# SPDX-FileCopyrightText: 2020 Dmitry Bogatov +# SPDX-FileCopyrightText: © 2020 Liferay, Inc. +# SPDX-FileCopyrightText: 2021 Alvar Penning +# SPDX-FileCopyrightText: 2021 Alliander N.V. +# SPDX-FileCopyrightText: 2021 Robin Vobruba +# SPDX-FileCopyrightText: 2022 Florian Snow +# SPDX-FileCopyrightText: 2022 Yaman Qalieh +# SPDX-FileCopyrightText: 2022 Carmen Bianca Bakker +# +# SPDX-License-Identifier: GPL-3.0-or-later + +"""Functions for the CLI portion of manipulating headers.""" + +import datetime +import logging +import os +import sys +from argparse import ArgumentParser, Namespace +from gettext import gettext as _ +from pathlib import Path +from typing import IO, Iterable, Optional, Set, Tuple, Type, cast + +from jinja2 import Environment, FileSystemLoader, Template +from jinja2.exceptions import TemplateNotFound + +from . import ReuseInfo +from ._util import ( + _COPYRIGHT_STYLES, + PathType, + StrPath, + _determine_license_path, + _determine_license_suffix_path, + _get_comment_style, + _has_style, + _is_commentable, + contains_reuse_info, + detect_line_endings, + make_copyright_line, + spdx_identifier, +) +from .comment import NAME_STYLE_MAP, CommentCreateError, CommentStyle +from .header import MissingReuseInfo, add_new_header, find_and_replace_header +from .project import Project + +_LOGGER = logging.getLogger(__name__) + + +def _verify_paths_line_handling( + paths: Iterable[Path], + parser: ArgumentParser, + force_single: bool, + force_multi: bool, +) -> None: + """This function aborts the parser when *force_single* or *force_multi* is + used, but the file type does not support that type of comment style. + """ + for path in paths: + style = _get_comment_style(path) + if style is None: + continue + if force_single and not style.can_handle_single(): + parser.error( + _( + "'{path}' does not support single-line comments, please" + " do not use --single-line" + ).format(path=path) + ) + if force_multi and not style.can_handle_multi(): + parser.error( + _( + "'{path}' does not support multi-line comments, please" + " do not use --multi-line" + ).format(path=path) + ) + + +def _verify_paths_comment_style( + paths: Iterable[Path], parser: ArgumentParser +) -> None: + unrecognised_files = [] + + for path in paths: + if not _has_style(path): + unrecognised_files.append(path) + + if unrecognised_files: + parser.error( + "{}\n{}".format( + _( + "The following files do not have a recognised file" + " extension. Please use --style, --force-dot-license or" + " --skip-unrecognised:" + ), + "\n".join(str(path) for path in unrecognised_files), + ) + ) + + +def _find_template(project: Project, name: str) -> Template: + """Find a template given a name. + + Raises: + TemplateNotFound: if template could not be found. + """ + template_dir = project.root / ".reuse/templates" + env = Environment( + loader=FileSystemLoader(str(template_dir)), trim_blocks=True + ) + + names = [name] + if not name.endswith(".jinja2"): + names.append(f"{name}.jinja2") + if not name.endswith(".commented.jinja2"): + names.append(f"{name}.commented.jinja2") + + for item in names: + try: + return env.get_template(item) + except TemplateNotFound: + pass + raise TemplateNotFound(name) + + +def _add_header_to_file( + path: StrPath, + reuse_info: ReuseInfo, + template: Optional[Template], + template_is_commented: bool, + style: Optional[str], + force_multi: bool = False, + skip_existing: bool = False, + merge_copyrights: bool = False, + replace: bool = True, + out: IO[str] = sys.stdout, +) -> int: + """Helper function.""" + # pylint: disable=too-many-arguments,too-many-locals + result = 0 + if style is not None: + comment_style: Optional[Type[CommentStyle]] = NAME_STYLE_MAP.get(style) + else: + comment_style = _get_comment_style(path) + if comment_style is None: + out.write(_("Skipped unrecognised file {path}").format(path=path)) + out.write("\n") + return result + + with open(path, "r", encoding="utf-8", newline="") as fp: + text = fp.read() + + # Ideally, this check is done elsewhere. But that would necessitate reading + # the file contents before this function is called. + if skip_existing and contains_reuse_info(text): + out.write( + _( + "Skipped file '{path}' already containing REUSE information" + ).format(path=path) + ) + out.write("\n") + return result + + # Detect and remember line endings for later conversion. + line_ending = detect_line_endings(text) + # Normalise line endings. + text = text.replace(line_ending, "\n") + + try: + if replace: + output = find_and_replace_header( + text, + reuse_info, + template=template, + template_is_commented=template_is_commented, + style=comment_style, + force_multi=force_multi, + merge_copyrights=merge_copyrights, + ) + else: + output = add_new_header( + text, + reuse_info, + template=template, + template_is_commented=template_is_commented, + style=comment_style, + force_multi=force_multi, + merge_copyrights=merge_copyrights, + ) + except CommentCreateError: + out.write( + _("Error: Could not create comment for '{path}'").format(path=path) + ) + out.write("\n") + result = 1 + except MissingReuseInfo: + out.write( + _( + "Error: Generated comment header for '{path}' is missing" + " copyright lines or license expressions. The template is" + " probably incorrect. Did not write new header." + ).format(path=path) + ) + out.write("\n") + result = 1 + else: + with open(path, "w", encoding="utf-8", newline=line_ending) as fp: + fp.write(output) + # TODO: This may need to be rephrased more elegantly. + out.write(_("Successfully changed header of {path}").format(path=path)) + out.write("\n") + + return result + + +def _addheader_deprecation_warning(args: Namespace) -> None: + if "addheader" in args.parser.prog.split(): + _LOGGER.warning( + _( + "'reuse addheader' has been deprecated in favour of" + " 'reuse annotate'" + ) + ) + + +def _style_and_unrecognised_warning(args: Namespace) -> None: + if args.style is not None and args.skip_unrecognised: + _LOGGER.warning( + _( + "--skip-unrecognised has no effect when used together with" + " --style" + ) + ) + + +def _test_args(args: Namespace) -> None: + def _test_new_value_required() -> None: + if not any((args.contributor, args.copyright, args.license)): + args.parser.error( + _("option --contributor, --copyright or --license is required") + ) + + _test_new_value_required() + + +def _all_paths(args: Namespace, project: Project) -> Set[Path]: + if args.recursive: + paths: Set[Path] = set() + all_files = [path.resolve() for path in project.all_files()] + for path in args.path: + if path.is_file(): + paths.add(path) + else: + paths |= { + child + for child in all_files + if path.resolve() in child.parents + } + else: + paths = args.path + paths = {_determine_license_path(path) for path in paths} + return paths + + +def _get_template(args: Namespace, project: Project) -> Tuple[Template, bool]: + commented = False + try: + template = cast(Template, _find_template(project, args.template)) + except TemplateNotFound: + args.parser.error( + _("template {template} could not be found").format( + template=args.template + ) + ) + # This code is never reached, but mypy is not aware that + # parser.error quits the program. + raise + + if ".commented" in Path(cast(str, template.name)).suffixes: + commented = True + return template, commented + + +def _get_year(args: Namespace) -> Optional[str]: + year = None + if not args.exclude_year: + if args.year and len(args.year) > 1: + year = f"{min(args.year)} - {max(args.year)}" + elif args.year: + year = args.year.pop() + else: + year = str(datetime.date.today().year) + return year + + +def _get_reuse_info(args: Namespace, year: Optional[str]) -> ReuseInfo: + expressions = set(args.license) if args.license is not None else set() + copyright_style = ( + args.copyright_style if args.copyright_style is not None else "spdx" + ) + copyright_lines = ( + { + make_copyright_line( + item, year=year, copyright_style=copyright_style + ) + for item in args.copyright + } + if args.copyright is not None + else set() + ) + contributors = ( + set(args.contributor) if args.contributor is not None else set() + ) + + return ReuseInfo( + spdx_expressions=expressions, + copyright_lines=copyright_lines, + contributor_lines=contributors, + ) + + +def _verify_write_access( + paths: Iterable[StrPath], parser: ArgumentParser +) -> None: + not_writeable = [ + str(path) for path in paths if not os.access(path, os.W_OK) + ] + if not_writeable: + parser.error( + _("can't write to '{}'").format("', '".join(not_writeable)) + ) + + +def add_arguments(parser: ArgumentParser) -> None: + """Add arguments to parser.""" + parser.add_argument( + "--copyright", + "-c", + action="append", + type=str, + help=_("copyright statement, repeatable"), + ) + parser.add_argument( + "--license", + "-l", + action="append", + type=spdx_identifier, + help=_("SPDX Identifier, repeatable"), + ) + parser.add_argument( + "--contributor", + action="append", + type=str, + help=_("file contributor, repeatable"), + ) + year_mutex_group = parser.add_mutually_exclusive_group() + year_mutex_group.add_argument( + "--year", + "-y", + action="append", + type=str, + help=_("year of copyright statement, optional"), + ) + parser.add_argument( + "--style", + "-s", + action="store", + type=str, + choices=list(NAME_STYLE_MAP), + help=_("comment style to use, optional"), + ) + parser.add_argument( + "--copyright-style", + action="store", + choices=list(_COPYRIGHT_STYLES.keys()), + help=_("copyright style to use, optional"), + ) + parser.add_argument( + "--template", + "-t", + action="store", + type=str, + help=_("name of template to use, optional"), + ) + year_mutex_group.add_argument( + "--exclude-year", + action="store_true", + help=_("do not include year in statement"), + ) + parser.add_argument( + "--merge-copyrights", + action="store_true", + help=_("merge copyright lines if copyright statements are identical"), + ) + line_mutex_group = parser.add_mutually_exclusive_group() + line_mutex_group.add_argument( + "--single-line", + action="store_true", + help=_("force single-line comment style, optional"), + ) + line_mutex_group.add_argument( + "--multi-line", + action="store_true", + help=_("force multi-line comment style, optional"), + ) + parser.add_argument( + "--force-dot-license", + action="store_true", + help=_("write a .license file instead of a header inside the file"), + ) + parser.add_argument( + "--recursive", + "-r", + action="store_true", + help=_( + "add headers to all files under specified directories recursively" + ), + ) + parser.add_argument( + "--no-replace", + action="store_true", + help=_( + "do not replace the first header in the file; just add a new one" + ), + ) + parser.add_argument( + "--skip-unrecognised", + action="store_true", + help=_("skip files with unrecognised comment styles"), + ) + parser.add_argument( + "--skip-existing", + action="store_true", + help=_("skip files that already contain REUSE information"), + ) + parser.add_argument("path", action="store", nargs="+", type=PathType("r")) + + +def run(args: Namespace, project: Project, out: IO[str] = sys.stdout) -> int: + """Add headers to files.""" + _addheader_deprecation_warning(args) + + _test_args(args) + + _style_and_unrecognised_warning(args) + + paths = _all_paths(args, project) + + if not args.force_dot_license: + _verify_write_access(paths, args.parser) + + # Verify line handling and comment styles before proceeding + if args.style is None and not args.force_dot_license: + _verify_paths_line_handling( + paths, + args.parser, + force_single=args.single_line, + force_multi=args.multi_line, + ) + if not args.skip_unrecognised: + _verify_paths_comment_style(paths, args.parser) + + template: Optional[Template] = None + commented = False + if args.template: + template, commented = _get_template(args, project) + + year = _get_year(args) + + reuse_info = _get_reuse_info(args, year) + + result = 0 + for path in paths: + commentable = _is_commentable(path) + if not _has_style(path) and not args.force_dot_license: + # TODO: This is an awful check. + _LOGGER.debug( + _("{path} has no style, skipping it.").format(path=path) + ) + elif not commentable or args.force_dot_license: + new_path = _determine_license_suffix_path(path) + if not commentable: + _LOGGER.info( + _( + "'{path}' is a binary, therefore using '{new_path}'" + " for the header" + ).format(path=path, new_path=new_path) + ) + path = Path(new_path) + path.touch() + result += _add_header_to_file( + path=path, + reuse_info=reuse_info, + template=template, + template_is_commented=commented, + style=args.style, + force_multi=args.multi_line, + skip_existing=args.skip_existing, + merge_copyrights=args.merge_copyrights, + replace=not args.no_replace, + out=out, + ) + + return min(result, 1) diff --git a/src/reuse/header.py b/src/reuse/header.py index c70679367..9ad071c3b 100644 --- a/src/reuse/header.py +++ b/src/reuse/header.py @@ -14,58 +14,28 @@ """Functions for manipulating the comment headers of files.""" - -import datetime import logging -import os import re -import sys -from argparse import ArgumentParser, Namespace from gettext import gettext as _ -from pathlib import Path -from typing import ( - IO, - Iterable, - NamedTuple, - Optional, - Sequence, - Set, - Tuple, - Type, - cast, -) +from typing import NamedTuple, Optional, Sequence, Tuple, Type, cast from boolean.boolean import ParseError -from jinja2 import Environment, FileSystemLoader, PackageLoader, Template -from jinja2.exceptions import TemplateNotFound +from jinja2 import Environment, PackageLoader, Template from license_expression import ExpressionError from . import ReuseInfo from ._util import ( - _COPYRIGHT_STYLES, - PathType, - StrPath, - _determine_license_path, - _determine_license_suffix_path, - _get_comment_style, - _has_style, - _is_commentable, contains_reuse_info, - detect_line_endings, extract_reuse_info, - make_copyright_line, merge_copyright_lines, - spdx_identifier, ) from .comment import ( - NAME_STYLE_MAP, CommentCreateError, CommentParseError, CommentStyle, EmptyCommentStyle, PythonCommentStyle, ) -from .project import Project _LOGGER = logging.getLogger(__name__) @@ -87,7 +57,6 @@ class MissingReuseInfo(Exception): """Some REUSE information is missing from the result.""" -# TODO: Add a template here maybe. def _create_new_header( reuse_info: ReuseInfo, template: Optional[Template] = None, @@ -373,460 +342,3 @@ def add_new_header( if text.strip(): new_text = f"{new_text}\n{text.lstrip()}" return new_text - - -def _verify_paths_line_handling( - paths: Iterable[Path], - parser: ArgumentParser, - force_single: bool, - force_multi: bool, -) -> None: - """This function aborts the parser when *force_single* or *force_multi* is - used, but the file type does not support that type of comment style. - """ - for path in paths: - style = _get_comment_style(path) - if style is None: - continue - if force_single and not style.can_handle_single(): - parser.error( - _( - "'{path}' does not support single-line comments, please" - " do not use --single-line" - ).format(path=path) - ) - if force_multi and not style.can_handle_multi(): - parser.error( - _( - "'{path}' does not support multi-line comments, please" - " do not use --multi-line" - ).format(path=path) - ) - - -def _verify_paths_comment_style( - paths: Iterable[Path], parser: ArgumentParser -) -> None: - unrecognised_files = [] - - for path in paths: - if not _has_style(path): - unrecognised_files.append(path) - - if unrecognised_files: - parser.error( - "{}\n{}".format( - _( - "The following files do not have a recognised file" - " extension. Please use --style, --force-dot-license or" - " --skip-unrecognised:" - ), - "\n".join(str(path) for path in unrecognised_files), - ) - ) - - -def _find_template(project: Project, name: str) -> Template: - """Find a template given a name. - - Raises: - TemplateNotFound: if template could not be found. - """ - template_dir = project.root / ".reuse/templates" - env = Environment( - loader=FileSystemLoader(str(template_dir)), trim_blocks=True - ) - - names = [name] - if not name.endswith(".jinja2"): - names.append(f"{name}.jinja2") - if not name.endswith(".commented.jinja2"): - names.append(f"{name}.commented.jinja2") - - for item in names: - try: - return env.get_template(item) - except TemplateNotFound: - pass - raise TemplateNotFound(name) - - -def _add_header_to_file( - path: StrPath, - reuse_info: ReuseInfo, - template: Optional[Template], - template_is_commented: bool, - style: Optional[str], - force_multi: bool = False, - skip_existing: bool = False, - merge_copyrights: bool = False, - replace: bool = True, - out: IO[str] = sys.stdout, -) -> int: - """Helper function.""" - # pylint: disable=too-many-arguments,too-many-locals - result = 0 - if style is not None: - comment_style: Optional[Type[CommentStyle]] = NAME_STYLE_MAP.get(style) - else: - comment_style = _get_comment_style(path) - if comment_style is None: - out.write(_("Skipped unrecognised file {path}").format(path=path)) - out.write("\n") - return result - - with open(path, "r", encoding="utf-8", newline="") as fp: - text = fp.read() - - # Ideally, this check is done elsewhere. But that would necessitate reading - # the file contents before this function is called. - if skip_existing and contains_reuse_info(text): - out.write( - _( - "Skipped file '{path}' already containing REUSE information" - ).format(path=path) - ) - out.write("\n") - return result - - # Detect and remember line endings for later conversion. - line_ending = detect_line_endings(text) - # Normalise line endings. - text = text.replace(line_ending, "\n") - - try: - if replace: - output = find_and_replace_header( - text, - reuse_info, - template=template, - template_is_commented=template_is_commented, - style=comment_style, - force_multi=force_multi, - merge_copyrights=merge_copyrights, - ) - else: - output = add_new_header( - text, - reuse_info, - template=template, - template_is_commented=template_is_commented, - style=comment_style, - force_multi=force_multi, - merge_copyrights=merge_copyrights, - ) - except CommentCreateError: - out.write( - _("Error: Could not create comment for '{path}'").format(path=path) - ) - out.write("\n") - result = 1 - except MissingReuseInfo: - out.write( - _( - "Error: Generated comment header for '{path}' is missing" - " copyright lines or license expressions. The template is" - " probably incorrect. Did not write new header." - ).format(path=path) - ) - out.write("\n") - result = 1 - else: - with open(path, "w", encoding="utf-8", newline=line_ending) as fp: - fp.write(output) - # TODO: This may need to be rephrased more elegantly. - out.write(_("Successfully changed header of {path}").format(path=path)) - out.write("\n") - - return result - - -def _addheader_deprecation_warning(args: Namespace) -> None: - if "addheader" in args.parser.prog.split(): - _LOGGER.warning( - _( - "'reuse addheader' has been deprecated in favour of" - " 'reuse annotate'" - ) - ) - - -def _style_and_unrecognised_warning(args: Namespace) -> None: - if args.style is not None and args.skip_unrecognised: - _LOGGER.warning( - _( - "--skip-unrecognised has no effect when used together with" - " --style" - ) - ) - - -def _test_args(args: Namespace) -> None: - def _test_new_value_required() -> None: - if not any((args.contributor, args.copyright, args.license)): - args.parser.error( - _("option --contributor, --copyright or --license is required") - ) - - _test_new_value_required() - - -def _all_paths(args: Namespace, project: Project) -> Set[Path]: - if args.recursive: - paths: Set[Path] = set() - all_files = [path.resolve() for path in project.all_files()] - for path in args.path: - if path.is_file(): - paths.add(path) - else: - paths |= { - child - for child in all_files - if path.resolve() in child.parents - } - else: - paths = args.path - paths = {_determine_license_path(path) for path in paths} - return paths - - -def _get_template(args: Namespace, project: Project) -> Tuple[Template, bool]: - commented = False - try: - template = cast(Template, _find_template(project, args.template)) - except TemplateNotFound: - args.parser.error( - _("template {template} could not be found").format( - template=args.template - ) - ) - # This code is never reached, but mypy is not aware that - # parser.error quits the program. - raise - - if ".commented" in Path(cast(str, template.name)).suffixes: - commented = True - return template, commented - - -def _get_year(args: Namespace) -> Optional[str]: - year = None - if not args.exclude_year: - if args.year and len(args.year) > 1: - year = f"{min(args.year)} - {max(args.year)}" - elif args.year: - year = args.year.pop() - else: - year = str(datetime.date.today().year) - return year - - -def _get_reuse_info(args: Namespace, year: Optional[str]) -> ReuseInfo: - expressions = set(args.license) if args.license is not None else set() - copyright_style = ( - args.copyright_style if args.copyright_style is not None else "spdx" - ) - copyright_lines = ( - { - make_copyright_line( - item, year=year, copyright_style=copyright_style - ) - for item in args.copyright - } - if args.copyright is not None - else set() - ) - contributors = ( - set(args.contributor) if args.contributor is not None else set() - ) - - return ReuseInfo( - spdx_expressions=expressions, - copyright_lines=copyright_lines, - contributor_lines=contributors, - ) - - -def _verify_write_access( - paths: Iterable[StrPath], parser: ArgumentParser -) -> None: - not_writeable = [ - str(path) for path in paths if not os.access(path, os.W_OK) - ] - if not_writeable: - parser.error( - _("can't write to '{}'").format("', '".join(not_writeable)) - ) - - -def add_arguments(parser: ArgumentParser) -> None: - """Add arguments to parser.""" - parser.add_argument( - "--copyright", - "-c", - action="append", - type=str, - help=_("copyright statement, repeatable"), - ) - parser.add_argument( - "--license", - "-l", - action="append", - type=spdx_identifier, - help=_("SPDX Identifier, repeatable"), - ) - parser.add_argument( - "--contributor", - action="append", - type=str, - help=_("file contributor, repeatable"), - ) - year_mutex_group = parser.add_mutually_exclusive_group() - year_mutex_group.add_argument( - "--year", - "-y", - action="append", - type=str, - help=_("year of copyright statement, optional"), - ) - parser.add_argument( - "--style", - "-s", - action="store", - type=str, - choices=list(NAME_STYLE_MAP), - help=_("comment style to use, optional"), - ) - parser.add_argument( - "--copyright-style", - action="store", - choices=list(_COPYRIGHT_STYLES.keys()), - help=_("copyright style to use, optional"), - ) - parser.add_argument( - "--template", - "-t", - action="store", - type=str, - help=_("name of template to use, optional"), - ) - year_mutex_group.add_argument( - "--exclude-year", - action="store_true", - help=_("do not include year in statement"), - ) - parser.add_argument( - "--merge-copyrights", - action="store_true", - help=_("merge copyright lines if copyright statements are identical"), - ) - line_mutex_group = parser.add_mutually_exclusive_group() - line_mutex_group.add_argument( - "--single-line", - action="store_true", - help=_("force single-line comment style, optional"), - ) - line_mutex_group.add_argument( - "--multi-line", - action="store_true", - help=_("force multi-line comment style, optional"), - ) - parser.add_argument( - "--force-dot-license", - action="store_true", - help=_("write a .license file instead of a header inside the file"), - ) - parser.add_argument( - "--recursive", - "-r", - action="store_true", - help=_( - "add headers to all files under specified directories recursively" - ), - ) - parser.add_argument( - "--no-replace", - action="store_true", - help=_( - "do not replace the first header in the file; just add a new one" - ), - ) - parser.add_argument( - "--skip-unrecognised", - action="store_true", - help=_("skip files with unrecognised comment styles"), - ) - parser.add_argument( - "--skip-existing", - action="store_true", - help=_("skip files that already contain REUSE information"), - ) - parser.add_argument("path", action="store", nargs="+", type=PathType("r")) - - -def run(args: Namespace, project: Project, out: IO[str] = sys.stdout) -> int: - """Add headers to files.""" - _addheader_deprecation_warning(args) - - _test_args(args) - - _style_and_unrecognised_warning(args) - - paths = _all_paths(args, project) - - if not args.force_dot_license: - _verify_write_access(paths, args.parser) - - # Verify line handling and comment styles before proceeding - if args.style is None and not args.force_dot_license: - _verify_paths_line_handling( - paths, - args.parser, - force_single=args.single_line, - force_multi=args.multi_line, - ) - if not args.skip_unrecognised: - _verify_paths_comment_style(paths, args.parser) - - template: Optional[Template] = None - commented = False - if args.template: - template, commented = _get_template(args, project) - - year = _get_year(args) - - reuse_info = _get_reuse_info(args, year) - - result = 0 - for path in paths: - commentable = _is_commentable(path) - if not _has_style(path) and not args.force_dot_license: - # TODO: This is an awful check. - _LOGGER.debug( - _("{path} has no style, skipping it.").format(path=path) - ) - elif not commentable or args.force_dot_license: - new_path = _determine_license_suffix_path(path) - if not commentable: - _LOGGER.info( - _( - "'{path}' is a binary, therefore using '{new_path}'" - " for the header" - ).format(path=path, new_path=new_path) - ) - path = Path(new_path) - path.touch() - result += _add_header_to_file( - path=path, - reuse_info=reuse_info, - template=template, - template_is_commented=commented, - style=args.style, - force_multi=args.multi_line, - skip_existing=args.skip_existing, - merge_copyrights=args.merge_copyrights, - replace=not args.no_replace, - out=out, - ) - - return min(result, 1) From 4a0d0650539ec50708259ea2ba7aa39d8e1ac901 Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 19:39:49 +0200 Subject: [PATCH 04/10] Add lsp dependencies Signed-off-by: Carmen Bianca BAKKER --- poetry.lock | 467 ++++++++++++++++++++++++++++++++++++------------- pyproject.toml | 6 + 2 files changed, 353 insertions(+), 120 deletions(-) diff --git a/poetry.lock b/poetry.lock index 266b9b236..6fb3e1c12 100644 --- a/poetry.lock +++ b/poetry.lock @@ -24,7 +24,7 @@ wrapt = [ [[package]] name = "babel" -version = "2.13.0" +version = "2.13.1" description = "Internationalization utilities" category = "dev" optional = false @@ -32,6 +32,7 @@ python-versions = ">=3.7" [package.dependencies] pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} +setuptools = {version = "*", markers = "python_version >= \"3.12\""} [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] @@ -64,7 +65,7 @@ chardet = ">=3.0.2" [[package]] name = "black" -version = "23.10.0" +version = "23.10.1" description = "The uncompromising code formatter." category = "dev" optional = false @@ -127,7 +128,7 @@ python-versions = ">=3.7" [[package]] name = "charset-normalizer" -version = "3.3.0" +version = "3.3.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "dev" optional = false @@ -196,6 +197,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "docstring-to-markdown" +version = "0.13" +description = "On the fly conversion of Python docstrings to markdown" +category = "dev" +optional = false +python-versions = ">=3.6" + [[package]] name = "docutils" version = "0.20.1" @@ -244,7 +253,7 @@ sphinx-basic-ng = "*" [[package]] name = "gitdb" -version = "4.0.10" +version = "4.0.11" description = "Git Object Database" category = "dev" optional = false @@ -332,6 +341,22 @@ pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib" plugins = ["setuptools"] requirements-deprecated-finder = ["pip-api", "pipreqs"] +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + [[package]] name = "jinja2" version = "3.1.2" @@ -430,6 +455,18 @@ category = "dev" optional = false python-versions = ">=3.7" +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + [[package]] name = "pathspec" version = "0.11.2" @@ -522,6 +559,34 @@ typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\"" spelling = ["pyenchant (>=3.2,<4.0)"] testutils = ["gitpython (>3)"] +[[package]] +name = "pyls-isort" +version = "0.2.2" +description = "Isort plugin for python-lsp-server" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +isort = "*" +python-lsp-server = "*" + +[[package]] +name = "pylsp-mypy" +version = "0.6.7" +description = "Mypy linter for the Python LSP Server" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +mypy = ">=0.981" +python-lsp-server = ">=1.7.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + +[package.extras] +test = ["coverage", "pytest", "pytest-cov", "tox"] + [[package]] name = "pytest" version = "7.4.2" @@ -567,6 +632,66 @@ python-versions = ">=3.5" [package.dependencies] chardet = "*" +[[package]] +name = "python-lsp-black" +version = "1.3.0" +description = "Black plugin for the Python LSP Server" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +black = ">=22.3.0" +python-lsp-server = ">=1.4.0" +tomli = {version = "*", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["flake8", "isort (>=5.0)", "mypy", "pre-commit", "pytest", "types-pkg-resources", "types-setuptools"] + +[[package]] +name = "python-lsp-jsonrpc" +version = "1.1.2" +description = "JSON RPC 2.0 server library" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +ujson = ">=3.0.0" + +[package.extras] +test = ["coverage", "pycodestyle", "pyflakes", "pylint", "pytest", "pytest-cov"] + +[[package]] +name = "python-lsp-server" +version = "1.8.2" +description = "Python Language Server for the Language Server Protocol" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +docstring-to-markdown = "*" +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +jedi = ">=0.17.2,<0.20.0" +pluggy = ">=1.0.0" +python-lsp-jsonrpc = ">=1.1.0,<2.0.0" +ujson = ">=3.0.0" + +[package.extras] +all = ["autopep8 (>=2.0.4,<2.1.0)", "flake8 (>=6.1.0,<7)", "mccabe (>=0.7.0,<0.8.0)", "pycodestyle (>=2.11.0,<2.12.0)", "pydocstyle (>=6.3.0,<6.4.0)", "pyflakes (>=3.1.0,<3.2.0)", "pylint (>=2.5.0,<3)", "rope (>1.2.0)", "whatthepatch (>=1.0.2,<2.0.0)", "yapf (>=0.33.0)"] +autopep8 = ["autopep8 (>=1.6.0,<2.1.0)"] +flake8 = ["flake8 (>=6.1.0,<7)"] +mccabe = ["mccabe (>=0.7.0,<0.8.0)"] +pycodestyle = ["pycodestyle (>=2.11.0,<2.12.0)"] +pydocstyle = ["pydocstyle (>=6.3.0,<6.4.0)"] +pyflakes = ["pyflakes (>=3.1.0,<3.2.0)"] +pylint = ["pylint (>=2.5.0,<3)"] +rope = ["rope (>1.2.0)"] +test = ["coverage", "flaky", "matplotlib", "numpy", "pandas", "pylint (>=2.5.0,<3)", "pyqt5", "pytest", "pytest-cov"] +websockets = ["websockets (>=10.3)"] +yapf = ["whatthepatch (>=1.0.2,<2.0.0)", "yapf (>=0.33.0)"] + [[package]] name = "pytz" version = "2023.3.post1" @@ -804,6 +929,14 @@ category = "dev" optional = false python-versions = ">=3.8" +[[package]] +name = "ujson" +version = "5.8.0" +description = "Ultra fast JSON encoder and decoder for Python" +category = "dev" +optional = false +python-versions = ">=3.8" + [[package]] name = "urllib3" version = "2.0.7" @@ -820,7 +953,7 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.24.5" +version = "20.24.6" description = "Virtual Python Environment builder" category = "dev" optional = false @@ -858,7 +991,7 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "7b67415498755f0dd9a35b849c632e73109252ff99eed433c60f6fcc5fb39f2f" +content-hash = "a5460fc09f52a5cab5923b9ecb375b2c63e43ce859b0a518cb60b919b83583cc" [metadata.files] alabaster = [ @@ -870,8 +1003,8 @@ astroid = [ {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"}, ] babel = [ - {file = "Babel-2.13.0-py3-none-any.whl", hash = "sha256:fbfcae1575ff78e26c7449136f1abbefc3c13ce542eeb13d43d50d8b047216ec"}, - {file = "Babel-2.13.0.tar.gz", hash = "sha256:04c3e2d28d2b7681644508f836be388ae49e0cfe91465095340395b60d00f210"}, + {file = "Babel-2.13.1-py3-none-any.whl", hash = "sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed"}, + {file = "Babel-2.13.1.tar.gz", hash = "sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900"}, ] beautifulsoup4 = [ {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, @@ -882,24 +1015,24 @@ binaryornot = [ {file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"}, ] black = [ - {file = "black-23.10.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:f8dc7d50d94063cdfd13c82368afd8588bac4ce360e4224ac399e769d6704e98"}, - {file = "black-23.10.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:f20ff03f3fdd2fd4460b4f631663813e57dc277e37fb216463f3b907aa5a9bdd"}, - {file = "black-23.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3d9129ce05b0829730323bdcb00f928a448a124af5acf90aa94d9aba6969604"}, - {file = "black-23.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:960c21555be135c4b37b7018d63d6248bdae8514e5c55b71e994ad37407f45b8"}, - {file = "black-23.10.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:30b78ac9b54cf87bcb9910ee3d499d2bc893afd52495066c49d9ee6b21eee06e"}, - {file = "black-23.10.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:0e232f24a337fed7a82c1185ae46c56c4a6167fb0fe37411b43e876892c76699"}, - {file = "black-23.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31946ec6f9c54ed7ba431c38bc81d758970dd734b96b8e8c2b17a367d7908171"}, - {file = "black-23.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:c870bee76ad5f7a5ea7bd01dc646028d05568d33b0b09b7ecfc8ec0da3f3f39c"}, - {file = "black-23.10.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:6901631b937acbee93c75537e74f69463adaf34379a04eef32425b88aca88a23"}, - {file = "black-23.10.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:481167c60cd3e6b1cb8ef2aac0f76165843a374346aeeaa9d86765fe0dd0318b"}, - {file = "black-23.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f74892b4b836e5162aa0452393112a574dac85e13902c57dfbaaf388e4eda37c"}, - {file = "black-23.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:47c4510f70ec2e8f9135ba490811c071419c115e46f143e4dce2ac45afdcf4c9"}, - {file = "black-23.10.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:76baba9281e5e5b230c9b7f83a96daf67a95e919c2dfc240d9e6295eab7b9204"}, - {file = "black-23.10.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:a3c2ddb35f71976a4cfeca558848c2f2f89abc86b06e8dd89b5a65c1e6c0f22a"}, - {file = "black-23.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db451a3363b1e765c172c3fd86213a4ce63fb8524c938ebd82919bf2a6e28c6a"}, - {file = "black-23.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:7fb5fc36bb65160df21498d5a3dd330af8b6401be3f25af60c6ebfe23753f747"}, - {file = "black-23.10.0-py3-none-any.whl", hash = "sha256:e223b731a0e025f8ef427dd79d8cd69c167da807f5710add30cdf131f13dd62e"}, - {file = "black-23.10.0.tar.gz", hash = "sha256:31b9f87b277a68d0e99d2905edae08807c007973eaa609da5f0c62def6b7c0bd"}, + {file = "black-23.10.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69"}, + {file = "black-23.10.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916"}, + {file = "black-23.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc"}, + {file = "black-23.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173"}, + {file = "black-23.10.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0"}, + {file = "black-23.10.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace"}, + {file = "black-23.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb"}, + {file = "black-23.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce"}, + {file = "black-23.10.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a"}, + {file = "black-23.10.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1"}, + {file = "black-23.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad"}, + {file = "black-23.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884"}, + {file = "black-23.10.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9"}, + {file = "black-23.10.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7"}, + {file = "black-23.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d"}, + {file = "black-23.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982"}, + {file = "black-23.10.1-py3-none-any.whl", hash = "sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe"}, + {file = "black-23.10.1.tar.gz", hash = "sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"}, ] boolean-py = [ {file = "boolean.py-4.0-py3-none-any.whl", hash = "sha256:2876f2051d7d6394a531d82dc6eb407faa0b01a0a0b3083817ccd7323b8d96bd"}, @@ -922,96 +1055,96 @@ chardet = [ {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, ] charset-normalizer = [ - {file = "charset-normalizer-3.3.0.tar.gz", hash = "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-win32.whl", hash = "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-win32.whl", hash = "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-win32.whl", hash = "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-win32.whl", hash = "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-win32.whl", hash = "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-win32.whl", hash = "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884"}, - {file = "charset_normalizer-3.3.0-py3-none-any.whl", hash = "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2"}, + {file = "charset-normalizer-3.3.1.tar.gz", hash = "sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win32.whl", hash = "sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win32.whl", hash = "sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win32.whl", hash = "sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win32.whl", hash = "sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win32.whl", hash = "sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win32.whl", hash = "sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727"}, + {file = "charset_normalizer-3.3.1-py3-none-any.whl", hash = "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708"}, ] click = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, @@ -1087,6 +1220,10 @@ distlib = [ {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, ] +docstring-to-markdown = [ + {file = "docstring-to-markdown-0.13.tar.gz", hash = "sha256:3025c428638ececae920d6d26054546a20335af3504a145327e657e7ad7ce1ce"}, + {file = "docstring_to_markdown-0.13-py3-none-any.whl", hash = "sha256:aa487059d0883e70e54da25c7b230e918d9e4d40f23d6dfaa2b73e4225b2d7dd"}, +] docutils = [ {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, @@ -1104,8 +1241,8 @@ furo = [ {file = "furo-2023.9.10.tar.gz", hash = "sha256:5707530a476d2a63b8cad83b4f961f3739a69f4b058bcf38a03a39fa537195b2"}, ] gitdb = [ - {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, - {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, ] gitpython = [ {file = "GitPython-3.1.40-py3-none-any.whl", hash = "sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a"}, @@ -1135,6 +1272,10 @@ isort = [ {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, ] +jedi = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] jinja2 = [ {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, @@ -1288,6 +1429,10 @@ packaging = [ {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +parso = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] pathspec = [ {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, @@ -1316,6 +1461,13 @@ pylint = [ {file = "pylint-2.17.7-py3-none-any.whl", hash = "sha256:27a8d4c7ddc8c2f8c18aa0050148f89ffc09838142193fdbe98f172781a3ff87"}, {file = "pylint-2.17.7.tar.gz", hash = "sha256:f4fcac7ae74cfe36bc8451e931d8438e4a476c20314b1101c458ad0f05191fad"}, ] +pyls-isort = [ + {file = "pyls-isort-0.2.2.tar.gz", hash = "sha256:2192bd2203db00459f85eb329521feba58af63075d2dd10a051a4eccd000bba0"}, +] +pylsp-mypy = [ + {file = "pylsp-mypy-0.6.7.tar.gz", hash = "sha256:06ba6d09bdd6ec29025ccc952dd66a849361a224a9f04cebd69b9f45f7d4a064"}, + {file = "pylsp_mypy-0.6.7-py3-none-any.whl", hash = "sha256:7c50dc8bbfc45aee1efb9e7555d3bee7188c81a74098efd2e0e51ef574c8d277"}, +] pytest = [ {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, @@ -1328,6 +1480,18 @@ python-debian = [ {file = "python-debian-0.1.49.tar.gz", hash = "sha256:8cf677a30dbcb4be7a99536c17e11308a827a4d22028dc59a67f6c6dd3f0f58c"}, {file = "python_debian-0.1.49-py3-none-any.whl", hash = "sha256:880f3bc52e31599f2a9b432bd7691844286825087fccdcf2f6ffd5cd79a26f9f"}, ] +python-lsp-black = [ + {file = "python-lsp-black-1.3.0.tar.gz", hash = "sha256:5aa257e9e7b7e5a2316ef2a9fbcd242e82e0f695bf1622e31c0bf5cd69e6113f"}, + {file = "python_lsp_black-1.3.0-py3-none-any.whl", hash = "sha256:5f583b4395d8d048885974095088ab81e36e501de369cc49a621a82473bb9070"}, +] +python-lsp-jsonrpc = [ + {file = "python-lsp-jsonrpc-1.1.2.tar.gz", hash = "sha256:4688e453eef55cd952bff762c705cedefa12055c0aec17a06f595bcc002cc912"}, + {file = "python_lsp_jsonrpc-1.1.2-py3-none-any.whl", hash = "sha256:7339c2e9630ae98903fdaea1ace8c47fba0484983794d6aafd0bd8989be2b03c"}, +] +python-lsp-server = [ + {file = "python-lsp-server-1.8.2.tar.gz", hash = "sha256:fd85e1c6ad95c1d276c82a33c2c85898f110afc3c7bfeaced79c0df095076fd1"}, + {file = "python_lsp_server-1.8.2-py3-none-any.whl", hash = "sha256:65cfb20c8945bdb7b6bf7577207004e05e2550dac867339ef2e3605a0eeca9ca"}, +] pytz = [ {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, @@ -1456,13 +1620,76 @@ typing-extensions = [ {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] +ujson = [ + {file = "ujson-5.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4511560d75b15ecb367eef561554959b9d49b6ec3b8d5634212f9fed74a6df1"}, + {file = "ujson-5.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9399eaa5d1931a0ead49dce3ffacbea63f3177978588b956036bfe53cdf6af75"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4e7bb7eba0e1963f8b768f9c458ecb193e5bf6977090182e2b4f4408f35ac76"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40931d7c08c4ce99adc4b409ddb1bbb01635a950e81239c2382cfe24251b127a"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d53039d39de65360e924b511c7ca1a67b0975c34c015dd468fca492b11caa8f7"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bdf04c6af3852161be9613e458a1fb67327910391de8ffedb8332e60800147a2"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a70f776bda2e5072a086c02792c7863ba5833d565189e09fabbd04c8b4c3abba"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f26629ac531d712f93192c233a74888bc8b8212558bd7d04c349125f10199fcf"}, + {file = "ujson-5.8.0-cp310-cp310-win32.whl", hash = "sha256:7ecc33b107ae88405aebdb8d82c13d6944be2331ebb04399134c03171509371a"}, + {file = "ujson-5.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b27a8da7a080add559a3b73ec9ebd52e82cc4419f7c6fb7266e62439a055ed0"}, + {file = "ujson-5.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:193349a998cd821483a25f5df30b44e8f495423840ee11b3b28df092ddfd0f7f"}, + {file = "ujson-5.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ddeabbc78b2aed531f167d1e70387b151900bc856d61e9325fcdfefb2a51ad8"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ce24909a9c25062e60653073dd6d5e6ec9d6ad7ed6e0069450d5b673c854405"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27a2a3c7620ebe43641e926a1062bc04e92dbe90d3501687957d71b4bdddaec4"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b852bdf920fe9f84e2a2c210cc45f1b64f763b4f7d01468b33f7791698e455e"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:20768961a6a706170497129960762ded9c89fb1c10db2989c56956b162e2a8a3"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e0147d41e9fb5cd174207c4a2895c5e24813204499fd0839951d4c8784a23bf5"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e3673053b036fd161ae7a5a33358ccae6793ee89fd499000204676baafd7b3aa"}, + {file = "ujson-5.8.0-cp311-cp311-win32.whl", hash = "sha256:a89cf3cd8bf33a37600431b7024a7ccf499db25f9f0b332947fbc79043aad879"}, + {file = "ujson-5.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3659deec9ab9eb19e8646932bfe6fe22730757c4addbe9d7d5544e879dc1b721"}, + {file = "ujson-5.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:102bf31c56f59538cccdfec45649780ae00657e86247c07edac434cb14d5388c"}, + {file = "ujson-5.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:299a312c3e85edee1178cb6453645217ba23b4e3186412677fa48e9a7f986de6"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e385a7679b9088d7bc43a64811a7713cc7c33d032d020f757c54e7d41931ae"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad24ec130855d4430a682c7a60ca0bc158f8253ec81feed4073801f6b6cb681b"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16fde596d5e45bdf0d7de615346a102510ac8c405098e5595625015b0d4b5296"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6d230d870d1ce03df915e694dcfa3f4e8714369cce2346686dbe0bc8e3f135e7"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9571de0c53db5cbc265945e08f093f093af2c5a11e14772c72d8e37fceeedd08"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7cba16b26efe774c096a5e822e4f27097b7c81ed6fb5264a2b3f5fd8784bab30"}, + {file = "ujson-5.8.0-cp312-cp312-win32.whl", hash = "sha256:48c7d373ff22366eecfa36a52b9b55b0ee5bd44c2b50e16084aa88b9de038916"}, + {file = "ujson-5.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:5ac97b1e182d81cf395ded620528c59f4177eee024b4b39a50cdd7b720fdeec6"}, + {file = "ujson-5.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2a64cc32bb4a436e5813b83f5aab0889927e5ea1788bf99b930fad853c5625cb"}, + {file = "ujson-5.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e54578fa8838ddc722539a752adfce9372474114f8c127bb316db5392d942f8b"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9721cd112b5e4687cb4ade12a7b8af8b048d4991227ae8066d9c4b3a6642a582"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9707e5aacf63fb919f6237d6490c4e0244c7f8d3dc2a0f84d7dec5db7cb54c"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0be81bae295f65a6896b0c9030b55a106fb2dec69ef877253a87bc7c9c5308f7"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae7f4725c344bf437e9b881019c558416fe84ad9c6b67426416c131ad577df67"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9ab282d67ef3097105552bf151438b551cc4bedb3f24d80fada830f2e132aeb9"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94c7bd9880fa33fcf7f6d7f4cc032e2371adee3c5dba2922b918987141d1bf07"}, + {file = "ujson-5.8.0-cp38-cp38-win32.whl", hash = "sha256:bf5737dbcfe0fa0ac8fa599eceafae86b376492c8f1e4b84e3adf765f03fb564"}, + {file = "ujson-5.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:11da6bed916f9bfacf13f4fc6a9594abd62b2bb115acfb17a77b0f03bee4cfd5"}, + {file = "ujson-5.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:69b3104a2603bab510497ceabc186ba40fef38ec731c0ccaa662e01ff94a985c"}, + {file = "ujson-5.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9249fdefeb021e00b46025e77feed89cd91ffe9b3a49415239103fc1d5d9c29a"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2873d196725a8193f56dde527b322c4bc79ed97cd60f1d087826ac3290cf9207"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4dafa9010c366589f55afb0fd67084acd8added1a51251008f9ff2c3e44042"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a42baa647a50fa8bed53d4e242be61023bd37b93577f27f90ffe521ac9dc7a3"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f3554eaadffe416c6f543af442066afa6549edbc34fe6a7719818c3e72ebfe95"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fb87decf38cc82bcdea1d7511e73629e651bdec3a43ab40985167ab8449b769c"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:407d60eb942c318482bbfb1e66be093308bb11617d41c613e33b4ce5be789adc"}, + {file = "ujson-5.8.0-cp39-cp39-win32.whl", hash = "sha256:0fe1b7edaf560ca6ab023f81cbeaf9946a240876a993b8c5a21a1c539171d903"}, + {file = "ujson-5.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:3f9b63530a5392eb687baff3989d0fb5f45194ae5b1ca8276282fb647f8dcdb3"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:efeddf950fb15a832376c0c01d8d7713479fbeceaed1eaecb2665aa62c305aec"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d8283ac5d03e65f488530c43d6610134309085b71db4f675e9cf5dff96a8282"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb0142f6f10f57598655340a3b2c70ed4646cbe674191da195eb0985a9813b83"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d459aca895eb17eb463b00441986b021b9312c6c8cc1d06880925c7f51009c"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d524a8c15cfc863705991d70bbec998456a42c405c291d0f84a74ad7f35c5109"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d6f84a7a175c75beecde53a624881ff618e9433045a69fcfb5e154b73cdaa377"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b748797131ac7b29826d1524db1cc366d2722ab7afacc2ce1287cdafccddbf1f"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e72ba76313d48a1a3a42e7dc9d1db32ea93fac782ad8dde6f8b13e35c229130"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f504117a39cb98abba4153bf0b46b4954cc5d62f6351a14660201500ba31fe7f"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8c91b6f4bf23f274af9002b128d133b735141e867109487d17e344d38b87d94"}, + {file = "ujson-5.8.0.tar.gz", hash = "sha256:78e318def4ade898a461b3d92a79f9441e7e0e4d2ad5419abed4336d702c7425"}, +] urllib3 = [ {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, ] virtualenv = [ - {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, - {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, + {file = "virtualenv-20.24.6-py3-none-any.whl", hash = "sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381"}, + {file = "virtualenv-20.24.6.tar.gz", hash = "sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af"}, ] wrapt = [ {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, diff --git a/pyproject.toml b/pyproject.toml index fd17325bc..fe2915059 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,6 +76,12 @@ pylint = "^2.12.2" mypy = "^1.0" GitPython = "^3.0" +[tool.poetry.group.lsp.dependencies] +python-lsp-server = "*" +pylsp-mypy = "*" +pyls-isort = "*" +python-lsp-black = "*" + [tool.poetry.scripts] reuse = 'reuse._main:main' From 067cbef0e8e2300e6ab9b3f3eabf934586f232c3 Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 19:41:30 +0200 Subject: [PATCH 05/10] No private functions in annotate.py Signed-off-by: Carmen Bianca BAKKER --- CHANGELOG.md | 1 + src/reuse/_main.py | 9 ---- src/reuse/annotate.py | 123 ++++++++++++++++++++++-------------------- 3 files changed, 66 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 721be4b23..9a7324c8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ CLI command and its behaviour. There are no guarantees of stability for the ### Removed - Removed deprecated `--explicit-license`. (#TODO) +- Removed deprecated `addheader`. (#TODO) ### Fixed diff --git a/src/reuse/_main.py b/src/reuse/_main.py index 5c0cf0ca8..f11600c56 100644 --- a/src/reuse/_main.py +++ b/src/reuse/_main.py @@ -151,15 +151,6 @@ def parser() -> argparse.ArgumentParser: ), ) - add_command( - subparsers, - "addheader", - annotate.add_arguments, - annotate.run, - # TRANSLATORS: Do not translate annotate. - help=_("deprecated in favor of annotate"), - ) - add_command( subparsers, "download", diff --git a/src/reuse/annotate.py b/src/reuse/annotate.py index dd6669a05..b42d630f5 100644 --- a/src/reuse/annotate.py +++ b/src/reuse/annotate.py @@ -48,7 +48,7 @@ _LOGGER = logging.getLogger(__name__) -def _verify_paths_line_handling( +def verify_paths_line_handling( paths: Iterable[Path], parser: ArgumentParser, force_single: bool, @@ -77,9 +77,10 @@ def _verify_paths_line_handling( ) -def _verify_paths_comment_style( +def verify_paths_comment_style( paths: Iterable[Path], parser: ArgumentParser ) -> None: + """Raise parser.error if a style could not be found for one of the paths.""" unrecognised_files = [] for path in paths: @@ -99,7 +100,7 @@ def _verify_paths_comment_style( ) -def _find_template(project: Project, name: str) -> Template: +def find_template(project: Project, name: str) -> Template: """Find a template given a name. Raises: @@ -124,7 +125,7 @@ def _find_template(project: Project, name: str) -> Template: raise TemplateNotFound(name) -def _add_header_to_file( +def add_header_to_file( path: StrPath, reuse_info: ReuseInfo, template: Optional[Template], @@ -214,17 +215,8 @@ def _add_header_to_file( return result -def _addheader_deprecation_warning(args: Namespace) -> None: - if "addheader" in args.parser.prog.split(): - _LOGGER.warning( - _( - "'reuse addheader' has been deprecated in favour of" - " 'reuse annotate'" - ) - ) - - -def _style_and_unrecognised_warning(args: Namespace) -> None: +def style_and_unrecognised_warning(args: Namespace) -> None: + """Log a warning if --style is used together with --skip-unrecognised.""" if args.style is not None and args.skip_unrecognised: _LOGGER.warning( _( @@ -234,17 +226,19 @@ def _style_and_unrecognised_warning(args: Namespace) -> None: ) -def _test_args(args: Namespace) -> None: - def _test_new_value_required() -> None: - if not any((args.contributor, args.copyright, args.license)): - args.parser.error( - _("option --contributor, --copyright or --license is required") - ) - - _test_new_value_required() +def test_mandatory_option_required(args: Namespace) -> None: + """Raise a parser error if one of the mandatory options is not provided.""" + if not any((args.contributor, args.copyright, args.license)): + args.parser.error( + _("option --contributor, --copyright or --license is required") + ) -def _all_paths(args: Namespace, project: Project) -> Set[Path]: +def all_paths(args: Namespace, project: Project) -> Set[Path]: + """Return a set of all provided paths, converted into .license paths if they + exist. If recursive is enabled, all files belonging to *project* are also + added. + """ if args.recursive: paths: Set[Path] = set() all_files = [path.resolve() for path in project.all_files()] @@ -259,42 +253,59 @@ def _all_paths(args: Namespace, project: Project) -> Set[Path]: } else: paths = args.path - paths = {_determine_license_path(path) for path in paths} - return paths + return {_determine_license_path(path) for path in paths} -def _get_template(args: Namespace, project: Project) -> Tuple[Template, bool]: +def get_template( + args: Namespace, project: Project +) -> Tuple[Optional[Template], bool]: + """If a template is specified on the CLI, find and return it, including + whether it is a 'commented' template. + + If no template is specified, just return None. + """ + template: Optional[Template] = None commented = False - try: - template = cast(Template, _find_template(project, args.template)) - except TemplateNotFound: - args.parser.error( - _("template {template} could not be found").format( - template=args.template + if args.template: + try: + template = cast(Template, find_template(project, args.template)) + except TemplateNotFound: + args.parser.error( + _("template {template} could not be found").format( + template=args.template + ) ) - ) - # This code is never reached, but mypy is not aware that - # parser.error quits the program. - raise + # This code is never reached, but mypy is not aware that + # parser.error quits the program. + raise - if ".commented" in Path(cast(str, template.name)).suffixes: - commented = True + if ".commented" in Path(cast(str, template.name)).suffixes: + commented = True return template, commented -def _get_year(args: Namespace) -> Optional[str]: +def get_year(args: Namespace) -> Optional[str]: + """Get the year. Normally it is today's year. If --year is specified once, + get that one. If it is specified twice (or more), return the range between + the two. + + If --exclude-year is specified, return None. + """ year = None if not args.exclude_year: if args.year and len(args.year) > 1: year = f"{min(args.year)} - {max(args.year)}" elif args.year: - year = args.year.pop() + year = args.year[0] else: year = str(datetime.date.today().year) return year -def _get_reuse_info(args: Namespace, year: Optional[str]) -> ReuseInfo: +def get_reuse_info(args: Namespace, year: Optional[str]) -> ReuseInfo: + """Create a ReuseInfo object from --license, --copyright, and + --contributor. + """ expressions = set(args.license) if args.license is not None else set() copyright_style = ( args.copyright_style if args.copyright_style is not None else "spdx" @@ -320,9 +331,10 @@ def _get_reuse_info(args: Namespace, year: Optional[str]) -> ReuseInfo: ) -def _verify_write_access( +def verify_write_access( paths: Iterable[StrPath], parser: ArgumentParser ) -> None: + """Raise a parser.error if one of the paths is not writable.""" not_writeable = [ str(path) for path in paths if not os.access(path, os.W_OK) ] @@ -439,36 +451,31 @@ def add_arguments(parser: ArgumentParser) -> None: def run(args: Namespace, project: Project, out: IO[str] = sys.stdout) -> int: """Add headers to files.""" - _addheader_deprecation_warning(args) - - _test_args(args) + test_mandatory_option_required(args) - _style_and_unrecognised_warning(args) + style_and_unrecognised_warning(args) - paths = _all_paths(args, project) + paths = all_paths(args, project) if not args.force_dot_license: - _verify_write_access(paths, args.parser) + verify_write_access(paths, args.parser) # Verify line handling and comment styles before proceeding if args.style is None and not args.force_dot_license: - _verify_paths_line_handling( + verify_paths_line_handling( paths, args.parser, force_single=args.single_line, force_multi=args.multi_line, ) if not args.skip_unrecognised: - _verify_paths_comment_style(paths, args.parser) + verify_paths_comment_style(paths, args.parser) - template: Optional[Template] = None - commented = False - if args.template: - template, commented = _get_template(args, project) + template, commented = get_template(args, project) - year = _get_year(args) + year = get_year(args) - reuse_info = _get_reuse_info(args, year) + reuse_info = get_reuse_info(args, year) result = 0 for path in paths: @@ -489,7 +496,7 @@ def run(args: Namespace, project: Project, out: IO[str] = sys.stdout) -> int: ) path = Path(new_path) path.touch() - result += _add_header_to_file( + result += add_header_to_file( path=path, reuse_info=reuse_info, template=template, From ebf7de33e039466d0928446f8cd4776708c0b5ad Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 19:43:13 +0200 Subject: [PATCH 06/10] Rename annotate to _annotate Signed-off-by: Carmen Bianca BAKKER --- src/reuse/{annotate.py => _annotate.py} | 0 src/reuse/_main.py | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/reuse/{annotate.py => _annotate.py} (100%) diff --git a/src/reuse/annotate.py b/src/reuse/_annotate.py similarity index 100% rename from src/reuse/annotate.py rename to src/reuse/_annotate.py diff --git a/src/reuse/_main.py b/src/reuse/_main.py index f11600c56..cbd4afc48 100644 --- a/src/reuse/_main.py +++ b/src/reuse/_main.py @@ -16,7 +16,7 @@ from . import ( __REUSE_version__, __version__, - annotate, + _annotate, download, init, lint, @@ -108,8 +108,8 @@ def parser() -> argparse.ArgumentParser: add_command( subparsers, "annotate", - annotate.add_arguments, - annotate.run, + _annotate.add_arguments, + _annotate.run, help=_("add copyright and licensing into the header of files"), description=fill_all( _( From a4afd1fc5ef733eae6fba7cb3049c41214aa4804 Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 19:44:01 +0200 Subject: [PATCH 07/10] Remove addheader test Signed-off-by: Carmen Bianca BAKKER --- tests/test_main_annotate.py | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/tests/test_main_annotate.py b/tests/test_main_annotate.py index a95b49aa2..d4623246b 100644 --- a/tests/test_main_annotate.py +++ b/tests/test_main_annotate.py @@ -52,36 +52,6 @@ def test_annotate_simple(fake_repository, stringio, mock_date_today): assert simple_file.read_text() == expected -def test_addheader_simple(fake_repository, stringio, mock_date_today): - """Add a header to a file that does not have one.""" - simple_file = fake_repository / "foo.py" - simple_file.write_text("pass") - expected = cleandoc( - """ - # SPDX-FileCopyrightText: 2018 Jane Doe - # - # SPDX-License-Identifier: GPL-3.0-or-later - - pass - """ - ) - - result = main( - [ - "addheader", - "--license", - "GPL-3.0-or-later", - "--copyright", - "Jane Doe", - "foo.py", - ], - out=stringio, - ) - - assert result == 0 - assert simple_file.read_text() == expected - - def test_annotate_simple_no_replace(fake_repository, stringio, mock_date_today): """Add a header to a file without replacing the existing header.""" simple_file = fake_repository / "foo.py" From ceb4f004148ac3d4ffdf4baeee217b4e43b1ba80 Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 20:04:13 +0200 Subject: [PATCH 08/10] Create .license file when running against unrecognised file paths Signed-off-by: Carmen Bianca BAKKER --- CHANGELOG.md | 7 +++-- src/reuse/_annotate.py | 47 +++++++++++++------------------ tests/test_main_annotate.py | 56 ++++++++++++------------------------- 3 files changed, 41 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a7324c8e..300ad3d89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,7 +58,8 @@ CLI command and its behaviour. There are no guarantees of stability for the "[repositories] that were cloned independently and later added as a submodule or old setups", which "have the submodule's git directory inside the submodule instead of embedded into the superproject's git directory". (#687) - +- When running `annotate` on a file with an unrecognised file path, + automatically create a `.license` file. (#851) - No longer scan binary or uncommentable files for their contents in search of REUSE information. (#825) @@ -66,8 +67,8 @@ CLI command and its behaviour. There are no guarantees of stability for the ### Removed -- Removed deprecated `--explicit-license`. (#TODO) -- Removed deprecated `addheader`. (#TODO) +- Removed deprecated `--explicit-license`. (#851) +- Removed deprecated `addheader`. (#851) ### Fixed diff --git a/src/reuse/_annotate.py b/src/reuse/_annotate.py index b42d630f5..d6594d5d4 100644 --- a/src/reuse/_annotate.py +++ b/src/reuse/_annotate.py @@ -41,7 +41,12 @@ make_copyright_line, spdx_identifier, ) -from .comment import NAME_STYLE_MAP, CommentCreateError, CommentStyle +from .comment import ( + NAME_STYLE_MAP, + CommentCreateError, + CommentStyle, + EmptyCommentStyle, +) from .header import MissingReuseInfo, add_new_header, find_and_replace_header from .project import Project @@ -77,29 +82,6 @@ def verify_paths_line_handling( ) -def verify_paths_comment_style( - paths: Iterable[Path], parser: ArgumentParser -) -> None: - """Raise parser.error if a style could not be found for one of the paths.""" - unrecognised_files = [] - - for path in paths: - if not _has_style(path): - unrecognised_files.append(path) - - if unrecognised_files: - parser.error( - "{}\n{}".format( - _( - "The following files do not have a recognised file" - " extension. Please use --style, --force-dot-license or" - " --skip-unrecognised:" - ), - "\n".join(str(path) for path in unrecognised_files), - ) - ) - - def find_template(project: Project, name: str) -> Template: """Find a template given a name. @@ -133,6 +115,7 @@ def add_header_to_file( style: Optional[str], force_multi: bool = False, skip_existing: bool = False, + skip_unrecognised: bool = False, merge_copyrights: bool = False, replace: bool = True, out: IO[str] = sys.stdout, @@ -145,9 +128,18 @@ def add_header_to_file( else: comment_style = _get_comment_style(path) if comment_style is None: - out.write(_("Skipped unrecognised file {path}").format(path=path)) + if skip_unrecognised: + out.write(_("Skipped unrecognised file {path}").format(path=path)) + out.write("\n") + return result + out.write( + _("{path} is not recognised; creating {path}.license").format( + path=path + ) + ) out.write("\n") - return result + path = _determine_license_path(path) + comment_style = EmptyCommentStyle with open(path, "r", encoding="utf-8", newline="") as fp: text = fp.read() @@ -468,8 +460,6 @@ def run(args: Namespace, project: Project, out: IO[str] = sys.stdout) -> int: force_single=args.single_line, force_multi=args.multi_line, ) - if not args.skip_unrecognised: - verify_paths_comment_style(paths, args.parser) template, commented = get_template(args, project) @@ -504,6 +494,7 @@ def run(args: Namespace, project: Project, out: IO[str] = sys.stdout) -> int: style=args.style, force_multi=args.multi_line, skip_existing=args.skip_existing, + skip_unrecognised=args.skip_unrecognised, merge_copyrights=args.merge_copyrights, replace=not args.no_replace, out=out, diff --git a/tests/test_main_annotate.py b/tests/test_main_annotate.py index d4623246b..f0773953b 100644 --- a/tests/test_main_annotate.py +++ b/tests/test_main_annotate.py @@ -399,22 +399,28 @@ def test_annotate_implicit_style_filename( assert simple_file.read_text() == expected -def test_annotate_unrecognised_style(fake_repository): +def test_annotate_unrecognised_style(fake_repository, stringio): """Add a header to a file that has an unrecognised extension.""" simple_file = fake_repository / "foo.foo" simple_file.write_text("pass") - with pytest.raises(SystemExit): - main( - [ - "annotate", - "--license", - "GPL-3.0-or-later", - "--copyright", - "Jane Doe", - "foo.foo", - ] - ) + result = main( + [ + "annotate", + "--license", + "GPL-3.0-or-later", + "--copyright", + "Jane Doe", + "foo.foo", + ], + out=stringio, + ) + + assert result == 0 + assert ( + "foo.foo is not recognised; creating foo.foo.license" + in stringio.getvalue() + ) def test_annotate_skip_unrecognised(fake_repository, stringio): @@ -1267,30 +1273,4 @@ def test_annotate_recursive_on_file(fake_repository, stringio, mock_date_today): assert result == 0 -def test_annotate_recursive_contains_unrecognised( - fake_repository, stringio, mock_date_today -): - """Expect error and no edited files if at least one file has not been - recognised.""" - (fake_repository / "baz").mkdir(parents=True) - (fake_repository / "baz/foo.py").write_text("foo") - (fake_repository / "baz/bar.unknown").write_text("bar") - (fake_repository / "baz/baz.sh").write_text("baz") - - with pytest.raises(SystemExit): - main( - [ - "annotate", - "--license", - "Apache-2.0", - "--copyright", - "Jane Doe", - "--recursive", - "baz/", - ] - ) - - assert "Jane Doe" not in (fake_repository / "baz/foo.py").read_text() - - # REUSE-IgnoreEnd From b23ccdbe39ae0e501167328d59a57c1ea3bbdbb5 Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 20:10:42 +0200 Subject: [PATCH 09/10] Update versions to be in sync with the lockfile Signed-off-by: Carmen Bianca BAKKER --- .github/workflows/test.yaml | 2 +- .pre-commit-config.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8e7f0f268..db40eb628 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -97,7 +97,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install prettier - run: npm install prettier@2.7.1 + run: npm install prettier@3.0.3 - name: Run prettier run: npx prettier --check . diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cfb914c3c..2360761df 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: - repo: https://github.com/psf/black - rev: 22.8.0 + rev: 23.10.1 hooks: - id: black - repo: https://github.com/pycqa/isort @@ -20,11 +20,11 @@ repos: name: isort (pyi) types: [pyi] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.2.0 + rev: v1.6.1 hooks: - id: mypy - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.7.1 + rev: v3.0.3 hooks: - id: prettier name: prettier From 3d6351456a8d2e18e286be8db8c31a727547ff6f Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Tue, 24 Oct 2023 20:13:12 +0200 Subject: [PATCH 10/10] Run prettier on CHANGELOG.md Signed-off-by: Carmen Bianca BAKKER --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 300ad3d89..3d43bbd65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -767,8 +767,8 @@ Specification. - `reuse lint` now provides a helpful summary instead of merely spitting out non-compliant files. - `reuse compile` is now `reuse spdx`. -- In addition to `Copyright` and `©`, copyright lines can be marked with the tag - `SPDX-FileCopyrightText:`. This is the new recommended default. +- In addition to `Copyright` and `©`, copyright lines can be marked with the + tag `SPDX-FileCopyrightText:`. This is the new recommended default. - Project no longer depends on pygit2. - The list of SPDX licenses has been updated. - `Valid-License-Identifier` is no longer used, and licenses and exceptions can