diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 1ac5fa1..fdb27d0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8 +FROM python:3.12 RUN apt update && apt install -y vim diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69fdf6a..5a2a420 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.8', '3.9', '3.10'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v3 with: @@ -27,24 +27,17 @@ jobs: python -m pip install --upgrade pip pip install poetry poetry install - echo "CODEQL_PYTHON=$(which python)" >> $GITHUB_ENV - name: Linting run: | - poetry run flake8 + poetry run ruff check . - name: Testing run: | poetry run pytest - - name: Publish coverage - uses: codecov/codecov-action@v1 - with: - file: ./coverage.xml - fail_ci_if_error: true - verbose: true win: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.8', '3.9', '3.10'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v3 with: @@ -61,13 +54,42 @@ jobs: echo "CODEQL_PYTHON=$(which python)" >> $GITHUB_ENV - name: Linting run: | - poetry run flake8 + poetry run ruff check . - name: Testing run: | poetry run pytest - - name: Publish coverage - uses: codecov/codecov-action@v1 + + quality: + runs-on: ubuntu-latest + needs: [win, linux] + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install poetry + poetry install + - name: Linting + run: | + poetry run ruff check . + - name: Testing + run: | + poetry run pytest + - name: SonarQube Scan + uses: sonarsource/sonarqube-scan-action@v4 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + - name: SonarQube Quality Gate check + id: sonarqube-quality-gate-check + uses: sonarsource/sonarqube-quality-gate-action@master with: - file: ./coverage.xml - fail_ci_if_error: true - verbose: true + pollingTimeoutSec: 600 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7893bec..f12c09b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,7 +12,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.12' - name: Install dependencies run: | python -m pip install --upgrade pip @@ -20,7 +20,7 @@ jobs: poetry install - name: Linting run: | - poetry run flake8 + poetry run ruff check . - name: Testing run: | poetry run pytest diff --git a/.gitignore b/.gitignore index e233c53..def8a10 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,4 @@ venv.bak/ local .vscode/ +.ruff_cache \ No newline at end of file diff --git a/README.md b/README.md index 27d2ca2..a34b156 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # interrogatio -![Python versions](https://img.shields.io/pypi/pyversions/interrogatio.svg) [![PyPi Status](https://img.shields.io/pypi/v/interrogatio.svg)](https://pypi.org/project/interrogatio/) ![Read the Docs](https://img.shields.io/readthedocs/interrogatio) [![Build Status](https://img.shields.io/github/workflow/status/ffaraone/interrogatio/Build%20interrogatio)](https://github.com/ffaraone/interrogatio/actions) [![codecov](https://codecov.io/gh/ffaraone/interrogatio/branch/master/graph/badge.svg)](https://codecov.io/gh/ffaraone/interrogatio) - +![Python versions](https://img.shields.io/pypi/pyversions/interrogatio.svg) [![PyPi Status](https://img.shields.io/pypi/v/interrogatio.svg)](https://pypi.org/project/interrogatio/) ![Read the Docs](https://img.shields.io/readthedocs/interrogatio) [![Build Status](https://img.shields.io/github/workflow/status/ffaraone/interrogatio/Build%20interrogatio)](https://github.com/ffaraone/interrogatio/actions) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ffaraone_interrogatio&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ffaraone_interrogatio) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=ffaraone_interrogatio&metric=coverage)](https://sonarcloud.io/summary/new_code?id=ffaraone_interrogatio) A python library to prompt users for inputs in a terminal application. diff --git a/docs/conf.py b/docs/conf.py index 1050a85..20d77f4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # @@ -16,20 +15,20 @@ import sys from datetime import datetime -sys.path.insert(0, os.path.abspath('..')) +sys.path.insert(0, os.path.abspath("..")) # on_rtd = os.environ.get('READTHEDOCS', None) == 'True' # -- Project information ----------------------------------------------------- -project = 'interrogatio' -copyright = '{}, Francesco Faraone.'.format(datetime.now().year) -author = 'Francesco Faraone' +project = "interrogatio" +copyright = f"{datetime.now().year}, Francesco Faraone." +author = "Francesco Faraone" # The short X.Y version -version = '' +version = "" # The full version, including alpha/beta/rc tags -release = '1.0.0' +release = "1.0.0" # -- General configuration --------------------------------------------------- @@ -42,7 +41,7 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', + "sphinx.ext.autodoc", ] # if not on_rtd: # only import and set the theme if we're building docs locally @@ -52,16 +51,16 @@ # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -73,7 +72,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. pygments_style = None @@ -85,7 +84,7 @@ # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -96,7 +95,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -112,7 +111,7 @@ # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'interrogatiodoc' +htmlhelp_basename = "interrogatiodoc" # -- Options for LaTeX output ------------------------------------------------ @@ -121,15 +120,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -139,8 +135,13 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'interrogatio.tex', 'interrogatio Documentation', - 'Francesco Faraone', 'manual'), + ( + master_doc, + "interrogatio.tex", + "interrogatio Documentation", + "Francesco Faraone", + "manual", + ), ] @@ -148,10 +149,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'interrogatio', 'interrogatio Documentation', - [author], 1) -] +man_pages = [(master_doc, "interrogatio", "interrogatio Documentation", [author], 1)] # -- Options for Texinfo output ---------------------------------------------- @@ -160,9 +158,15 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'interrogatio', 'interrogatio Documentation', - author, 'interrogatio', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "interrogatio", + "interrogatio Documentation", + author, + "interrogatio", + "One line description of project.", + "Miscellaneous", + ), ] @@ -181,7 +185,7 @@ # epub_uid = '' # A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] +epub_exclude_files = ["search.html"] # -- Extension configuration ------------------------------------------------- diff --git a/interrogatio/__init__.py b/interrogatio/__init__.py index 415a03b..6fba4ee 100644 --- a/interrogatio/__init__.py +++ b/interrogatio/__init__.py @@ -1,15 +1,12 @@ -from pkg_resources import DistributionNotFound, get_distribution +from importlib_metadata import version from interrogatio.core.dialog import dialogus from interrogatio.core.prompt import interrogatio -__all__ = ('dialogus', 'interrogatio') +__all__ = ("dialogus", "interrogatio") -try: - __version__ = get_distribution('interrogatio').version -except DistributionNotFound: # pragma: no cover - __version__ = '0.0.0' +__version__ = version("interrogatio") def get_version(): diff --git a/interrogatio/core/dialog.py b/interrogatio/core/dialog.py index 3f47229..ee04b38 100644 --- a/interrogatio/core/dialog.py +++ b/interrogatio/core/dialog.py @@ -6,8 +6,7 @@ from interrogatio.themes import for_dialog, set_theme from interrogatio.widgets.wizard import WizardDialog - -__all__ = ['dialogus'] +__all__ = ["dialogus"] def show_dialog( @@ -16,19 +15,24 @@ def show_dialog( intro=None, summary=False, fast_forward=False, - next_text='Next', - previous_text='Previous', - cancel_text='Cancel', - finish_text='Finish', + next_text="Next", + previous_text="Previous", + cancel_text="Cancel", + finish_text="Finish", ): handlers = [get_instance(q) for q in questions] app = Application( layout=Layout( WizardDialog( - title, handlers, - intro=intro, summary=summary, fast_forward=fast_forward, - next_text=next_text, previous_text=previous_text, - cancel_text=cancel_text, finish_text=finish_text, + title, + handlers, + intro=intro, + summary=summary, + fast_forward=fast_forward, + next_text=next_text, + previous_text=previous_text, + cancel_text=cancel_text, + finish_text=finish_text, ), ), mouse_support=False, @@ -51,11 +55,11 @@ def dialogus( intro=None, summary=False, fast_forward=False, - next_text='Next', - previous_text='Previous', - cancel_text='Cancel', - finish_text='Finish', - theme='default', + next_text="Next", + previous_text="Previous", + cancel_text="Cancel", + finish_text="Finish", + theme="default", ): """ Show a dialog with inputs as defined in the questions parameter and returns diff --git a/interrogatio/core/exceptions.py b/interrogatio/core/exceptions.py index 857a5e7..7914506 100644 --- a/interrogatio/core/exceptions.py +++ b/interrogatio/core/exceptions.py @@ -14,8 +14,9 @@ class ValidationError(Exception): """ Exception raised when validation fails. """ + def __init__(self, message): - super(ValidationError, self).__init__() + super().__init__() self._message = message def __str__(self): diff --git a/interrogatio/core/prompt.py b/interrogatio/core/prompt.py index 6b3e03d..914ab65 100644 --- a/interrogatio/core/prompt.py +++ b/interrogatio/core/prompt.py @@ -9,11 +9,10 @@ from interrogatio.handlers import get_instance from interrogatio.themes import for_prompt, set_theme +__all__ = ["interrogatio"] -__all__ = ['interrogatio'] - -def interrogatio(questions, theme='default'): +def interrogatio(questions, theme="default"): """ Prompts user for inputs as defined in the questions parameter and returns a dictionary with the answers. @@ -83,7 +82,7 @@ def interrogatio(questions, theme='default'): break else: print_formatted_text( - FormattedText([('class:error', handler.errors[0])]), + FormattedText([("class:error", handler.errors[0])]), style=for_prompt(), ) return answers diff --git a/interrogatio/core/utils.py b/interrogatio/core/utils.py index de815dd..ed6e04d 100644 --- a/interrogatio/core/utils.py +++ b/interrogatio/core/utils.py @@ -3,67 +3,65 @@ def _validate_validator_object(obj): - if 'name' not in obj: - raise InvalidQuestionError( - 'You must specify a name for the validator.') + if "name" not in obj: + raise InvalidQuestionError("You must specify a name for the validator.") - if obj['name'] not in validators.get_registered(): + if obj["name"] not in validators.get_registered(): raise InvalidQuestionError( f'Validator {obj["name"]} does not exists.', ) - if 'args' in obj and not isinstance(obj['args'], dict): - raise InvalidQuestionError('Validator arguments must be a dictionary.') + if "args" in obj and not isinstance(obj["args"], dict): + raise InvalidQuestionError("Validator arguments must be a dictionary.") def _validate_question(q): # noqa: CCR001 + if "name" not in q: + raise InvalidQuestionError("You must specify a name for the question.") - if 'name' not in q: - raise InvalidQuestionError('You must specify a name for the question.') - - if 'type' not in q: - raise InvalidQuestionError('You must specify a question type.') + if "type" not in q: + raise InvalidQuestionError("You must specify a question type.") - q_type = q['type'] + q_type = q["type"] if q_type not in handlers.get_registered(): raise InvalidQuestionError( - f'Unsupported question type: {q_type}.', + f"Unsupported question type: {q_type}.", ) - if q_type in ('selectone', 'selectmany'): - if 'values' not in q: + if q_type in ("selectone", "selectmany"): + if "values" not in q: raise InvalidQuestionError( - 'You must specify at least one choice for type choice.', + "You must specify at least one choice for type choice.", ) - values = q['values'] + values = q["values"] if values: if not isinstance(values, (list, tuple)): if not callable(values): raise InvalidQuestionError( - 'Choices must be a list, tuple of tuples or callable.', + "Choices must be a list, tuple of tuples or callable.", ) else: first_value = values[0] if not isinstance(first_value, (list, tuple)): raise InvalidQuestionError( - 'Choices must be a list or tuple of tuples.', + "Choices must be a list or tuple of tuples.", ) if len(first_value) != 2: raise InvalidQuestionError( - 'Every choice must be a tuple (value, label).', + "Every choice must be a tuple (value, label).", ) - if 'validators' in q: - if not isinstance(q['validators'], (list, tuple)): - raise InvalidQuestionError('Validators must be a list or tuple.') + if "validators" in q: + if not isinstance(q["validators"], (list, tuple)): + raise InvalidQuestionError("Validators must be a list or tuple.") validator_instances = [] - for v in q['validators']: + for v in q["validators"]: if not isinstance(v, (validators.Validator, dict)): raise InvalidQuestionError( - 'Validators must be a list of ' - 'interrogatio.validators.Validator' - ' instances or a list of validator objects.', + "Validators must be a list of " + "interrogatio.validators.Validator" + " instances or a list of validator objects.", ) if isinstance(v, dict): @@ -72,12 +70,12 @@ def _validate_question(q): # noqa: CCR001 validator_instances.append(v) else: validator_instances.append(v) - q['validators'] = validator_instances + q["validators"] = validator_instances - if 'disabled' in q: - if not (isinstance(q['disabled'], bool) or callable(q['disabled'])): + if "disabled" in q: + if not (isinstance(q["disabled"], bool) or callable(q["disabled"])): raise InvalidQuestionError( - 'Disabled flag must be a boolean or callable.', + "Disabled flag must be a boolean or callable.", ) diff --git a/interrogatio/handlers/__init__.py b/interrogatio/handlers/__init__.py index cc64ba8..86ab33b 100644 --- a/interrogatio/handlers/__init__.py +++ b/interrogatio/handlers/__init__.py @@ -1,5 +1,7 @@ from interrogatio.handlers.base import QHandler # noqa from interrogatio.handlers.registry import ( # noqa - register, get_instance, get_registered, + register, + get_instance, + get_registered, ) from interrogatio.handlers.builtins import * # noqa diff --git a/interrogatio/handlers/base.py b/interrogatio/handlers/base.py index c82aa71..155f419 100644 --- a/interrogatio/handlers/base.py +++ b/interrogatio/handlers/base.py @@ -7,7 +7,7 @@ from interrogatio.core.exceptions import ValidationError __all__ = [ - 'QHandler', + "QHandler", ] @@ -45,7 +45,7 @@ def get_layout(self): :rtype: :class:`~prompt_toolkit.layout.Layout` """ raise NotImplementedError( - 'Subclass must implements `get_layout` method.', + "Subclass must implements `get_layout` method.", ) def get_question(self): @@ -62,7 +62,7 @@ def get_value(self): :rtype: str """ raise NotImplementedError( - 'Subclass must implements `get_value` method.', + "Subclass must implements `get_value` method.", ) def get_formatted_value(self): @@ -79,7 +79,7 @@ def get_widget_init_kwargs(self): :rtype: dict """ raise NotImplementedError( - 'Subclass must implements `get_widget_init_kwargs` method.', + "Subclass must implements `get_widget_init_kwargs` method.", ) def get_init_extra_args(self): @@ -91,7 +91,7 @@ def get_init_extra_args(self): :return: a dictionary containing the initialization extra arguments. :rtype: dict """ - return self.get_question().get('extra_args', dict()) + return self.get_question().get("extra_args", {}) @abstractmethod def get_widget_class(self): @@ -102,7 +102,7 @@ def get_widget_class(self): :rtype: class """ raise NotImplementedError( - 'Subclass must implements `get_widget_class` method.', + "Subclass must implements `get_widget_class` method.", ) def get_widget(self): @@ -141,20 +141,21 @@ def get_answer(self): Returns dictionary with the question variable as key and the answer as the value. """ - return {self.get_question()['name']: self.to_python()} + return {self.get_question()["name"]: self.to_python()} def get_variable_name(self): """ Returns the name of the variable of this question. """ - return self._question['name'] + return self._question["name"] def get_label(self): """ Returns the label of the variable of this question. """ return self._question.get( - 'label', self.get_variable_name().capitalize(), + "label", + self.get_variable_name().capitalize(), ) def is_disabled(self, context=None): @@ -162,7 +163,7 @@ def is_disabled(self, context=None): If disabled flag specified, it is evaluated if needed and returned. By default, all questions are enabled. """ - disabled = self._question.get('disabled', False) + disabled = self._question.get("disabled", False) if callable(disabled): return disabled(context) else: @@ -175,7 +176,7 @@ def is_valid(self, context=None): If the answer isn't valid, it also set the errors property to a list of error messages. """ - validators = self._question.get('validators', []) + validators = self._question.get("validators", []) self._errors = [] for validator in validators: try: diff --git a/interrogatio/handlers/builtins.py b/interrogatio/handlers/builtins.py index 6173e89..e4b3573 100644 --- a/interrogatio/handlers/builtins.py +++ b/interrogatio/handlers/builtins.py @@ -18,25 +18,24 @@ from interrogatio.widgets import DateRange, MaskedInput, SelectMany, SelectOne -@register('input') +@register("input") class StringHandler(QHandler): - def get_widget_class(self): return TextArea def get_widget_init_kwargs(self): - kwgars = dict( - multiline=self._question.get('multiline', False), - style='class:input.answer', - ) - default = self.get_question().get('default') + kwgars = { + "multiline": self._question.get("multiline", False), + "style": "class:input.answer", + } + default = self.get_question().get("default") if default and not callable(default): - kwgars['text'] = default + kwgars["text"] = default return kwgars def set_context(self, context): widget = self.get_widget() - default = self.get_question().get('default') + default = self.get_question().get("default") if default and callable(default): widget.text = default(context) widget.buffer.cursor_position = len(widget.text) @@ -45,25 +44,29 @@ def get_layout(self): widget = self.get_widget() vsplit_components = [widget] widget.buffer.cursor_position = len(widget.text) - if 'message' in self._question and self._question['message']: + if "message" in self._question and self._question["message"]: vsplit_components.insert( 0, Label( - self._question['message'], + self._question["message"], dont_extend_width=True, - style='class:input.question', + style="class:input.question", ), ) hsplit_components = [VSplit(vsplit_components, padding=1)] - if 'description' in self._question and self._question['description']: + if "description" in self._question and self._question["description"]: hsplit_components.insert( 0, Window( FormattedTextControl( - FormattedText([( - 'class:input.question', - self._question['description'], - )]), + FormattedText( + [ + ( + "class:input.question", + self._question["description"], + ) + ] + ), ), wrap_lines=True, height=D(min=1, max=5, preferred=3), @@ -75,26 +78,25 @@ def get_value(self): return self.get_widget().text -@register('password') +@register("password") class PasswordHandler(QHandler): - def get_widget_class(self): return TextArea def get_widget_init_kwargs(self): - kwgars = dict( - multiline=self._question.get('multiline', False), - password=True, - style='class:password.answer', - ) - default = self.get_question().get('default') + kwgars = { + "multiline": self._question.get("multiline", False), + "password": True, + "style": "class:password.answer", + } + default = self.get_question().get("default") if default and not callable(default): - kwgars['text'] = default + kwgars["text"] = default return kwgars def set_context(self, context): widget = self.get_widget() - default = self.get_question().get('default') + default = self.get_question().get("default") if default and callable(default): widget.text = default(context) widget.buffer.cursor_position = len(widget.text) @@ -106,25 +108,29 @@ def get_layout(self): widget = self.get_widget() widget.buffer.cursor_position = len(widget.text) vsplit_components = [widget] - if 'message' in self._question and self._question['message']: + if "message" in self._question and self._question["message"]: vsplit_components.insert( 0, Label( - self._question['message'], + self._question["message"], dont_extend_width=True, - style='class:password.question', + style="class:password.question", ), ) hsplit_components = [VSplit(vsplit_components, padding=1)] - if 'description' in self._question and self._question['description']: + if "description" in self._question and self._question["description"]: hsplit_components.insert( 0, Window( FormattedTextControl( - FormattedText([( - 'class:password.question', - self._question['description'], - )]), + FormattedText( + [ + ( + "class:password.question", + self._question["description"], + ) + ] + ), ), wrap_lines=True, height=D(min=1, max=5, preferred=3), @@ -133,9 +139,8 @@ def get_layout(self): return HSplit(hsplit_components, padding=1) -@register('selectone') +@register("selectone") class SelectOneHandler(QHandler): - def get_widget_class(self): return SelectOne @@ -143,50 +148,54 @@ def get_value(self): return self.get_widget().current_value def get_widget_init_kwargs(self): - values = self.get_question()['values'] - kwargs = dict( - values=values if not callable(values) else None, - style='class:selectone.answer', - ) - default = self.get_question().get('default') + values = self.get_question()["values"] + kwargs = { + "values": values if not callable(values) else None, + "style": "class:selectone.answer", + } + default = self.get_question().get("default") if default and not callable(default): - kwargs['default'] = default + kwargs["default"] = default return kwargs def set_context(self, context): widget = self.get_widget() - values = self.get_question()['values'] + values = self.get_question()["values"] if callable(values): values = values(context) widget.values = values or [] widget.current_value = values[0][0] if values else None - default = self.get_question().get('default') + default = self.get_question().get("default") if default and callable(default): widget.value = default(context) def get_layout(self): vsplit_components = [self.get_widget()] - if 'message' in self._question and self._question['message']: + if "message" in self._question and self._question["message"]: vsplit_components.insert( 0, Label( - self._question['message'], + self._question["message"], dont_extend_width=True, dont_extend_height=False, - style='class:selectone.question', + style="class:selectone.question", ), ) hsplit_components = [VSplit(vsplit_components, padding=1)] - if 'description' in self._question and self._question['description']: + if "description" in self._question and self._question["description"]: hsplit_components.insert( 0, Window( FormattedTextControl( - FormattedText([( - 'class:selectone.question', - self._question['description'], - )]), + FormattedText( + [ + ( + "class:selectone.question", + self._question["description"], + ) + ] + ), ), wrap_lines=True, height=D(min=1, max=5, preferred=3), @@ -196,19 +205,19 @@ def get_layout(self): def get_formatted_value(self): format = self._question.get( - 'formatting_template', - '${label} (${value})', + "formatting_template", + "${label} (${value})", ) value = self.get_value() - options = {t[0]: t[1] for t in self._question['values']} + options = {t[0]: t[1] for t in self._question["values"]} return string.Template(format).safe_substitute( - label=options[value], value=value, + label=options[value], + value=value, ) -@register('selectmany') +@register("selectmany") class SelectManyHandler(QHandler): - def get_widget_class(self): return SelectMany @@ -216,43 +225,43 @@ def get_value(self): return self.get_widget().value def get_widget_init_kwargs(self): - values = self.get_question()['values'] - kwargs = dict( - values=values if not callable(values) else None, - style='class:selectmany.answer', - ) - default = self.get_question().get('default') + values = self.get_question()["values"] + kwargs = { + "values": values if not callable(values) else None, + "style": "class:selectmany.answer", + } + default = self.get_question().get("default") if default and not callable(default): - kwargs['default'] = default + kwargs["default"] = default return kwargs def set_context(self, context): widget = self.get_widget() - values = self.get_question()['values'] + values = self.get_question()["values"] if callable(values): values = values(context) widget.values = values or [] - default = self.get_question().get('default') + default = self.get_question().get("default") if default and callable(default): widget.value = default(context) def get_layout(self): widget = self.get_widget() vsplit_components = [widget] - if 'message' in self._question and self._question['message']: + if "message" in self._question and self._question["message"]: vsplit_components.insert( 0, Label( - self._question['message'], + self._question["message"], dont_extend_width=True, dont_extend_height=False, - style='class:selectone.question', + style="class:selectone.question", ), ) - btn_all = Button('All', widget.select_all) - btn_none = Button('None', widget.select_none) + btn_all = Button("All", widget.select_all) + btn_none = Button("None", widget.select_none) buttons = Box( body=VSplit([btn_all, btn_none], padding=1), height=D(min=1, max=3, preferred=3), @@ -260,15 +269,19 @@ def get_layout(self): ) hsplit_components = [buttons, VSplit(vsplit_components, padding=1)] - if 'description' in self._question and self._question['description']: + if "description" in self._question and self._question["description"]: hsplit_components.insert( 0, Window( FormattedTextControl( - FormattedText([( - 'class:selectone.question', - self._question['description'], - )]), + FormattedText( + [ + ( + "class:selectone.question", + self._question["description"], + ) + ] + ), ), wrap_lines=True, height=D(min=1, max=5, preferred=3), @@ -277,7 +290,6 @@ def get_layout(self): return HSplit(hsplit_components, padding=1) def get_keybindings(self): - bindings = super().get_keybindings() @bindings.add(Keys.Tab) @@ -292,79 +304,83 @@ def _s_tab(event): def get_formatted_value(self): format = self._question.get( - 'formatting_template', - '${label} (${value})', + "formatting_template", + "${label} (${value})", ) values = self.get_value() if not values: - return '' + return "" - if callable(self._question['values']): + if callable(self._question["values"]): options = {t[0]: t[1] for t in self.get_widget().values} else: - options = {t[0]: t[1] for t in self._question['values']} + options = {t[0]: t[1] for t in self._question["values"]} formatted_values = [] for idx, value in enumerate(values): if idx > 14: - formatted_values.append('...') + formatted_values.append("...") break formatted_values.append( string.Template(format).safe_substitute( - label=options[value], value=value, + label=options[value], + value=value, ), ) - return ', '.join(formatted_values) + return ", ".join(formatted_values) -@register('maskedinput') +@register("maskedinput") class MaskedInputHandler(QHandler): - def get_widget_class(self): return MaskedInput def get_widget_init_kwargs(self): - mask = self.get_question()['mask'] - kwargs = dict( - style='class:input.answer', - mask=mask, - ) - default = self.get_question().get('default') + mask = self.get_question()["mask"] + kwargs = { + "style": "class:input.answer", + "mask": mask, + } + default = self.get_question().get("default") if default and not callable(default): - kwargs['default'] = default + kwargs["default"] = default return kwargs def set_context(self, context): widget = self.get_widget() - default = self.get_question().get('default') + default = self.get_question().get("default") if default and callable(default): widget.value = default(context) def get_layout(self): widget = self.get_widget() vsplit_components = [widget] - if 'message' in self._question and self._question['message']: + if "message" in self._question and self._question["message"]: vsplit_components.insert( 0, Label( - self._question['message'], + self._question["message"], dont_extend_width=True, - style='class:input.question', + style="class:input.question", ), ) hsplit_components = [VSplit(vsplit_components, padding=1)] - if 'description' in self._question and self._question['description']: + if "description" in self._question and self._question["description"]: hsplit_components.insert( 0, Window( FormattedTextControl( - FormattedText([( - 'class:input.question', - self._question['description'], - )]), + FormattedText( + [ + ( + "class:input.question", + self._question["description"], + ) + ] + ), ), wrap_lines=True, height=D(min=1, max=5, preferred=3), @@ -376,58 +392,61 @@ def get_value(self): return self.get_widget().value -@register('date') +@register("date") class DateHandler(QHandler): - def get_widget_class(self): return MaskedInput def get_widget_init_kwargs(self): - kwargs = dict( - style='class:input.answer', - mask='____-__-__', - allowed_chars=string.digits, - ) - default = self.get_question().get('default') + kwargs = { + "style": "class:input.answer", + "mask": "____-__-__", + "allowed_chars": string.digits, + } + default = self.get_question().get("default") if default and not callable(default): if isinstance(default, (date, datetime)): - kwargs['default'] = default.strftime('%Y-%m-%d') + kwargs["default"] = default.strftime("%Y-%m-%d") else: - kwargs['default'] = default + kwargs["default"] = default return kwargs def set_context(self, context): widget = self.get_widget() - default = self.get_question().get('default') + default = self.get_question().get("default") if default and callable(default): value = default(context) if isinstance(value, (date, datetime)): - widget.value = value.strftime('%Y-%m-%d') + widget.value = value.strftime("%Y-%m-%d") else: widget.value = value def get_layout(self): widget = self.get_widget() vsplit_components = [widget] - if 'message' in self._question and self._question['message']: + if "message" in self._question and self._question["message"]: vsplit_components.insert( 0, Label( - self._question['message'], + self._question["message"], dont_extend_width=True, - style='class:input.question', + style="class:input.question", ), ) hsplit_components = [VSplit(vsplit_components, padding=1)] - if 'description' in self._question and self._question['description']: + if "description" in self._question and self._question["description"]: hsplit_components.insert( 0, Window( FormattedTextControl( - FormattedText([( - 'class:input.question', - self._question['description'], - )]), + FormattedText( + [ + ( + "class:input.question", + self._question["description"], + ) + ] + ), ), wrap_lines=True, height=D(min=1, max=5, preferred=3), @@ -441,12 +460,12 @@ def to_python(self): return question = self.get_question() - if 'timezone' in question: - tzinfo = pytz.timezone(question['timezone']) + if "timezone" in question: + tzinfo = pytz.timezone(question["timezone"]) else: tzinfo = pytz.timezone(get_localzone_name()) - year, month, day = value.split('-') + year, month, day = value.split("-") return tzinfo.localize( datetime(int(year), int(month), int(day)), ) @@ -455,84 +474,87 @@ def get_value(self): return self.get_widget().value -@register('daterange') +@register("daterange") class DateRangeHandler(QHandler): - def get_widget_class(self): return DateRange def get_widget_init_kwargs(self): # noqa: CCR001 - kwargs = dict( - style='class:input.answer', - ) - if 'from_label' in self._question: - kwargs['from_label'] = self._question['from_label'] - if 'to_label' in self._question: - kwargs['to_label'] = self._question['to_label'] - default = self.get_question().get('default') + kwargs = { + "style": "class:input.answer", + } + if "from_label" in self._question: + kwargs["from_label"] = self._question["from_label"] + if "to_label" in self._question: + kwargs["to_label"] = self._question["to_label"] + default = self.get_question().get("default") if default and not callable(default): - kwargs['default'] = {} - default_from = default.get('from') + kwargs["default"] = {} + default_from = default.get("from") if default_from: if isinstance(default_from, (date, datetime)): - kwargs['default']['from'] = default_from.strftime( - '%Y-%m-%d', + kwargs["default"]["from"] = default_from.strftime( + "%Y-%m-%d", ) else: - kwargs['default']['from'] = default_from - default_to = default.get('to') + kwargs["default"]["from"] = default_from + default_to = default.get("to") if default_to: if isinstance(default_to, (date, datetime)): - kwargs['default']['to'] = default_to.strftime('%Y-%m-%d') + kwargs["default"]["to"] = default_to.strftime("%Y-%m-%d") else: - kwargs['default']['to'] = default_to + kwargs["default"]["to"] = default_to return kwargs def set_context(self, context): widget = self.get_widget() - default = self.get_question().get('default') + default = self.get_question().get("default") if default and callable(default): value = default(context) default_value = {} - default_from = value.get('from') + default_from = value.get("from") if default_from: if isinstance(default_from, (date, datetime)): - default_value['from'] = default_from.strftime( - '%Y-%m-%d', + default_value["from"] = default_from.strftime( + "%Y-%m-%d", ) else: - default_value['from'] = default_from - default_to = value.get('to') + default_value["from"] = default_from + default_to = value.get("to") if default_to: if isinstance(default_to, (date, datetime)): - default_value['to'] = default_to.strftime('%Y-%m-%d') + default_value["to"] = default_to.strftime("%Y-%m-%d") else: - default_value['to'] = default_to + default_value["to"] = default_to widget.value = default_value def get_layout(self): widget = self.get_widget() vsplit_components = [widget] - if 'message' in self._question and self._question['message']: + if "message" in self._question and self._question["message"]: vsplit_components.insert( 0, Label( - self._question['message'], + self._question["message"], dont_extend_width=True, dont_extend_height=False, - style='class:input.question', + style="class:input.question", ), ) hsplit_components = [VSplit(vsplit_components, padding=1)] - if 'description' in self._question and self._question['description']: + if "description" in self._question and self._question["description"]: hsplit_components.insert( 0, Window( FormattedTextControl( - FormattedText([( - 'class:input.question', - self._question['description'], - )]), + FormattedText( + [ + ( + "class:input.question", + self._question["description"], + ) + ] + ), ), wrap_lines=True, height=D(min=1, max=5, preferred=3), @@ -542,8 +564,8 @@ def get_layout(self): def to_python(self): question = self.get_question() - if 'timezone' in question: - tzinfo = pytz.timezone(question['timezone']) + if "timezone" in question: + tzinfo = pytz.timezone(question["timezone"]) else: tzinfo = pytz.timezone(get_localzone_name()) @@ -552,21 +574,21 @@ def to_python(self): value = self.get_value() - from_value = value.get('from') + from_value = value.get("from") if from_value: - year, month, day = from_value.split('-') + year, month, day = from_value.split("-") from_date = tzinfo.localize( datetime(int(year), int(month), int(day)), ) - to_value = value.get('to') + to_value = value.get("to") if to_value: - year, month, day = to_value.split('-') + year, month, day = to_value.split("-") to_date = tzinfo.localize(datetime(int(year), int(month), int(day))) return { - 'from': from_date, - 'to': to_date, + "from": from_date, + "to": to_date, } def get_value(self): @@ -574,16 +596,16 @@ def get_value(self): def get_formatted_value(self): format = self._question.get( - 'formatting_template', - 'from ${start} - to ${end}', + "formatting_template", + "from ${start} - to ${end}", ) value = self.get_value() return string.Template(format).safe_substitute( - start=value['from'], end=value['to'], + start=value["from"], + end=value["to"], ) def get_keybindings(self): - bindings = super().get_keybindings() @bindings.add(Keys.Tab) diff --git a/interrogatio/handlers/registry.py b/interrogatio/handlers/registry.py index 3c99d75..27cc66b 100644 --- a/interrogatio/handlers/registry.py +++ b/interrogatio/handlers/registry.py @@ -5,14 +5,14 @@ class QHandlersRegistry(dict): def register(self, alias, clazz): if alias in self: - raise AlreadyRegisteredError(f'alias `{alias}` already exists.') + raise AlreadyRegisteredError(f"alias `{alias}` already exists.") self[alias] = clazz def get_registered(self): return list(self.keys()) def get_instance(self, question): - qtype = question['type'] + qtype = question["type"] clazz = self[qtype] return clazz(question) @@ -52,16 +52,17 @@ def get_registered(): def register(name): if name in get_registry().get_registered(): raise AlreadyRegisteredError( - f'The handler `{name}` is already registered.', + f"The handler `{name}` is already registered.", ) def _wrapper(cls): if not issubclass(cls, QHandler): raise ValueError( - 'The provided class must be a subclass of QHandler.', + "The provided class must be a subclass of QHandler.", ) get_registry().register(name, cls) return cls + return _wrapper diff --git a/interrogatio/main.py b/interrogatio/main.py index 025bd07..1460df9 100644 --- a/interrogatio/main.py +++ b/interrogatio/main.py @@ -5,10 +5,11 @@ try: import yaml - FORMAT_CHOICES = ['json', 'yaml'] + + FORMAT_CHOICES = ["json", "yaml"] except ImportError: yaml = None - FORMAT_CHOICES = ['json'] + FORMAT_CHOICES = ["json"] from interrogatio import dialogus, interrogatio @@ -26,78 +27,76 @@ def _write_answers(args, answers): def _add_common_arguments(parser): parser.add_argument( - '--input', - '-i', - type=argparse.FileType('r'), + "--input", + "-i", + type=argparse.FileType("r"), required=True, - help='Input file with questions', + help="Input file with questions", ) parser.add_argument( - '--output', - '-o', - type=argparse.FileType('w'), + "--output", + "-o", + type=argparse.FileType("w"), default=sys.stdout, - help='Output file to write answers to (Default: STDOUT)', + help="Output file to write answers to (Default: STDOUT)", ) if len(FORMAT_CHOICES) > 1: parser.add_argument( - '--input-format', + "--input-format", choices=FORMAT_CHOICES, - default='json', - help='Questions file format (Default: json)', + default="json", + help="Questions file format (Default: json)", ) parser.add_argument( - '--output-format', + "--output-format", choices=FORMAT_CHOICES, - default='json', - help='Answers file format (Default: json)', + default="json", + help="Answers file format (Default: json)", ) parser.add_argument( - '--theme', - '-t', - default='default', - help='Name of the UI theme to use (Default: default)', + "--theme", + "-t", + default="default", + help="Name of the UI theme to use (Default: default)", ) def main_dialogus(): parser = argparse.ArgumentParser( - description='Show a wizard dialog to prompt user for questions.', + description="Show a wizard dialog to prompt user for questions.", ) _add_common_arguments(parser) parser.add_argument( - '--title', - help='Title of the dialog', + "--title", + help="Title of the dialog", ) parser.add_argument( - '--intro', - help='Specify the text of the introduction step (Default: no intro)', + "--intro", + help="Specify the text of the introduction step (Default: no intro)", ) parser.add_argument( - '--summary', - action='store_true', + "--summary", + action="store_true", help=( - 'Show a summary with answers as the ' - 'latest step (Default: no summary)' + "Show a summary with answers as the " "latest step (Default: no summary)" ), ) - for button in ('previous', 'next', 'cancel', 'finish'): + for button in ("previous", "next", "cancel", "finish"): cap_btn = button.capitalize() parser.add_argument( - f'--{button}', + f"--{button}", default=cap_btn, help=( - f'Customize the text of the "{button}" ' - f'button (Default: {cap_btn})' + f'Customize the text of the "{button}" ' f"button (Default: {cap_btn})" ), ) args = parser.parse_args() - if args.input_format == 'yaml': + if args.input_format == "yaml": args.deserialize = partial(yaml.load, Loader=yaml.FullLoader) args.serialize = yaml.dump else: @@ -105,13 +104,13 @@ def main_dialogus(): args.serialize = json.dump kwargs = { - 'intro': args.intro, - 'summary': args.summary, - 'title': args.title, - 'previous_text': args.previous, - 'next_text': args.next, - 'cancel_text': args.cancel, - 'finish_text': args.finish, + "intro": args.intro, + "summary": args.summary, + "title": args.title, + "previous_text": args.previous, + "next_text": args.next, + "cancel_text": args.cancel, + "finish_text": args.finish, } _write_answers(args, dialogus(_load_questions(args), **kwargs)) @@ -119,13 +118,13 @@ def main_dialogus(): def main_interrogatio(): parser = argparse.ArgumentParser( - description='Prompt user for questions.', + description="Prompt user for questions.", ) _add_common_arguments(parser) args = parser.parse_args() - if args.input_format == 'yaml': + if args.input_format == "yaml": args.deserialize = partial(yaml.load, Loader=yaml.FullLoader) args.serialize = yaml.dump else: diff --git a/interrogatio/shortcuts/__init__.py b/interrogatio/shortcuts/__init__.py index d22021e..5807d29 100644 --- a/interrogatio/shortcuts/__init__.py +++ b/interrogatio/shortcuts/__init__.py @@ -1 +1 @@ -from interrogatio.shortcuts.dialogs import * # noqa \ No newline at end of file +from interrogatio.shortcuts.dialogs import * # noqa diff --git a/interrogatio/shortcuts/dialogs.py b/interrogatio/shortcuts/dialogs.py index c05e0d2..0ffa378 100644 --- a/interrogatio/shortcuts/dialogs.py +++ b/interrogatio/shortcuts/dialogs.py @@ -8,20 +8,20 @@ from interrogatio.themes import for_dialog __all__ = [ - 'yes_no_dialog', - 'button_dialog', - 'input_dialog', - 'message_dialog', - 'radiolist_dialog', - 'progress_dialog', + "yes_no_dialog", + "button_dialog", + "input_dialog", + "message_dialog", + "radiolist_dialog", + "progress_dialog", ] def yes_no_dialog( - title='', - text='', - yes_text='Yes', - no_text='No', + title="", + text="", + yes_text="Yes", + no_text="No", style=None, ): style = style or for_dialog() @@ -35,8 +35,8 @@ def yes_no_dialog( def button_dialog( - title='', - text='', + title="", + text="", buttons=None, style=None, ): @@ -50,45 +50,70 @@ def button_dialog( def input_dialog( - title='', text='', ok_text='OK', cancel_text='Cancel', - completer=None, password=False, style=None, + title="", + text="", + ok_text="OK", + cancel_text="Cancel", + completer=None, + password=False, + style=None, ): style = style or for_dialog() return pt_input_dialog( - title=title, text=text, ok_text=ok_text, - cancel_text=cancel_text, completer=completer, - password=password, style=style, + title=title, + text=text, + ok_text=ok_text, + cancel_text=cancel_text, + completer=completer, + password=password, + style=style, ) def message_dialog( - title='', text='', ok_text='Ok', style=None, + title="", + text="", + ok_text="Ok", + style=None, ): style = style or for_dialog() return pt_message_dialog( - title=title, text=text, - ok_text=ok_text, style=style, + title=title, + text=text, + ok_text=ok_text, + style=style, ) def radiolist_dialog( - title='', text='', ok_text='Ok', cancel_text='Cancel', - values=None, style=None, + title="", + text="", + ok_text="Ok", + cancel_text="Cancel", + values=None, + style=None, ): style = style or for_dialog() return pt_radiolist_dialog( - title=title, text=text, - ok_text=ok_text, cancel_text=cancel_text, - values=values, style=style, + title=title, + text=text, + ok_text=ok_text, + cancel_text=cancel_text, + values=values, + style=style, ) def progress_dialog( - title='', text='', - run_callback=None, style=None, + title="", + text="", + run_callback=None, + style=None, ): style = style or for_dialog() return pt_progress_dialog( - title=title, text=text, - run_callback=run_callback, style=style, + title=title, + text=text, + run_callback=run_callback, + style=style, ) diff --git a/interrogatio/themes/base.py b/interrogatio/themes/base.py index a61dc3a..6f12f21 100644 --- a/interrogatio/themes/base.py +++ b/interrogatio/themes/base.py @@ -1,6 +1,6 @@ import json -from prompt_toolkit.styles import default_ui_style, merge_styles, Style +from prompt_toolkit.styles import Style, default_ui_style, merge_styles from interrogatio.core.exceptions import ( AlreadyRegisteredError, @@ -8,69 +8,70 @@ ) __all__ = [ - 'Theme', - 'register', - 'for_dialog', - 'for_prompt', - 'set_theme', + "Theme", + "register", + "for_dialog", + "for_prompt", + "set_theme", ] class Theme: - def __init__(self): - self._prompt_styles = dict() - self._dialog_styles = dict() - self._name = '' + self._prompt_styles = {} + self._dialog_styles = {} + self._name = "" def load(self, filename): - with open(filename, 'r') as f: + with open(filename) as f: tmp = json.load(f) - self._name = tmp['name'] - self._prompt_styles = tmp['prompt'] - self._dialog_styles = tmp['dialog'] + self._name = tmp["name"] + self._prompt_styles = tmp["prompt"] + self._dialog_styles = tmp["dialog"] def for_prompt(self): - return merge_styles([ - default_ui_style(), - Style(list(self._prompt_styles.items())), - ]) + return merge_styles( + [ + default_ui_style(), + Style(list(self._prompt_styles.items())), + ] + ) def for_dialog(self): - return merge_styles([ - default_ui_style(), - Style(list(self._dialog_styles.items())), - ]) + return merge_styles( + [ + default_ui_style(), + Style(list(self._dialog_styles.items())), + ] + ) def save(self, filename): - with open(filename, 'w') as f: + with open(filename, "w") as f: json.dump( { - 'name': self._name, - 'prompt': self._prompt_styles, - 'dialog': self._dialog_styles, + "name": self._name, + "prompt": self._prompt_styles, + "dialog": self._dialog_styles, }, f, indent=2, ) -class ThemeRegistry(object): - +class ThemeRegistry: def __init__(self): self._themes = {} - self._current_theme = 'default' + self._current_theme = "default" def register(self, alias, theme): assert isinstance(theme, Theme) if alias in self._themes: - raise AlreadyRegisteredError( - 'theme {} already registered'.format(alias)) + raise AlreadyRegisteredError(f"theme {alias} already registered") self._themes[alias] = theme def set_current(self, alias): if alias not in self._themes: - raise ThemeNotFoundError('theme {} not registered'.format(alias)) + raise ThemeNotFoundError(f"theme {alias} not registered") self._current_theme = alias def get_current(self): diff --git a/interrogatio/themes/builtins.py b/interrogatio/themes/builtins.py index 290f6c3..3cbcba1 100644 --- a/interrogatio/themes/builtins.py +++ b/interrogatio/themes/builtins.py @@ -1,29 +1,33 @@ import os -from interrogatio.themes.base import register, Theme +from interrogatio.themes.base import Theme, register class DefaultTheme(Theme): def __init__(self): - super(DefaultTheme, self).__init__() - self.load(os.path.join( - os.path.dirname(__file__), - 'theme_files', - 'default.json', - )) + super().__init__() + self.load( + os.path.join( + os.path.dirname(__file__), + "theme_files", + "default.json", + ) + ) -register('default', DefaultTheme()) +register("default", DefaultTheme()) class PurpleTheme(Theme): def __init__(self): - super(PurpleTheme, self).__init__() - self.load(os.path.join( - os.path.dirname(__file__), - 'theme_files', - 'purple.json', - )) + super().__init__() + self.load( + os.path.join( + os.path.dirname(__file__), + "theme_files", + "purple.json", + ) + ) -register('purple', PurpleTheme()) +register("purple", PurpleTheme()) diff --git a/interrogatio/validators/base.py b/interrogatio/validators/base.py index 2820282..fd23f88 100644 --- a/interrogatio/validators/base.py +++ b/interrogatio/validators/base.py @@ -1,8 +1,7 @@ from abc import ABCMeta, abstractmethod - __all__ = [ - 'Validator', + "Validator", ] @@ -10,7 +9,8 @@ class Validator(metaclass=ABCMeta): """ Abstract class for validators. """ - def __init__(self, message='invalid input'): + + def __init__(self, message="invalid input"): self.message = message @abstractmethod diff --git a/interrogatio/validators/builtins.py b/interrogatio/validators/builtins.py index c051380..86334a0 100644 --- a/interrogatio/validators/builtins.py +++ b/interrogatio/validators/builtins.py @@ -7,26 +7,25 @@ from interrogatio.validators.base import Validator from interrogatio.validators.registry import register - __all__ = [ - 'RequiredValidator', - 'RegexValidator', - 'URLValidator', - 'EmailValidator', - 'MinLengthValidator', - 'MaxLengthValidator', - 'NumberValidator', - 'IntegerValidator', - 'IPv4Validator', - 'RangeValidator', - 'MinValidator', - 'MaxValidator', - 'DateTimeValidator', - 'DateTimeRangeValidator', + "RequiredValidator", + "RegexValidator", + "URLValidator", + "EmailValidator", + "MinLengthValidator", + "MaxLengthValidator", + "NumberValidator", + "IntegerValidator", + "IPv4Validator", + "RangeValidator", + "MinValidator", + "MaxValidator", + "DateTimeValidator", + "DateTimeRangeValidator", ] -@register('required') +@register("required") class RequiredValidator(Validator): def __init__(self, message=None): """ @@ -35,8 +34,8 @@ def __init__(self, message=None): :param message: the error message in case that validation fails. :type message: str """ - super(RequiredValidator, self).__init__( - message=message or 'this field is required', + super().__init__( + message=message or "this field is required", ) def validate(self, value, context=None): @@ -44,7 +43,7 @@ def validate(self, value, context=None): raise ValidationError(self.message) -@register('regex') +@register("regex") class RegexValidator(Validator): def __init__(self, expr, message=None, inverse_match=None): """ @@ -57,32 +56,29 @@ def __init__(self, expr, message=None, inverse_match=None): :param inverse_match: invert the match of the expression. :type inverse_match: bool """ - super(RegexValidator, self).__init__( - message=message or f'this field does not match {expr}', + super().__init__( + message=message or f"this field does not match {expr}", ) self.regex = re.compile(expr) self.inverse_match = inverse_match def validate(self, value, context=None): regex_matches = self.regex.search(str(value)) - invalid_input = ( - regex_matches if self.inverse_match else not regex_matches - ) + invalid_input = regex_matches if self.inverse_match else not regex_matches if invalid_input: raise ValidationError(self.message) -@register('email') +@register("email") class EmailValidator(Validator): - def __init__(self, message=None): """ Initialise the ``email`` validator. :param message: the error message in case that validation fails. :type message: str """ - super(EmailValidator, self).__init__( - message=message or 'this field must be an email address', + super().__init__( + message=message or "this field must be an email address", ) def validate(self, value, context=None): @@ -90,18 +86,17 @@ def validate(self, value, context=None): raise ValidationError(self.message) -@register('url') +@register("url") class URLValidator(Validator): - def __init__(self, message=None): - super().__init__(message=message or 'this field must be an url') + super().__init__(message=message or "this field must be an url") def validate(self, value, context=None): if value and validators.url(value) is not True: raise ValidationError(self.message) -@register('min-length') +@register("min-length") class MinLengthValidator(Validator): def __init__(self, min_length, message=None): """ @@ -116,22 +111,19 @@ def __init__(self, min_length, message=None): self.min_length = min_length self.message = message or ( - 'the length of this field must be at ' - 'least {} characters long'.format(self.min_length) + "the length of this field must be at " + f"least {self.min_length} characters long" ) def validate(self, value, context=None): try: - if ( - value - and validators.length(value, min=self.min_length) is not True - ): + if value and validators.length(value, min=self.min_length) is not True: raise ValidationError(message=self.message) except (TypeError, AssertionError): raise ValidationError(message=self.message) -@register('max-length') +@register("max-length") class MaxLengthValidator(Validator): def __init__(self, max_length, message=None): """ @@ -145,25 +137,21 @@ def __init__(self, max_length, message=None): """ self.max_length = max_length self.message = message or ( - 'the length of this field must be at ' - f'most {max_length} characters long' + "the length of this field must be at " f"most {max_length} characters long" ) def validate(self, value, context=None): try: - if ( - value - and validators.length(value, max=self.max_length) is not True - ): + if value and validators.length(value, max=self.max_length) is not True: raise ValidationError(message=self.message) except (TypeError, AssertionError): raise ValidationError(message=self.message) -@register('number') +@register("number") class NumberValidator(Validator): def __init__(self, message=None): - self.message = message or 'this field must be a number' + self.message = message or "this field must be a number" def validate(self, value, context=None): try: @@ -172,10 +160,10 @@ def validate(self, value, context=None): raise ValidationError(message=self.message) -@register('integer') +@register("integer") class IntegerValidator(Validator): def __init__(self, message=None): - self.message = message or 'this field must be an integer' + self.message = message or "this field must be an integer" def validate(self, value, context=None): try: @@ -187,92 +175,94 @@ def validate(self, value, context=None): raise ValidationError(message=self.message) -@register('ipv4') +@register("ipv4") class IPv4Validator(Validator): def __init__(self, message=None): - self.message = message or 'this field must be an IPv4 address' + self.message = message or "this field must be an IPv4 address" def validate(self, value, context=None): if value and validators.ipv4(value) is not True: raise ValidationError(message=self.message) -@register('range') +@register("range") class RangeValidator(Validator): def __init__(self, min=None, max=None, message=None): self.min = min self.max = max self.message = message or ( - f'this field must be a number between {min} and {max}' + f"this field must be a number between {min} and {max}" ) def validate(self, value, context=None): try: if ( - value is not None and value != '' + value is not None + and value != "" and validators.between( value, min=self.min, max=self.max, - ) is not True + ) + is not True ): raise ValidationError(message=self.message) except (TypeError, AssertionError): raise ValidationError(message=self.message) -@register('min') +@register("min") class MinValidator(Validator): def __init__(self, min=None, message=None): self.min = min - self.message = ( - message or f'this field must be greater or equal to {min}' - ) + self.message = message or f"this field must be greater or equal to {min}" def validate(self, value, context=None): try: if ( - value is not None and value != '' + value is not None + and value != "" and validators.between( value, min=self.min, - ) is not True + ) + is not True ): raise ValidationError(message=self.message) except (TypeError, AssertionError): raise ValidationError(message=self.message) -@register('max') +@register("max") class MaxValidator(Validator): def __init__(self, max=None, message=None): self.max = max - self.message = ( - message or f'this field must be smaller or equal to {max}' - ) + self.message = message or f"this field must be smaller or equal to {max}" def validate(self, value, context=None): try: if ( - value is not None and value != '' + value is not None + and value != "" and validators.between( value, max=self.max, - ) is not True + ) + is not True ): raise ValidationError(message=self.message) except (TypeError, AssertionError): raise ValidationError(message=self.message) -@register('datetime') +@register("datetime") class DateTimeValidator(Validator): - def __init__(self, format_pattern='%Y-%m-%dT%H:%M:%S', message=None): + def __init__(self, format_pattern="%Y-%m-%dT%H:%M:%S", message=None): self.format_pattern = format_pattern - self.message = message or 'this field is not a valid datetime' + self.message = message or "this field is not a valid datetime" def validate(self, value, context=None): - if value is None or value == '': + if value is None or value == "": return try: datetime.strptime(value, self.format_pattern) @@ -280,22 +270,22 @@ def validate(self, value, context=None): raise ValidationError(message=self.message) -@register('datetimerange') +@register("datetimerange") class DateTimeRangeValidator(Validator): - def __init__(self, format_pattern='%Y-%m-%d', message=None): + def __init__(self, format_pattern="%Y-%m-%d", message=None): self.format_pattern = format_pattern - self.message = message or 'this field is not a valid datetime range' + self.message = message or "this field is not a valid datetime range" def validate(self, value, context=None): - if value is None or value == '': + if value is None or value == "": return d_from = None d_to = None try: - if value['from']: - d_from = datetime.strptime(value['from'], self.format_pattern) - if value['to']: - d_to = datetime.strptime(value['to'], self.format_pattern) + if value["from"]: + d_from = datetime.strptime(value["from"], self.format_pattern) + if value["to"]: + d_to = datetime.strptime(value["to"], self.format_pattern) except (TypeError, ValueError): raise ValidationError(message=self.message) diff --git a/interrogatio/validators/registry.py b/interrogatio/validators/registry.py index 2f8f2b3..149d85b 100644 --- a/interrogatio/validators/registry.py +++ b/interrogatio/validators/registry.py @@ -5,17 +5,16 @@ class ValidatorsRegistry(dict): def register(self, alias, clazz): if alias in self: - raise AlreadyRegisteredError( - 'validator `{}` already exists.'.format(alias)) + raise AlreadyRegisteredError(f"validator `{alias}` already exists.") self[alias] = clazz def get_registered(self): return list(self.keys()) def get_instance(self, v): - clazz = self[v['name']] - if 'args' in v: - return clazz(**v['args']) + clazz = self[v["name"]] + if "args" in v: + return clazz(**v["args"]) return clazz() @@ -29,18 +28,19 @@ def get_registry(): def register(name): if name in get_registry().get_registered(): raise AlreadyRegisteredError( - f'The validator `{name}` is already registered.', + f"The validator `{name}` is already registered.", ) def _wrapper(cls): if not issubclass(cls, Validator): raise ValueError( - 'The provided class must be a subclass of Validator.', + "The provided class must be a subclass of Validator.", ) get_registry().register(name, cls) return cls + return _wrapper diff --git a/interrogatio/widgets/base.py b/interrogatio/widgets/base.py index 67e7136..5ed8474 100644 --- a/interrogatio/widgets/base.py +++ b/interrogatio/widgets/base.py @@ -14,16 +14,16 @@ from prompt_toolkit.widgets import Label, TextArea -class SelectOne(object): +class SelectOne: def __init__( # noqa: CCR001 - self, values=None, default=None, - accept_handler=None, style='', + self, + values=None, + default=None, + accept_handler=None, + style="", ): - self.values = values or [] - self.current_value = ( - values[0][0] if values and not callable(values) else None - ) + self.current_value = values[0][0] if values and not callable(values) else None self._selected_index = 0 self.accept_handler = accept_handler if default: @@ -31,20 +31,19 @@ def __init__( # noqa: CCR001 # Key bindings. kb = KeyBindings() - @kb.add('up') + @kb.add("up") def _(event): if not self.values: return self._selected_index = max(0, self._selected_index - 1) - @kb.add('down') + @kb.add("down") def _(event): if not self.values: return - self._selected_index = min( - len(self.values) - 1, self._selected_index + 1) + self._selected_index = min(len(self.values) - 1, self._selected_index + 1) - @kb.add('pageup') + @kb.add("pageup") def _(event): if not self.values: return @@ -54,7 +53,7 @@ def _(event): self._selected_index - len(w.render_info.displayed_lines), ) - @kb.add('pagedown') + @kb.add("pagedown") def _(event): if not self.values: return @@ -64,7 +63,7 @@ def _(event): self._selected_index + len(w.render_info.displayed_lines), ) - @kb.add(' ') + @kb.add(" ") def _(event): if not self.values: return @@ -75,22 +74,22 @@ def _(event): if not self.values: return # We first check values after the selected value, then all values. - for value in self.values[self._selected_index + 1:] + self.values: + for value in self.values[self._selected_index + 1 :] + self.values: if value[1].startswith(event.data): self._selected_index = self.values.index(value) return # Control and window. self.control = FormattedTextControl( - lambda: self._get_text_fragments(style), - key_bindings=kb, - focusable=True) + lambda: self._get_text_fragments(style), key_bindings=kb, focusable=True + ) self.window = Window( content=self.control, - style='class:radio-list', + style="class:radio-list", right_margins=[ScrollbarMargin(display_arrows=True)], - dont_extend_height=True) + dont_extend_height=True, + ) @property def value(self): @@ -116,29 +115,28 @@ def mouse_handler(mouse_event): result = [] for i, value in enumerate(self.values): - checked = (value[0] == self.current_value) - selected = (i == self._selected_index) + checked = value[0] == self.current_value + selected = i == self._selected_index style = out_style if checked: - style += ' class:radio-checked' + style += " class:radio-checked" if selected: - style += ' class:radio-selected' + style += " class:radio-selected" - result.append((style, '(')) + result.append((style, "(")) if selected: - result.append(('[SetCursorPosition]', '')) + result.append(("[SetCursorPosition]", "")) if checked: - result.append((style, '*')) + result.append((style, "*")) else: - result.append((style, ' ')) + result.append((style, " ")) - result.append((style, ')')) - result.append((out_style + ' class:radio', ' ')) - result.extend( - to_formatted_text(value[1], style=out_style + ' class:radio')) - result.append(('', '\n')) + result.append((style, ")")) + result.append((out_style + " class:radio", " ")) + result.extend(to_formatted_text(value[1], style=out_style + " class:radio")) + result.append(("", "\n")) # Add mouse handler to all fragments. for i, fragment in enumerate(result): @@ -152,12 +150,14 @@ def __pt_container__(self): return self.window -class SelectMany(object): +class SelectMany: def __init__( # noqa: CCR001 - self, values=None, default=None, - accept_handler=None, style='', + self, + values=None, + default=None, + accept_handler=None, + style="", ): - self.values = values self.checked = None self._selected_index = 0 @@ -168,20 +168,19 @@ def __init__( # noqa: CCR001 # Key bindings. kb = KeyBindings() - @kb.add('up') + @kb.add("up") def _(event): if not self.values: return self._selected_index = max(0, self._selected_index - 1) - @kb.add('down') + @kb.add("down") def _(event): if not self.values: return - self._selected_index = min( - len(self.values) - 1, self._selected_index + 1) + self._selected_index = min(len(self.values) - 1, self._selected_index + 1) - @kb.add('pageup') + @kb.add("pageup") def _(event): if not self.values: return @@ -191,7 +190,7 @@ def _(event): self._selected_index - len(w.render_info.displayed_lines), ) - @kb.add('pagedown') + @kb.add("pagedown") def _(event): if not self.values: return @@ -201,7 +200,7 @@ def _(event): self._selected_index + len(w.render_info.displayed_lines), ) - @kb.add(' ') + @kb.add(" ") def _(event): if not self.values: return @@ -215,22 +214,22 @@ def _(event): if not self.values: return # We first check values after the selected value, then all values. - for value in self.values[self._selected_index + 1:] + self.values: + for value in self.values[self._selected_index + 1 :] + self.values: if value[1].startswith(event.data): self._selected_index = self.values.index(value) return # Control and window. self.control = FormattedTextControl( - lambda: self._get_text_fragments(style), - key_bindings=kb, - focusable=True) + lambda: self._get_text_fragments(style), key_bindings=kb, focusable=True + ) self.window = Window( content=self.control, - style='class:checkbox-list', + style="class:checkbox-list", right_margins=[ScrollbarMargin(display_arrows=True)], - dont_extend_height=True) + dont_extend_height=True, + ) if default: self.value = default @@ -253,33 +252,33 @@ def select_none(self): def _generate_fragments(self, out_style): result = [] for i, value in enumerate(self.values): - checked = (value[0] in self.checked) - selected = (i == self._selected_index) + checked = value[0] in self.checked + selected = i == self._selected_index style = out_style if checked: - style += ' class:checkbox-checked' + style += " class:checkbox-checked" if selected: - style += ' class:checkbox-selected' + style += " class:checkbox-selected" - result.append((style, '[')) + result.append((style, "[")) if selected: - result.append(('[SetCursorPosition]', '')) + result.append(("[SetCursorPosition]", "")) if checked: - result.append((style, '*')) + result.append((style, "*")) else: - result.append((style, ' ')) + result.append((style, " ")) - result.append((style, ']')) - result.append((out_style + ' class:checkbox', ' ')) + result.append((style, "]")) + result.append((out_style + " class:checkbox", " ")) result.extend( to_formatted_text( value[1], - style=out_style + ' class:checkbox', + style=out_style + " class:checkbox", ), ) - result.append(('', '\n')) + result.append(("", "\n")) return result def _get_text_fragments(self, out_style): # pragma: no cover @@ -309,15 +308,15 @@ def __pt_container__(self): class FixedLengthBuffer(Buffer): def __init__(self, **kwargs): - self._max_length = kwargs.pop('max_length') - self._allowed_chars = kwargs.pop('allowed_chars') - self._widget = kwargs.pop('widget') + self._max_length = kwargs.pop("max_length") + self._allowed_chars = kwargs.pop("allowed_chars") + self._widget = kwargs.pop("widget") super().__init__(**kwargs) def _is_input_allowed(self, data): if not self._allowed_chars: return True - return all([char in self._allowed_chars for char in data]) + return all(char in self._allowed_chars for char in data) def insert_text( self, @@ -342,10 +341,9 @@ def delete_before_cursor(self, count=1): class FixedLengthTextArea(TextArea): - def __init__( self, - text='', + text="", width=None, height=None, max_length=None, @@ -353,7 +351,6 @@ def __init__( widget=None, style=None, ): - self.max_length = max_length self.buffer = FixedLengthBuffer( @@ -383,11 +380,10 @@ def __init__( class MaskedInput(VSplit): - def __init__( self, mask, - placeholder='_', + placeholder="_", style=None, default=None, allowed_chars=None, @@ -427,7 +423,7 @@ def __init__( ) self._components.append(widget) self._fields.append(widget) - self._components.append(Label('')) + self._components.append(Label("")) if default: self.value = default @@ -447,15 +443,18 @@ def go_next(self, component): get_app().layout.focus_next() def _has_value(self): - values = ''.join([ - cmp.text for cmp in self._components - if isinstance(cmp, FixedLengthTextArea) - ]).strip() + values = "".join( + [ + cmp.text + for cmp in self._components + if isinstance(cmp, FixedLengthTextArea) + ] + ).strip() return bool(values) def _build_value(self): if self._has_value(): - return ''.join([cmp.text for cmp in self._components]) + return "".join([cmp.text for cmp in self._components]) return None @property @@ -465,48 +464,56 @@ def value(self): @value.setter def value(self, val): if len(val) != len(self._mask): - raise ValueError('Invalid value length') + raise ValueError("Invalid value length") pos = 0 - non_mask_chars = self._mask.replace(self._placeholder, '') + non_mask_chars = self._mask.replace(self._placeholder, "") for char in non_mask_chars: - val = val.replace(char, '') + val = val.replace(char, "") for field in self._fields: - field.text = val[pos:pos + field.max_length] + field.text = val[pos : pos + field.max_length] pos += field.max_length class DateRange(HSplit): - def __init__( self, - from_label='From: ', - to_label=' to: ', + from_label="From: ", + to_label=" to: ", style=None, ): - self._from = MaskedInput( - mask='____-__-__', allowed_chars=string.digits, style=style, + mask="____-__-__", + allowed_chars=string.digits, + style=style, ) self._to = MaskedInput( - mask='____-__-__', allowed_chars=string.digits, style=style, + mask="____-__-__", + allowed_chars=string.digits, + style=style, ) components = [] if from_label: - components.append(VSplit([ - Label(from_label, dont_extend_width=True), - self._from, - ])) + components.append( + VSplit( + [ + Label(from_label, dont_extend_width=True), + self._from, + ] + ) + ) else: components.append(self._from) if to_label: components.append( - VSplit([ - Label(to_label, dont_extend_width=True), - self._to, - ]), + VSplit( + [ + Label(to_label, dont_extend_width=True), + self._to, + ] + ), ) else: components.append(self._to) @@ -516,14 +523,14 @@ def __init__( @property def value(self): return { - 'from': self._from.value, - 'to': self._to.value, + "from": self._from.value, + "to": self._to.value, } @value.setter def value(self, val): - if 'from' in val: - self._from.value = val['from'] + if "from" in val: + self._from.value = val["from"] - if 'to' in val: - self._to.value = val['to'] + if "to" in val: + self._to.value = val["to"] diff --git a/interrogatio/widgets/wizard.py b/interrogatio/widgets/wizard.py index 6c6b7eb..d2d7dbb 100644 --- a/interrogatio/widgets/wizard.py +++ b/interrogatio/widgets/wizard.py @@ -2,7 +2,7 @@ from prompt_toolkit.application import get_app from prompt_toolkit.filters import has_focus -from prompt_toolkit.formatted_text import FormattedText, HTML, to_formatted_text +from prompt_toolkit.formatted_text import HTML, FormattedText, to_formatted_text from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous from prompt_toolkit.key_binding.key_bindings import KeyBindings from prompt_toolkit.keys import Keys @@ -20,9 +20,15 @@ class WizardDialog: def __init__( # noqa: CCR001 - self, title, handlers, intro=None, summary=False, - next_text='Next', previous_text='Previous', - cancel_text='Cancel', finish_text='Finish', + self, + title, + handlers, + intro=None, + summary=False, + next_text="Next", + previous_text="Previous", + cancel_text="Cancel", + finish_text="Finish", fast_forward=False, ): self.title = title @@ -39,7 +45,7 @@ def __init__( # noqa: CCR001 self.label_previous = previous_text self.label_cancel = cancel_text self.label_finish = finish_text - self.error_messages = '' + self.error_messages = "" self.cancel_btn = Button( text=self.label_cancel, @@ -63,8 +69,8 @@ def __init__( # noqa: CCR001 first_selected = has_focus(self.buttons[0]) last_selected = has_focus(self.buttons[-1]) - self.buttons_kb.add('left', filter=~first_selected)(focus_previous) - self.buttons_kb.add('right', filter=~last_selected)(focus_next) + self.buttons_kb.add("left", filter=~first_selected)(focus_previous) + self.buttons_kb.add("right", filter=~last_selected)(focus_next) input_container = HSplit( [ @@ -93,9 +99,9 @@ def __init__( # noqa: CCR001 ) top_container = VSplit( [left_container, right_container], - padding_char='│', + padding_char="│", padding=1, - padding_style='#000000', + padding_style="#000000", height=D(min=10, preferred=24), ) @@ -116,35 +122,33 @@ def __init__( # noqa: CCR001 top_container, buttons_container, ], - padding_char='─', + padding_char="─", padding=1, - padding_style='#000000', + padding_style="#000000", ), - style='class:dialog.body', + style="class:dialog.body", key_bindings=kb, width=D(min=78, preferred=132), ), ) self.container = Box( - body=frame, style='class:dialog', + body=frame, + style="class:dialog", ) def get_title(self): - return ( - f'{self.title} - {self.current_step_idx + 1} of {len(self.steps)}' - ) + return f"{self.title} - {self.current_step_idx + 1} of {len(self.steps)}" def _get_step_style(self, idx): if idx == self.current_step_idx: - return 'class:dialog.step.current' + return "class:dialog.step.current" - if ( - self.steps[idx].get('handler') - and self.steps[idx]['handler'].is_disabled(context=self.answers) + if self.steps[idx].get("handler") and self.steps[idx]["handler"].is_disabled( + context=self.answers ): - return 'class:dialog.step.disabled' + return "class:dialog.step.disabled" - return 'class:dialog.step' + return "class:dialog.step" def get_steps_labels(self): steps_labels = [] @@ -167,27 +171,27 @@ def get_status(self): if self.error_messages: return Window( FormattedTextControl( - FormattedText([('class:error', self.error_messages)]), + FormattedText([("class:error", self.error_messages)]), ), height=1, ) - return Label('') + return Label("") def get_summary(self): if isinstance(self.summary, bool): - text = '\n'.join( + text = "\n".join( [ - f'{handler.get_variable_name().capitalize()}:' - f' {handler.get_formatted_value()}' + f"{handler.get_variable_name().capitalize()}:" + f" {handler.get_formatted_value()}" for handler in self.handlers ], ) elif callable(self.summary): data = { handler.get_variable_name(): { - 'question': handler.get_question(), - 'value': handler.get_value(), - 'formatted_value': handler.get_formatted_value(), + "question": handler.get_question(), + "value": handler.get_value(), + "formatted_value": handler.get_formatted_value(), } for handler in self.handlers } @@ -205,7 +209,7 @@ def get_summary(self): ) def get_current_step_container(self): - return self.current_step['layout'] + return self.current_step["layout"] def get_buttons_container(self): return VSplit( @@ -222,9 +226,9 @@ def process_steps(self): ) self.steps.append( { - 'layout': layout, - 'label': 'Introduction', - 'handler': None, + "layout": layout, + "label": "Introduction", + "handler": None, }, ) @@ -233,9 +237,9 @@ def process_steps(self): layout.align = HorizontalAlign.JUSTIFY self.steps.append( { - 'layout': layout, - 'label': handler.get_label(), - 'handler': handler, + "layout": layout, + "label": handler.get_label(), + "handler": handler, }, ) @@ -247,9 +251,9 @@ def process_steps(self): ) self.steps.append( { - 'layout': layout, - 'label': 'Summary', - 'handler': None, + "layout": layout, + "label": "Summary", + "handler": None, }, ) @@ -257,7 +261,7 @@ def _check_no_next_steps(self): idx = self.current_step_idx + 1 while idx <= len(self.steps) - 1: next_step = self.steps[idx] - next_handler = next_step['handler'] + next_handler = next_step["handler"] if next_handler and not next_handler.is_disabled(self.answers): return False idx += 1 @@ -273,9 +277,8 @@ def set_buttons_labels(self): self.buttons = [self.next_btn, self.cancel_btn] return - if ( - self.current_step_idx == len(self.steps) - 1 - or (self._check_no_next_steps() and not self.summary) + if self.current_step_idx == len(self.steps) - 1 or ( + self._check_no_next_steps() and not self.summary ): self.next_btn.text = self.label_finish else: @@ -288,31 +291,31 @@ def cancel(self): def previous(self): if self.current_step_idx != 0: - self.error_messages = '' + self.error_messages = "" self.current_step_idx -= 1 self.current_step = self.steps[self.current_step_idx] - handler = self.current_step['handler'] + handler = self.current_step["handler"] if handler and handler.is_disabled(self.answers): return self.previous() - get_app().layout.focus(self.current_step['layout']) + get_app().layout.focus(self.current_step["layout"]) self.set_buttons_labels() def next(self): # noqa: CCR001 if self.validate(): if self.current_step_idx < len(self.steps) - 1: - handler = self.current_step['handler'] + handler = self.current_step["handler"] if handler: self.answers.update(handler.get_answer()) self.current_step_idx += 1 self.current_step = self.steps[self.current_step_idx] - handler = self.current_step['handler'] + handler = self.current_step["handler"] if handler: if handler.is_disabled(context=self.answers): return self.next() # noqa: B305 handler.set_context(self.answers) if not self.summary or self.current_step != self.steps[-1]: - get_app().layout.focus(self.current_step['layout']) + get_app().layout.focus(self.current_step["layout"]) else: get_app().exit(result=True) @@ -322,7 +325,7 @@ def fast_forward(self): while self.current_step_idx < len(self.steps) - 1: if self.validate(): step = self.steps[self.current_step_idx] - handler = step['handler'] + handler = step["handler"] if handler and not handler.is_disabled(self.answers): self.answers.update(handler.get_answer()) handler.set_context(self.answers) @@ -335,15 +338,15 @@ def fast_forward(self): def validate(self): step = self.steps[self.current_step_idx] - handler = step['handler'] + handler = step["handler"] if ( - handler - and not handler.is_valid(self.answers) - and not handler.is_disabled(self.answers) + handler + and not handler.is_valid(self.answers) + and not handler.is_disabled(self.answers) ): - self.error_messages = ','.join(handler.errors) + self.error_messages = ",".join(handler.errors) return False - self.error_messages = '' + self.error_messages = "" return True def __pt_container__(self): # pragma: no cover diff --git a/poetry.lock b/poetry.lock index fb0fd67..6ed2c8b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,85 +1,63 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "alabaster" -version = "0.7.12" +version = "0.7.13" description = "A configurable sidebar-enabled Sphinx theme" -category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, - {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, + {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, + {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, ] [[package]] name = "appnope" -version = "0.1.3" +version = "0.1.4" description = "Disable App Nap on macOS >= 10.9" -category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, ] [[package]] name = "asttokens" -version = "2.2.1" +version = "3.0.0" description = "Annotate AST trees with source code positions" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "asttokens-2.2.1-py2.py3-none-any.whl", hash = "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c"}, - {file = "asttokens-2.2.1.tar.gz", hash = "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3"}, -] - -[package.dependencies] -six = "*" - -[package.extras] -test = ["astroid", "pytest"] - -[[package]] -name = "attrs" -version = "22.1.0" -description = "Classes Without Boilerplate" -category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, + {file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"}, + {file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"}, ] [package.extras] -dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] -docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] -tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +astroid = ["astroid (>=2,<4)"] +test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "babel" -version = "2.11.0" +version = "2.16.0" description = "Internationalization utilities" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"}, - {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"}, + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, ] [package.dependencies] -pytz = ">=2015.7" +pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "backcall" version = "0.2.0" description = "Specifications for callback functions passed in to an API" -category = "dev" optional = false python-versions = "*" files = [ @@ -91,7 +69,6 @@ files = [ name = "backports-zoneinfo" version = "0.2.1" description = "Backport of the standard library zoneinfo module" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -118,50 +95,133 @@ tzdata = ["tzdata"] [[package]] name = "certifi" -version = "2022.9.24" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, - {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "charset-normalizer" -version = "2.1.1" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "dev" -optional = false -python-versions = ">=3.6.0" -files = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, -] - -[package.extras] -unicode-backport = ["unicodedata2"] - -[[package]] -name = "cognitive-complexity" -version = "1.3.0" -description = "Library to calculate Python functions cognitive complexity via code" -category = "dev" optional = false -python-versions = ">=3.6" -files = [ - {file = "cognitive_complexity-1.3.0.tar.gz", hash = "sha256:a0cfbd47dee0b19f4056f892389f501694b205c3af69fb703cc744541e03dde5"}, +python-versions = ">=3.7.0" +files = [ + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -173,7 +233,6 @@ files = [ name = "coverage" version = "6.5.0" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -239,7 +298,6 @@ toml = ["tomli"] name = "decorator" version = "5.1.1" description = "Decorators for Humans" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -249,26 +307,24 @@ files = [ [[package]] name = "docutils" -version = "0.17.1" +version = "0.18.1" description = "Docutils -- Python Documentation Utilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, - {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, + {file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"}, + {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, ] [[package]] name = "exceptiongroup" -version = "1.0.4" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"}, - {file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -276,177 +332,81 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "1.2.0" +version = "2.1.0" description = "Get the currently executing AST node of a frame, and other information" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"}, - {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"}, -] - -[package.extras] -tests = ["asttokens", "littleutils", "pytest", "rich"] - -[[package]] -name = "flake8" -version = "3.9.2" -description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -files = [ - {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, - {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, -] - -[package.dependencies] -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.7.0,<2.8.0" -pyflakes = ">=2.3.0,<2.4.0" - -[[package]] -name = "flake8-broken-line" -version = "0.6.0" -description = "Flake8 plugin to forbid backslashes for line breaks" -category = "dev" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "flake8-broken-line-0.6.0.tar.gz", hash = "sha256:a02268f11a18837c83c59013a36cc00fee9e17a042745cc0c9895f1c9f6acc16"}, - {file = "flake8_broken_line-0.6.0-py3-none-any.whl", hash = "sha256:c0ab336ff7de228dbffbe56d67b3615bb21fb15f3ed0604fa7bdf9feb72d7d88"}, -] - -[package.dependencies] -flake8 = ">=3.5,<6" - -[[package]] -name = "flake8-bugbear" -version = "22.12.6" -description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "flake8-bugbear-22.12.6.tar.gz", hash = "sha256:4cdb2c06e229971104443ae293e75e64c6107798229202fbe4f4091427a30ac0"}, - {file = "flake8_bugbear-22.12.6-py3-none-any.whl", hash = "sha256:b69a510634f8a9c298dfda2b18a8036455e6b19ecac4fe582e4d7a0abfa50a30"}, + {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, + {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, ] -[package.dependencies] -attrs = ">=19.2.0" -flake8 = ">=3.0.0" - [package.extras] -dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "tox"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] [[package]] -name = "flake8-cognitive-complexity" -version = "0.1.0" -description = "An extension for flake8 that validates cognitive functions complexity" -category = "dev" +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" files = [ - {file = "flake8_cognitive_complexity-0.1.0.tar.gz", hash = "sha256:f202df054e4f6ff182b659c261922b9c684628a47beb19cb0973c50d6a7831c1"}, -] - -[package.dependencies] -cognitive_complexity = "*" -setuptools = "*" - -[[package]] -name = "flake8-commas" -version = "2.0.0" -description = "Flake8 lint for trailing commas." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "flake8-commas-2.0.0.tar.gz", hash = "sha256:d3005899466f51380387df7151fb59afec666a0f4f4a2c6a8995b975de0f44b7"}, - {file = "flake8_commas-2.0.0-py2.py3-none-any.whl", hash = "sha256:ee2141a3495ef9789a3894ed8802d03eff1eaaf98ce6d8653a7c573ef101935e"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] -[package.dependencies] -flake8 = ">=2,<4.0.0" +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] [[package]] -name = "flake8-future-import" -version = "0.4.7" -description = "__future__ import checker, plugin for flake8" -category = "dev" +name = "imagesize" +version = "1.4.1" +description = "Getting image size from png/jpeg/jpeg2000/gif file" optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "flake8-future-import-0.4.7.tar.gz", hash = "sha256:ed826cca28fd4b55c486d69c4bfb32e9a052efc66714bf22bf471f50ecf8e0de"}, - {file = "flake8_future_import-0.4.7-py2.py3-none-any.whl", hash = "sha256:7ecb1b89f5e026afb0cfdb8642d150bf56efbb6fb86a713ea4568398142f47ae"}, + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] -[package.dependencies] -flake8 = "*" - [[package]] -name = "flake8-import-order" -version = "0.18.2" -description = "Flake8 and pylama plugin that checks the ordering of import statements." -category = "dev" +name = "importlib-metadata" +version = "1.4.0" +description = "Read metadata from Python packages" optional = false -python-versions = "*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ - {file = "flake8-import-order-0.18.2.tar.gz", hash = "sha256:e23941f892da3e0c09d711babbb0c73bc735242e9b216b726616758a920d900e"}, - {file = "flake8_import_order-0.18.2-py2.py3-none-any.whl", hash = "sha256:82ed59f1083b629b030ee9d3928d9e06b6213eb196fe745b3a7d4af2168130df"}, + {file = "importlib_metadata-1.4.0-py2.py3-none-any.whl", hash = "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359"}, + {file = "importlib_metadata-1.4.0.tar.gz", hash = "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8"}, ] [package.dependencies] -pycodestyle = "*" -setuptools = "*" - -[[package]] -name = "idna" -version = "3.4" -description = "Internationalized Domain Names in Applications (IDNA)" -category = "dev" -optional = false -python-versions = ">=3.5" -files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, -] +zipp = ">=0.5" -[[package]] -name = "imagesize" -version = "1.4.1" -description = "Getting image size from png/jpeg/jpeg2000/gif file" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, - {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, -] +[package.extras] +docs = ["rst.linker", "sphinx"] +testing = ["importlib-resources", "packaging"] [[package]] name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] [[package]] name = "ipython" -version = "8.10.0" +version = "8.12.3" description = "IPython: Productive Interactive Computing" -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "ipython-8.10.0-py3-none-any.whl", hash = "sha256:b38c31e8fc7eff642fc7c597061fff462537cf2314e3225a19c906b7b0d8a345"}, - {file = "ipython-8.10.0.tar.gz", hash = "sha256:b13a1d6c1f5818bd388db53b7107d17454129a70de2b87481d555daede5eb49e"}, + {file = "ipython-8.12.3-py3-none-any.whl", hash = "sha256:b0340d46a933d27c657b211a329d0be23793c36595acf9e6ef4164bc01a1804c"}, + {file = "ipython-8.12.3.tar.gz", hash = "sha256:3910c4b54543c2ad73d06579aa771041b7d5707b033bd488669b4cf544e3b363"}, ] [package.dependencies] @@ -458,10 +418,11 @@ jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} pickleshare = "*" -prompt-toolkit = ">=3.0.30,<3.1.0" +prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5" +typing-extensions = {version = "*", markers = "python_version < \"3.10\""} [package.extras] all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] @@ -478,34 +439,32 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa [[package]] name = "jedi" -version = "0.18.2" +version = "0.19.2" description = "An autocompletion tool for Python that can be used for text editors." -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "jedi-0.18.2-py2.py3-none-any.whl", hash = "sha256:203c1fd9d969ab8f2119ec0a3342e0b49910045abe6af0a3ae83a5764d54639e"}, - {file = "jedi-0.18.2.tar.gz", hash = "sha256:bae794c30d07f6d910d32a7048af09b5a39ed740918da923c6b780790ebac612"}, + {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, + {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, ] [package.dependencies] -parso = ">=0.8.0,<0.9.0" +parso = ">=0.8.4,<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 (==3.8.3)", "mypy (==0.782)"] -testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.4" description = "A very fast and expressive template engine." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -516,122 +475,122 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "markupsafe" -version = "2.1.1" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, - {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] name = "matplotlib-inline" -version = "0.1.6" +version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" -category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, + {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, + {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, ] [package.dependencies] traitlets = "*" -[[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] - [[package]] name = "packaging" -version = "21.3" +version = "24.2" description = "Core utilities for Python packages" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - [[package]] name = "parso" -version = "0.8.3" +version = "0.8.4" description = "A Python Parser" -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, ] [package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] [[package]] name = "pexpect" -version = "4.8.0" +version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." -category = "dev" optional = false python-versions = "*" files = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, ] [package.dependencies] @@ -641,7 +600,6 @@ ptyprocess = ">=0.5" name = "pickleshare" version = "0.7.5" description = "Tiny 'shelve'-like database with concurrency support" -category = "dev" optional = false python-versions = "*" files = [ @@ -651,14 +609,13 @@ files = [ [[package]] name = "pluggy" -version = "1.0.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -667,14 +624,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "prompt-toolkit" -version = "3.0.36" +version = "3.0.48" description = "Library for building powerful interactive command lines in Python" -category = "main" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.36-py3-none-any.whl", hash = "sha256:aa64ad242a462c5ff0363a7b9cfe696c20d55d9fc60c11fd8e632d064804d305"}, - {file = "prompt_toolkit-3.0.36.tar.gz", hash = "sha256:3e163f254bef5a03b146397d7c1963bd3e2812f0964bb9a24e6ec761fd28db63"}, + {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, + {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, ] [package.dependencies] @@ -684,7 +640,6 @@ wcwidth = "*" name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -694,87 +649,44 @@ files = [ [[package]] name = "pure-eval" -version = "0.2.2" +version = "0.2.3" description = "Safely evaluate AST nodes without side effects" -category = "dev" optional = false python-versions = "*" files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, + {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, + {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, ] [package.extras] tests = ["pytest"] -[[package]] -name = "pycodestyle" -version = "2.7.0" -description = "Python style guide checker" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, - {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, -] - -[[package]] -name = "pyflakes" -version = "2.3.1" -description = "passive checker of Python programs" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, - {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, -] - [[package]] name = "pygments" -version = "2.13.0" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, - {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, -] - -[package.extras] -plugins = ["importlib-metadata"] - -[[package]] -name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "dev" optional = false -python-versions = ">=3.6.8" +python-versions = ">=3.8" files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -diagrams = ["jinja2", "railroad-diagrams"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" -version = "7.2.0" +version = "7.4.4" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, - {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" @@ -783,18 +695,17 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" -version = "4.0.0" +version = "4.1.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, - {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, ] [package.dependencies] @@ -806,39 +717,36 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "pytest-mock" -version = "3.10.0" +version = "3.14.0" description = "Thin-wrapper around the mock package for easier use with pytest" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-mock-3.10.0.tar.gz", hash = "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f"}, - {file = "pytest_mock-3.10.0-py3-none-any.whl", hash = "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b"}, + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, ] [package.dependencies] -pytest = ">=5.0" +pytest = ">=6.2.5" [package.extras] dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "pytz" -version = "2022.6" +version = "2022.7.1" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" files = [ - {file = "pytz-2022.6-py2.py3-none-any.whl", hash = "sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427"}, - {file = "pytz-2022.6.tar.gz", hash = "sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"}, + {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, + {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, ] [[package]] name = "pytz-deprecation-shim" version = "0.1.0.post0" description = "Shims to make deprecation of pytz easier" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -852,110 +760,148 @@ tzdata = {version = "*", markers = "python_version >= \"3.6\""} [[package]] name = "pyyaml" -version = "6.0" +version = "6.0.2" description = "YAML parser and emitter for Python" -category = "main" optional = true -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "requests" -version = "2.28.1" +version = "2.32.3" description = "Python HTTP for Humans." -category = "dev" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.8" files = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2,<3" +charset-normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "ruff" +version = "0.3.7" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e8377cccb2f07abd25e84fc5b2cbe48eeb0fea9f1719cad7caedb061d70e5ce"}, + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:15a4d1cc1e64e556fa0d67bfd388fed416b7f3b26d5d1c3e7d192c897e39ba4b"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28bdf3d7dc71dd46929fafeec98ba89b7c3550c3f0978e36389b5631b793663"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:379b67d4f49774ba679593b232dcd90d9e10f04d96e3c8ce4a28037ae473f7bb"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c060aea8ad5ef21cdfbbe05475ab5104ce7827b639a78dd55383a6e9895b7c51"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ebf8f615dde968272d70502c083ebf963b6781aacd3079081e03b32adfe4d58a"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48098bd8f5c38897b03604f5428901b65e3c97d40b3952e38637b5404b739a2"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da8a4fda219bf9024692b1bc68c9cff4b80507879ada8769dc7e985755d662ea"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c44e0149f1d8b48c4d5c33d88c677a4aa22fd09b1683d6a7ff55b816b5d074f"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3050ec0af72b709a62ecc2aca941b9cd479a7bf2b36cc4562f0033d688e44fa1"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a29cc38e4c1ab00da18a3f6777f8b50099d73326981bb7d182e54a9a21bb4ff7"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b15cc59c19edca917f51b1956637db47e200b0fc5e6e1878233d3a938384b0b"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e491045781b1e38b72c91247cf4634f040f8d0cb3e6d3d64d38dcf43616650b4"}, + {file = "ruff-0.3.7-py3-none-win32.whl", hash = "sha256:bc931de87593d64fad3a22e201e55ad76271f1d5bfc44e1a1887edd0903c7d9f"}, + {file = "ruff-0.3.7-py3-none-win_amd64.whl", hash = "sha256:5ef0e501e1e39f35e03c2acb1d1238c595b8bb36cf7a170e7c1df1b73da00e74"}, + {file = "ruff-0.3.7-py3-none-win_arm64.whl", hash = "sha256:789e144f6dc7019d1f92a812891c645274ed08af6037d11fc65fcbc183b7d59f"}, + {file = "ruff-0.3.7.tar.gz", hash = "sha256:d5c1aebee5162c2226784800ae031f660c350e7a3402c4d1f8ea4e97e232e3ba"}, +] + [[package]] name = "setuptools" -version = "65.6.3" +version = "75.3.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"}, - {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"}, + {file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"}, + {file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.12.*)", "pytest-mypy"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] name = "snowballstemmer" version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "dev" optional = false python-versions = "*" files = [ @@ -965,21 +911,20 @@ files = [ [[package]] name = "sphinx" -version = "1.8.6" +version = "1.8.5" description = "Python documentation generator" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "Sphinx-1.8.6-py2.py3-none-any.whl", hash = "sha256:5973adbb19a5de30e15ab394ec8bc05700317fa83f122c349dd01804d983720f"}, - {file = "Sphinx-1.8.6.tar.gz", hash = "sha256:e096b1b369dbb0fcb95a31ba8c9e1ae98c588e601f08eada032248e1696de4b1"}, + {file = "Sphinx-1.8.5-py2.py3-none-any.whl", hash = "sha256:9f3e17c64b34afc653d7c5ec95766e03043cc6d80b0de224f59b6b6e19d37c3c"}, + {file = "Sphinx-1.8.5.tar.gz", hash = "sha256:c7658aab75c920288a8cf6f09f244c6cfdae30d82d803ac1634d9f223a80ca08"}, ] [package.dependencies] alabaster = ">=0.7,<0.8" babel = ">=1.3,<2.0 || >2.0" colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.11,<0.18" +docutils = ">=0.11" imagesize = "*" Jinja2 = ">=2.3" packaging = "*" @@ -996,28 +941,41 @@ websupport = ["sqlalchemy (>=0.9)", "whoosh (>=2.0)"] [[package]] name = "sphinx-rtd-theme" -version = "1.1.1" +version = "1.3.0" description = "Read the Docs theme for Sphinx" -category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "sphinx_rtd_theme-1.1.1-py2.py3-none-any.whl", hash = "sha256:31faa07d3e97c8955637fc3f1423a5ab2c44b74b8cc558a51498c202ce5cbda7"}, - {file = "sphinx_rtd_theme-1.1.1.tar.gz", hash = "sha256:6146c845f1e1947b3c3dd4432c28998a1693ccc742b4f9ad7c63129f0757c103"}, + {file = "sphinx_rtd_theme-1.3.0-py2.py3-none-any.whl", hash = "sha256:46ddef89cc2416a81ecfbeaceab1881948c014b1b6e4450b815311a89fb977b0"}, + {file = "sphinx_rtd_theme-1.3.0.tar.gz", hash = "sha256:590b030c7abb9cf038ec053b95e5380b5c70d61591eb0b552063fbe7c41f0931"}, ] [package.dependencies] -docutils = "<0.18" -sphinx = ">=1.6,<6" +docutils = "<0.19" +sphinx = ">=1.6,<8" +sphinxcontrib-jquery = ">=4,<5" [package.extras] dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +description = "Extension to include jQuery on newer Sphinx releases" +optional = false +python-versions = ">=2.7" +files = [ + {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, + {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, +] + +[package.dependencies] +Sphinx = ">=1.8" + [[package]] name = "sphinxcontrib-serializinghtml" version = "1.1.5" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1033,7 +991,6 @@ test = ["pytest"] name = "sphinxcontrib-websupport" version = "1.2.4" description = "Sphinx API for Web Apps" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1050,14 +1007,13 @@ test = ["Sphinx", "pytest", "sqlalchemy", "whoosh"] [[package]] name = "stack-data" -version = "0.6.2" +version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" -category = "dev" optional = false python-versions = "*" files = [ - {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"}, - {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"}, + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, ] [package.dependencies] @@ -1070,54 +1026,91 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "tomli" -version = "2.0.1" +version = "2.2.1" description = "A lil' TOML parser" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] name = "traitlets" -version = "5.6.0" +version = "5.14.3" description = "Traitlets Python configuration system" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "traitlets-5.6.0-py3-none-any.whl", hash = "sha256:1410755385d778aed847d68deb99b3ba30fbbf489e17a1e8cbb753060d5cce73"}, - {file = "traitlets-5.6.0.tar.gz", hash = "sha256:10b6ed1c9cedee83e795db70a8b9c2db157bb3778ec4587a349ecb7ef3b1033b"}, + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["pre-commit", "pytest"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] [[package]] name = "tzdata" -version = "2022.7" +version = "2024.2" description = "Provider of IANA time zone data" -category = "main" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2022.7-py2.py3-none-any.whl", hash = "sha256:2b88858b0e3120792a3c0635c23daf36a7d7eeeca657c323da299d2094402a0d"}, - {file = "tzdata-2022.7.tar.gz", hash = "sha256:fe5f866eddd8b96e9fcba978f8e503c909b19ea7efda11e52e39494bad3a7bfa"}, + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] [[package]] name = "tzlocal" -version = "4.2" +version = "4.3.1" description = "tzinfo object for the local timezone" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "tzlocal-4.2-py3-none-any.whl", hash = "sha256:89885494684c929d9191c57aa27502afc87a579be5cdd3225c77c463ea043745"}, - {file = "tzlocal-4.2.tar.gz", hash = "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7"}, + {file = "tzlocal-4.3.1-py3-none-any.whl", hash = "sha256:67d7e7f4ce0a98e9dfde2e02474c60fe846ed032d78b555c554c2e9cba472d84"}, + {file = "tzlocal-4.3.1.tar.gz", hash = "sha256:ee32ef8c20803c19a96ed366addd3d4a729ef6309cb5c7359a0cc2eeeb7fa46a"}, ] [package.dependencies] @@ -1126,31 +1119,29 @@ pytz-deprecation-shim = "*" tzdata = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"] -test = ["pytest (>=4.3)", "pytest-mock (>=3.3)"] +devenv = ["black", "check-manifest", "flake8", "pyroma", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] [[package]] name = "urllib3" -version = "1.26.13" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.8" files = [ - {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, - {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "validators" version = "0.18.2" description = "Python Data Validation for Humans™." -category = "main" optional = false python-versions = ">=3.4" files = [ @@ -1167,20 +1158,38 @@ test = ["flake8 (>=2.4.0)", "isort (>=4.2.2)", "pytest (>=2.2.3)"] [[package]] name = "wcwidth" -version = "0.2.5" +version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" -category = "main" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, - {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + +[[package]] +name = "zipp" +version = "3.20.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, ] +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + [extras] yaml = ["PyYAML"] [metadata] lock-version = "2.0" -python-versions = "^3.8" -content-hash = "4347a35f73b4e6a6ff92604b7b54f825c423dccf08529eb202194ac1052fbedb" +python-versions = ">=3.8,<4" +content-hash = "25ec60db7644950fc5bac3b8a08d4c220f835402d87974461bfd7255f44ff9bc" diff --git a/pyproject.toml b/pyproject.toml index 904b8d2..b8c4c53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,17 +18,22 @@ classifiers = [ "Intended Audience :: Developers", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Utilities", "Topic :: Software Development :: Libraries", ] [tool.poetry.dependencies] -python = "^3.8" +python = ">=3.8,<4" prompt-toolkit = ">=3.0.29" PyYAML = {version = ">=5", optional = true } validators = "^0.18.2" pytz = "^2022.1" tzlocal = "^4.1" +importlib-metadata = "1.4" [tool.poetry.extras] yaml = ["PyYAML"] @@ -40,13 +45,7 @@ pytest = ">=6.1.2,<8" pytest-cov = ">=2.10.1,<5" pytest-mock = "^3.3.1" coverage = {extras = ["toml"], version = ">=5.3,<7"} -flake8 = ">=3.8,<6" -flake8-bugbear = ">=20,<23" -flake8-cognitive-complexity = "^0.1" -flake8-commas = "~2.0" -flake8-future-import = "~0.4" -flake8-import-order = "~0.18" -flake8-broken-line = ">=0.3,<0.7" +ruff = "0.3.*" Sphinx = "^1.8.5" sphinx-rtd-theme = "^1.0.0" @@ -65,6 +64,7 @@ addopts = "--cov=interrogatio --cov-report=term-missing:skip-covered --cov-repor [tool.coverage.run] branch = true +relative_files = true [tool.coverage.report] omit = [ @@ -79,3 +79,31 @@ exclude_lines = [ "raise NotImplementedError", "if __name__ == .__main__.:", ] + + +[tool.ruff] +extend-exclude = [".vscode", ".devcontainer"] +output-format = "full" + +[tool.ruff.lint] + +select = [ + "E", # w errors + "W", # pycodestyle warnings + "F", # pyflakes + "I", # isort + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "UP", # pyupgrade, + "PT", # flake8-pytest-style + "T10", # flake8-pytest-style +] +ignore = [ + "PT004", # fixture '{name}' does not return anything, add leading underscore + "PT011", # pytest.raises({exception}) is too broad, set the match parameter or use a more specific exception + "B008", # do not perform function calls in argument defaults + "B904", # Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling +] + +[tool.ruff.lint.pycodestyle] +max-line-length = 100 \ No newline at end of file diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..9ea7cbe --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,13 @@ +sonar.projectKey=ffaraone_interrogatio +sonar.organization=ffaraone + +sonar.language=py + +sonar.sources=interrogatio +sonar.tests=tests +sonar.inclusions=interrogatio/** +sonar.exclusions=tests/**,Dockerfile + +sonar.python.coverage.reportPaths=coverage.xml +sonar.python.xunit.reportPath=coverage.xml +sonar.python.version=3 \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 186c1a0..cd22e1c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,31 +12,31 @@ from interrogatio.validators.registry import _registry as v_registry -@pytest.fixture +@pytest.fixture() def handlers_registry(mocker): registry_copy = copy.deepcopy(h_registry) registry_copy.clear() mocker.patch( - 'interrogatio.handlers.registry.get_registry', + "interrogatio.handlers.registry.get_registry", return_value=registry_copy, ) yield registry_copy registry_copy.clear() -@pytest.fixture +@pytest.fixture() def validators_registry(mocker): registry_copy = copy.deepcopy(v_registry) registry_copy.clear() mocker.patch( - 'interrogatio.validators.registry.get_registry', + "interrogatio.validators.registry.get_registry", return_value=registry_copy, ) yield registry_copy registry_copy.clear() -@pytest.fixture +@pytest.fixture() def test_handler(): class TestHandler(QHandler): def get_layout(self): @@ -57,7 +57,7 @@ def get_keybindings(self): return TestHandler -@pytest.fixture +@pytest.fixture() def mock_input(): with create_pipe_input() as pipe_input: try: diff --git a/tests/core/test_dialog.py b/tests/core/test_dialog.py index 5c7bcf5..b77c080 100644 --- a/tests/core/test_dialog.py +++ b/tests/core/test_dialog.py @@ -2,80 +2,79 @@ def test_dialogus(mocker): - mocked_set_theme = mocker.patch('interrogatio.core.dialog.set_theme') - mocked_show_dialog = mocker.patch('interrogatio.core.dialog.show_dialog') + mocked_set_theme = mocker.patch("interrogatio.core.dialog.set_theme") + mocked_show_dialog = mocker.patch("interrogatio.core.dialog.show_dialog") mocked_validate = mocker.patch( - 'interrogatio.core.dialog.validate_questions', + "interrogatio.core.dialog.validate_questions", ) - args = ([{'name': 'question1'}], 'title') + args = ([{"name": "question1"}], "title") kwargs = { - 'intro': 'intro', - 'summary': True, - 'fast_forward': False, - 'next_text': 'next_text', - 'previous_text': 'previous_text', - 'cancel_text': 'cancel_text', - 'finish_text': 'finish_text', + "intro": "intro", + "summary": True, + "fast_forward": False, + "next_text": "next_text", + "previous_text": "previous_text", + "cancel_text": "cancel_text", + "finish_text": "finish_text", } dialogus(*args, **kwargs) - mocked_set_theme.assert_called_once_with('default') + mocked_set_theme.assert_called_once_with("default") mocked_validate.assert_called_once_with(args[0]) mocked_show_dialog.assert_called_once_with(*args, **kwargs) def test_show_dialog(mocker): - mocker.patch( - 'interrogatio.core.dialog.for_dialog', - return_value='a style', + "interrogatio.core.dialog.for_dialog", + return_value="a style", ) mocked_handler = mocker.MagicMock() - mocked_handler.get_answer.return_value = {'question': 'answer'} + mocked_handler.get_answer.return_value = {"question": "answer"} mocked_handler.is_disabled.return_value = False mocked_disabled_handler = mocker.MagicMock() mocked_disabled_handler.is_disabled.return_value = True mocker.patch( - 'interrogatio.core.dialog.get_instance', + "interrogatio.core.dialog.get_instance", side_effect=[mocked_handler, mocked_disabled_handler], ) mocked_app = mocker.MagicMock() mocked_app.run.return_value = True mocked_app_cls = mocker.patch( - 'interrogatio.core.dialog.Application', + "interrogatio.core.dialog.Application", return_value=mocked_app, ) mocked_wz = mocker.MagicMock() mocked_wz_cls = mocker.patch( - 'interrogatio.core.dialog.WizardDialog', + "interrogatio.core.dialog.WizardDialog", return_value=mocked_wz, ) mocked_layout = mocker.MagicMock() mocked_layout_cls = mocker.patch( - 'interrogatio.core.dialog.Layout', + "interrogatio.core.dialog.Layout", return_value=mocked_layout, ) - args = ([{'name': 'question'}, {'name': 'disabled_question'}], 'title') + args = ([{"name": "question"}, {"name": "disabled_question"}], "title") kwargs = { - 'intro': 'intro', - 'summary': True, - 'fast_forward': False, - 'next_text': 'next_text', - 'previous_text': 'previous_text', - 'cancel_text': 'cancel_text', - 'finish_text': 'finish_text', + "intro": "intro", + "summary": True, + "fast_forward": False, + "next_text": "next_text", + "previous_text": "previous_text", + "cancel_text": "cancel_text", + "finish_text": "finish_text", } answers = show_dialog(*args, **kwargs) mocked_wz_cls.assert_called_once_with( - 'title', + "title", [mocked_handler, mocked_disabled_handler], **kwargs, ) @@ -83,45 +82,44 @@ def test_show_dialog(mocker): mocked_app_cls.assert_called_once_with( layout=mocked_layout, mouse_support=False, - style='a style', + style="a style", full_screen=True, ) - assert answers == {'question': 'answer'} + assert answers == {"question": "answer"} def test_show_dialog_cancel(mocker): - mocker.patch( - 'interrogatio.core.dialog.for_dialog', + "interrogatio.core.dialog.for_dialog", ) mocked_handler = mocker.MagicMock() mocker.patch( - 'interrogatio.core.dialog.get_instance', + "interrogatio.core.dialog.get_instance", return_value=mocked_handler, ) mocked_app = mocker.MagicMock() mocked_app.run.return_value = False mocker.patch( - 'interrogatio.core.dialog.Application', + "interrogatio.core.dialog.Application", return_value=mocked_app, ) mocker.patch( - 'interrogatio.core.dialog.WizardDialog', + "interrogatio.core.dialog.WizardDialog", ) mocker.patch( - 'interrogatio.core.dialog.Layout', + "interrogatio.core.dialog.Layout", ) - args = ([{'name': 'question1'}], 'title') + args = ([{"name": "question1"}], "title") kwargs = { - 'intro': 'intro', - 'summary': True, - 'next_text': 'next_text', - 'previous_text': 'previous_text', - 'cancel_text': 'cancel_text', - 'finish_text': 'finish_text', + "intro": "intro", + "summary": True, + "next_text": "next_text", + "previous_text": "previous_text", + "cancel_text": "cancel_text", + "finish_text": "finish_text", } answers = show_dialog(*args, **kwargs) diff --git a/tests/core/test_prompt.py b/tests/core/test_prompt.py index 3e4ebf5..601b59f 100644 --- a/tests/core/test_prompt.py +++ b/tests/core/test_prompt.py @@ -9,31 +9,31 @@ def test_string_handler(mock_input): questions = [ { - 'name': 'question', - 'type': 'input', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "input", + "message": "message", + "description": "description", }, ] - mock_input.send_text('this is the answer\n') + mock_input.send_text("this is the answer\n") answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == 'this is the answer' + assert "question" in answers + assert answers["question"] == "this is the answer" def test_string_handler_ctrl_c(mock_input): questions = [ { - 'name': 'question', - 'type': 'input', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "input", + "message": "message", + "description": "description", }, ] - mock_input.send_text('\x03') + mock_input.send_text("\x03") answers = interrogatio(questions) assert answers is None @@ -42,25 +42,25 @@ def test_string_handler_ctrl_c(mock_input): def test_string_handler_invalid(mocker, mock_input): questions = [ { - 'name': 'question', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] mocked_style = mocker.MagicMock() mocker.patch( - 'interrogatio.core.prompt.for_prompt', + "interrogatio.core.prompt.for_prompt", return_value=mocked_style, ) mocked_text = mocker.MagicMock() mocked_formatted_text = mocker.patch( - 'interrogatio.core.prompt.FormattedText', + "interrogatio.core.prompt.FormattedText", return_value=mocked_text, ) - mocked_print = mocker.patch('interrogatio.core.prompt.print_formatted_text') - mock_input.send_text('\n\x03') + mocked_print = mocker.patch("interrogatio.core.prompt.print_formatted_text") + mock_input.send_text("\n\x03") interrogatio(questions) mocked_print.assert_called_once_with( @@ -69,38 +69,38 @@ def test_string_handler_invalid(mocker, mock_input): ) mocked_formatted_text.assert_called_once_with( - [('class:error', 'this field is required')], + [("class:error", "this field is required")], ) def test_password_handler(mock_input): questions = [ { - 'name': 'question', - 'type': 'password', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "password", + "message": "message", + "description": "description", }, ] - mock_input.send_text('mypassword\n') + mock_input.send_text("mypassword\n") answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == 'mypassword' + assert "question" in answers + assert answers["question"] == "mypassword" def test_password_handler_ctrl_c(mock_input): questions = [ { - 'name': 'question', - 'type': 'password', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "password", + "message": "message", + "description": "description", }, ] - mock_input.send_text('\x03') + mock_input.send_text("\x03") answers = interrogatio(questions) assert answers is None @@ -109,25 +109,25 @@ def test_password_handler_ctrl_c(mock_input): def test_password_handler_invalid(mocker, mock_input): questions = [ { - 'name': 'question', - 'type': 'password', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question", + "type": "password", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] mocked_style = mocker.MagicMock() mocker.patch( - 'interrogatio.core.prompt.for_prompt', + "interrogatio.core.prompt.for_prompt", return_value=mocked_style, ) mocked_text = mocker.MagicMock() mocked_formatted_text = mocker.patch( - 'interrogatio.core.prompt.FormattedText', + "interrogatio.core.prompt.FormattedText", return_value=mocked_text, ) - mocked_print = mocker.patch('interrogatio.core.prompt.print_formatted_text') - mock_input.send_text('\n\x03') + mocked_print = mocker.patch("interrogatio.core.prompt.print_formatted_text") + mock_input.send_text("\n\x03") interrogatio(questions) mocked_print.assert_called_once_with( @@ -136,181 +136,181 @@ def test_password_handler_invalid(mocker, mock_input): ) mocked_formatted_text.assert_called_once_with( - [('class:error', 'this field is required')], + [("class:error", "this field is required")], ) def test_selectone_handler(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectone', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectone", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\x1b[B ' + chr(13)) + mock_input.send_text("\x1b[B " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == 'second' + assert "question" in answers + assert answers["question"] == "second" def test_selectone_handler_up(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectone', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectone", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\x1b[B\x1b[A ' + chr(13)) + mock_input.send_text("\x1b[B\x1b[A " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == 'first' + assert "question" in answers + assert answers["question"] == "first" def test_selectone_handler_page_down(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectone', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectone", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\x1b[6~ ' + chr(13)) + mock_input.send_text("\x1b[6~ " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == 'third' + assert "question" in answers + assert answers["question"] == "third" def test_selectone_handler_page_up(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectone', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectone", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\x1b[6~\x1b[5~ ' + chr(13)) + mock_input.send_text("\x1b[6~\x1b[5~ " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == 'first' + assert "question" in answers + assert answers["question"] == "first" def test_selectone_handler_value_initial(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectone', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectone", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('T ' + chr(13)) + mock_input.send_text("T " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == 'third' + assert "question" in answers + assert answers["question"] == "third" def test_selectone_handler_value_initial_not_found(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectone', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectone", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('Z ' + chr(13)) + mock_input.send_text("Z " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == 'first' + assert "question" in answers + assert answers["question"] == "first" def test_selectone_handler_with_default(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectone', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectone", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], - 'default': 'third', + "default": "third", }, ] mock_input.send_text(chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == 'third' + assert "question" in answers + assert answers["question"] == "third" def test_selectone_handler_ctrl_c(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectone', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectone", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\x03') + mock_input.send_text("\x03") answers = interrogatio(questions) assert answers is None @@ -319,240 +319,240 @@ def test_selectone_handler_ctrl_c(mock_input): def test_selectmany_handler(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\t\t \x1b[B ' + chr(13)) + mock_input.send_text("\t\t \x1b[B " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert sorted(answers['question']) == sorted(['first', 'second']) + assert "question" in answers + assert sorted(answers["question"]) == sorted(["first", "second"]) def test_selectmany_handler_with_checked(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], - 'default': {'first', 'third'}, + "default": {"first", "third"}, }, ] - mock_input.send_text('\t\t' + chr(13)) + mock_input.send_text("\t\t" + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert sorted(answers['question']) == sorted(['first', 'third']) + assert "question" in answers + assert sorted(answers["question"]) == sorted(["first", "third"]) def test_selectmany_handler_check_uncheck(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\t\t ' + chr(13)) + mock_input.send_text("\t\t " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == [] + assert "question" in answers + assert answers["question"] == [] def test_selectmany_handler_up(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\t\t \x1b[B \x1b[A ' + chr(13)) + mock_input.send_text("\t\t \x1b[B \x1b[A " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == ['second'] + assert "question" in answers + assert answers["question"] == ["second"] def test_selectmany_handler_page_down(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\t\t\x1b[6~ ' + chr(13)) + mock_input.send_text("\t\t\x1b[6~ " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == ['third'] + assert "question" in answers + assert answers["question"] == ["third"] def test_selectmany_handler_page_up(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\t\t\x1b[6~\x1b[5~ ' + chr(13)) + mock_input.send_text("\t\t\x1b[6~\x1b[5~ " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == ['first'] + assert "question" in answers + assert answers["question"] == ["first"] def test_selectmany_handler_initial(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\t\tS T ' + chr(13)) + mock_input.send_text("\t\tS T " + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert sorted(answers['question']) == sorted(['second', 'third']) + assert "question" in answers + assert sorted(answers["question"]) == sorted(["second", "third"]) def test_selectmany_handler_initial_not_found(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\t\tZ' + chr(13)) + mock_input.send_text("\t\tZ" + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == [] + assert "question" in answers + assert answers["question"] == [] def test_selectmany_handler_select_all(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text(' \t\t' + chr(13)) + mock_input.send_text(" \t\t" + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert sorted(answers['question']) == sorted(['first', 'second', 'third']) + assert "question" in answers + assert sorted(answers["question"]) == sorted(["first", "second", "third"]) def test_selectmany_handler_select_none(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text(' \t \t' + chr(13)) + mock_input.send_text(" \t \t" + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == [] + assert "question" in answers + assert answers["question"] == [] def test_selectmany_handler_ctrl_c(mock_input): questions = [ { - 'name': 'question', - 'type': 'selectmany', - 'message': 'message', - 'description': 'description', - 'values': [ - ('first', 'First'), - ('second', 'Second'), - ('third', 'Third'), + "name": "question", + "type": "selectmany", + "message": "message", + "description": "description", + "values": [ + ("first", "First"), + ("second", "Second"), + ("third", "Third"), ], }, ] - mock_input.send_text('\x03') + mock_input.send_text("\x03") answers = interrogatio(questions) assert answers is None @@ -561,18 +561,18 @@ def test_selectmany_handler_ctrl_c(mock_input): def test_date_handler(mock_input): questions = [ { - 'name': 'question', - 'type': 'date', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "date", + "message": "message", + "description": "description", }, ] - mock_input.send_text('20200101' + chr(13)) + mock_input.send_text("20200101" + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == datetime( + assert "question" in answers + assert answers["question"] == datetime( 2020, 1, 1, @@ -583,20 +583,20 @@ def test_date_handler(mock_input): def test_date_handler_go_previous(mock_input): questions = [ { - 'name': 'question', - 'type': 'date', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "date", + "message": "message", + "description": "description", }, ] mock_input.send_text( - '20200101' + chr(127) + chr(127) + chr(127) + '201' + chr(13), + "20200101" + chr(127) + chr(127) + chr(127) + "201" + chr(13), ) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == datetime( + assert "question" in answers + assert answers["question"] == datetime( 2020, 2, 1, @@ -607,20 +607,20 @@ def test_date_handler_go_previous(mock_input): def test_date_handler_go_previous_beginning(mock_input): questions = [ { - 'name': 'question', - 'type': 'date', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "date", + "message": "message", + "description": "description", }, ] mock_input.send_text( - '20200101' + chr(127) * 9 + '20220706' + chr(13), + "20200101" + chr(127) * 9 + "20220706" + chr(13), ) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == datetime( + assert "question" in answers + assert answers["question"] == datetime( 2022, 7, 6, @@ -631,53 +631,53 @@ def test_date_handler_go_previous_beginning(mock_input): def test_date_handler_no_value(mock_input): questions = [ { - 'name': 'question', - 'type': 'date', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "date", + "message": "message", + "description": "description", }, ] mock_input.send_text(chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] is None + assert "question" in answers + assert answers["question"] is None def test_date_handler_invalid_char(mock_input): questions = [ { - 'name': 'question', - 'type': 'date', - 'message': 'message', - 'description': 'description', - 'disabled': False, + "name": "question", + "type": "date", + "message": "message", + "description": "description", + "disabled": False, }, ] - mock_input.send_text('**##**@@' + chr(13)) + mock_input.send_text("**##**@@" + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] is None + assert "question" in answers + assert answers["question"] is None def test_date_handler_exceed_length(mock_input): questions = [ { - 'name': 'question', - 'type': 'date', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "date", + "message": "message", + "description": "description", }, ] - mock_input.send_text('2020010101' + chr(13)) + mock_input.send_text("2020010101" + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == datetime( + assert "question" in answers + assert answers["question"] == datetime( 2020, 1, 1, @@ -688,34 +688,34 @@ def test_date_handler_exceed_length(mock_input): def test_daterange_handler(mock_input): questions = [ { - 'name': 'question', - 'type': 'daterange', - 'message': 'message', - 'description': 'description', + "name": "question", + "type": "daterange", + "message": "message", + "description": "description", }, ] - mock_input.send_text('20200101\t20210101' + chr(13)) + mock_input.send_text("20200101\t20210101" + chr(13)) answers = interrogatio(questions) - assert 'question' in answers - assert answers['question'] == { - 'from': datetime(2020, 1, 1, tzinfo=timezone.utc), - 'to': datetime(2021, 1, 1, tzinfo=timezone.utc), + assert "question" in answers + assert answers["question"] == { + "from": datetime(2020, 1, 1, tzinfo=timezone.utc), + "to": datetime(2021, 1, 1, tzinfo=timezone.utc), } def test_disabled_handler(mock_input): questions = [ { - 'name': 'question', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'disabled': True, + "name": "question", + "type": "input", + "message": "message", + "description": "description", + "disabled": True, }, ] - mock_input.send_text('this is the answer\n') + mock_input.send_text("this is the answer\n") answers = interrogatio(questions) assert len(answers) == 0 @@ -724,17 +724,17 @@ def test_disabled_handler(mock_input): def test_disabled_handler_invalid(mock_input): questions = [ { - 'name': 'question', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'disabled': 'not callable or boolean', + "name": "question", + "type": "input", + "message": "message", + "description": "description", + "disabled": "not callable or boolean", }, ] - mock_input.send_text('this is the answer\n') + mock_input.send_text("this is the answer\n") with pytest.raises(InvalidQuestionError) as cv: interrogatio(questions) - assert str(cv.value) == 'Disabled flag must be a boolean or callable.' + assert str(cv.value) == "Disabled flag must be a boolean or callable." diff --git a/tests/handlers/test_base.py b/tests/handlers/test_base.py index 65442ce..d553fe7 100644 --- a/tests/handlers/test_base.py +++ b/tests/handlers/test_base.py @@ -3,39 +3,43 @@ def test_qhandler_errors(test_handler): t = test_handler({}) - t._errors = ['a', 'b', 'c'] - assert t.errors == ['a', 'b', 'c'] + t._errors = ["a", "b", "c"] + assert t.errors == ["a", "b", "c"] def test_qhandler_get_init_extra_args(test_handler): - t = test_handler({'extra_args': {'a': 0, 'b': '1'}}) - assert t.get_init_extra_args() == {'a': 0, 'b': '1'} + t = test_handler({"extra_args": {"a": 0, "b": "1"}}) + assert t.get_init_extra_args() == {"a": 0, "b": "1"} def test_qhandler_get_answer(mocker, test_handler): - t = test_handler({'name': 'test_field'}) - t.get_value = mocker.MagicMock(return_value='test_value') - assert t.get_answer() == {'test_field': 'test_value'} + t = test_handler({"name": "test_field"}) + t.get_value = mocker.MagicMock(return_value="test_value") + assert t.get_answer() == {"test_field": "test_value"} def test_qhandler_get_variable_name(test_handler): - t = test_handler({'name': 'test_field'}) - assert t.get_variable_name() == 'test_field' + t = test_handler({"name": "test_field"}) + assert t.get_variable_name() == "test_field" def test_qhandler_is_valid_valid(mocker, test_handler): - t = test_handler({ - 'name': 'test_field', - 'validators': [RequiredValidator()], - }) - t.get_value = mocker.MagicMock(return_value='value') + t = test_handler( + { + "name": "test_field", + "validators": [RequiredValidator()], + } + ) + t.get_value = mocker.MagicMock(return_value="value") assert t.is_valid() is True def test_qhandler_is_valid_invalid(mocker, test_handler): - t = test_handler({ - 'name': 'test_field', - 'validators': [RequiredValidator()], - }) - t.get_value = mocker.MagicMock(return_value='') + t = test_handler( + { + "name": "test_field", + "validators": [RequiredValidator()], + } + ) + t.get_value = mocker.MagicMock(return_value="") assert t.is_valid() is False diff --git a/tests/handlers/test_builtins.py b/tests/handlers/test_builtins.py index c511eb6..837371b 100644 --- a/tests/handlers/test_builtins.py +++ b/tests/handlers/test_builtins.py @@ -19,8 +19,8 @@ @pytest.mark.parametrize( - ('handler', 'expected_widget'), - ( + ("handler", "expected_widget"), + [ (StringHandler, TextArea), (PasswordHandler, TextArea), (SelectOneHandler, SelectOne), @@ -28,7 +28,7 @@ (MaskedInputHandler, MaskedInput), (DateHandler, MaskedInput), (DateRangeHandler, DateRange), - ), + ], ) def test_handler_get_widget_class(handler, expected_widget): s = handler({}) @@ -36,11 +36,11 @@ def test_handler_get_widget_class(handler, expected_widget): @pytest.mark.parametrize( - ('handler', 'expected_widget'), - ( + ("handler", "expected_widget"), + [ (StringHandler, TextArea), (PasswordHandler, TextArea), - ), + ], ) def test_handler_get_widget(handler, expected_widget): question = {} @@ -49,33 +49,33 @@ def test_handler_get_widget(handler, expected_widget): @pytest.mark.parametrize( - 'handler', - ( + "handler", + [ StringHandler, PasswordHandler, - ), + ], ) def test_textarea_handler_get_layout_cursor_position(handler): question = {} s = handler(question) widget = s.get_widget() - widget.text = 'this is the text' + widget.text = "this is the text" s.get_layout() assert widget.buffer.cursor_position == len(widget.text) @pytest.mark.parametrize( - 'handler', - ( + "handler", + [ StringHandler, PasswordHandler, - ), + ], ) def test_textarea_handler_get_layout(handler): question = {} s = handler(question) widget = s.get_widget() - widget.text = 'This is the widget text' + widget.text = "This is the widget text" layout = s.get_layout() assert isinstance(layout, HSplit) assert len(layout.children) == 1 @@ -85,21 +85,21 @@ def test_textarea_handler_get_layout(handler): assert layout.children[0].padding == 1 input_ctrl = layout.children[0].children[0] assert isinstance(input_ctrl, Window) - assert input_ctrl.content.buffer.text == 'This is the widget text' + assert input_ctrl.content.buffer.text == "This is the widget text" @pytest.mark.parametrize( - 'handler', - ( + "handler", + [ StringHandler, PasswordHandler, - ), + ], ) def test_textarea_handler_get_layout_with_msg(handler): - question = {'message': 'this is a message'} + question = {"message": "this is a message"} s = handler(question) widget = s.get_widget() - widget.text = 'This is the widget text' + widget.text = "This is the widget text" layout = s.get_layout() assert isinstance(layout, HSplit) assert len(layout.children) == 1 @@ -109,44 +109,44 @@ def test_textarea_handler_get_layout_with_msg(handler): assert layout.children[0].padding == 1 label_ctrl = layout.children[0].children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text() == 'this is a message' + assert label_ctrl.content.text() == "this is a message" input_ctrl = layout.children[0].children[1] - assert input_ctrl.content.buffer.text == 'This is the widget text' + assert input_ctrl.content.buffer.text == "This is the widget text" @pytest.mark.parametrize( - 'handler', - ( + "handler", + [ StringHandler, PasswordHandler, - ), + ], ) def test_textarea_handler_get_layout_with_description(handler): - question = {'description': 'this is a description'} + question = {"description": "this is a description"} s = handler(question) widget = s.get_widget() - widget.text = 'This is the widget text' + widget.text = "This is the widget text" layout = s.get_layout() assert isinstance(layout, HSplit) assert len(layout.children) == 2 assert layout.padding == 1 label_ctrl = layout.children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text[0][1] == 'this is a description' + assert label_ctrl.content.text[0][1] == "this is a description" assert isinstance(layout.children[1], VSplit) assert len(layout.children[1].children) == 1 assert layout.children[1].padding == 1 input_ctrl = layout.children[1].children[0] - assert input_ctrl.content.buffer.text == 'This is the widget text' + assert input_ctrl.content.buffer.text == "This is the widget text" @pytest.mark.parametrize( - 'handler', - ( + "handler", + [ StringHandler, PasswordHandler, - ), + ], ) def test_textarea_handler_get_keybindings(handler): s = handler({}) @@ -157,37 +157,37 @@ def test_textarea_handler_get_keybindings(handler): @pytest.mark.parametrize( - 'handler', - ( + "handler", + [ StringHandler, PasswordHandler, - ), + ], ) def test_textarea_handler_get_value(mocker, handler): s = handler({}) widget_mock = mocker.MagicMock() - widget_mock.text = 'Test text' + widget_mock.text = "Test text" s.get_widget = mocker.MagicMock(return_value=widget_mock) - assert s.get_value() == 'Test text' + assert s.get_value() == "Test text" @pytest.mark.parametrize( - ('question', 'expected'), - ( + ("question", "expected"), + [ ( - {'default': 'default_text'}, + {"default": "default_text"}, { - 'multiline': False, - 'text': 'default_text', - 'style': 'class:input.answer', + "multiline": False, + "text": "default_text", + "style": "class:input.answer", }, ), ( - {'multiline': True}, - {'multiline': True, 'style': 'class:input.answer'}, + {"multiline": True}, + {"multiline": True, "style": "class:input.answer"}, ), - ), + ], ) def test_string_handler_get_widget_init_kwargs(question, expected): s = StringHandler(question) @@ -195,26 +195,26 @@ def test_string_handler_get_widget_init_kwargs(question, expected): @pytest.mark.parametrize( - ('question', 'expected'), - ( + ("question", "expected"), + [ ( - {'default': 'default_text'}, + {"default": "default_text"}, { - 'text': 'default_text', - 'style': 'class:password.answer', - 'password': True, - 'multiline': False, + "text": "default_text", + "style": "class:password.answer", + "password": True, + "multiline": False, }, ), ( {}, { - 'multiline': False, - 'style': 'class:password.answer', - 'password': True, + "multiline": False, + "style": "class:password.answer", + "password": True, }, ), - ), + ], ) def test_password_handler_get_widget_init_kwargs(question, expected): s = PasswordHandler(question) @@ -222,7 +222,7 @@ def test_password_handler_get_widget_init_kwargs(question, expected): def test_selectone_handler_get_layout(): - question = {'values': [('a', 'A')]} + question = {"values": [("a", "A")]} s = SelectOneHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -236,7 +236,7 @@ def test_selectone_handler_get_layout(): def test_selectone_handler_get_layout_with_msg(): - question = {'message': 'this is a message', 'values': [('a', 'A')]} + question = {"message": "this is a message", "values": [("a", "A")]} s = SelectOneHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -247,13 +247,13 @@ def test_selectone_handler_get_layout_with_msg(): assert layout.children[0].padding == 1 label_ctrl = layout.children[0].children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text() == 'this is a message' + assert label_ctrl.content.text() == "this is a message" input_ctrl = layout.children[0].children[1] assert isinstance(input_ctrl, Window) def test_selectone_handler_get_layout_with_description(): - question = {'description': 'this is a description', 'values': [('a', 'A')]} + question = {"description": "this is a description", "values": [("a", "A")]} s = SelectOneHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -261,7 +261,7 @@ def test_selectone_handler_get_layout_with_description(): assert layout.padding == 1 label_ctrl = layout.children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text[0][1] == 'this is a description' + assert label_ctrl.content.text[0][1] == "this is a description" assert isinstance(layout.children[1], VSplit) assert len(layout.children[1].children) == 1 @@ -271,24 +271,24 @@ def test_selectone_handler_get_layout_with_description(): @pytest.mark.parametrize( - ('question', 'expected'), - ( + ("question", "expected"), + [ ( - {'default': 'default_value', 'values': [('a', 'A')]}, + {"default": "default_value", "values": [("a", "A")]}, { - 'style': 'class:selectone.answer', - 'values': [('a', 'A')], - 'default': 'default_value', + "style": "class:selectone.answer", + "values": [("a", "A")], + "default": "default_value", }, ), ( - {'values': [('a', 'A')]}, + {"values": [("a", "A")]}, { - 'style': 'class:selectone.answer', - 'values': [('a', 'A')], + "style": "class:selectone.answer", + "values": [("a", "A")], }, ), - ), + ], ) def test_selectone_handler_get_widget_init_kwargs(question, expected): s = SelectOneHandler(question) @@ -296,7 +296,7 @@ def test_selectone_handler_get_widget_init_kwargs(question, expected): def test_selectone_handler_get_keybindings(): - s = SelectOneHandler({'values': [('a', 'A')]}) + s = SelectOneHandler({"values": [("a", "A")]}) kb = s.get_keybindings() assert isinstance(kb, KeyBindings) assert kb.get_bindings_for_keys(Keys.ControlC) is not None @@ -305,13 +305,13 @@ def test_selectone_handler_get_keybindings(): def test_selectone_handler_get_value(mocker): s = SelectOneHandler({}) widget_mock = mocker.MagicMock() - widget_mock.current_value = 'Test text' + widget_mock.current_value = "Test text" s.get_widget = mocker.MagicMock(return_value=widget_mock) - assert s.get_value() == 'Test text' + assert s.get_value() == "Test text" def test_selectmany_handler_get_layout(): - question = {'values': [('a', 'A')]} + question = {"values": [("a", "A")]} s = SelectManyHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -325,7 +325,7 @@ def test_selectmany_handler_get_layout(): def test_selectmany_handler_get_layout_with_msg(): - question = {'message': 'this is a message', 'values': [('a', 'A')]} + question = {"message": "this is a message", "values": [("a", "A")]} s = SelectManyHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -336,13 +336,13 @@ def test_selectmany_handler_get_layout_with_msg(): assert layout.children[1].padding == 1 label_ctrl = layout.children[1].children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text() == 'this is a message' + assert label_ctrl.content.text() == "this is a message" input_ctrl = layout.children[1].children[1] assert isinstance(input_ctrl, Window) def test_selectmany_handler_get_layout_with_description(): - question = {'description': 'this is a description', 'values': [('a', 'A')]} + question = {"description": "this is a description", "values": [("a", "A")]} s = SelectManyHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -350,7 +350,7 @@ def test_selectmany_handler_get_layout_with_description(): assert layout.padding == 1 label_ctrl = layout.children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text[0][1] == 'this is a description' + assert label_ctrl.content.text[0][1] == "this is a description" assert isinstance(layout.children[2], VSplit) assert len(layout.children[2].children) == 1 @@ -360,28 +360,27 @@ def test_selectmany_handler_get_layout_with_description(): @pytest.mark.parametrize( - ('question', 'expected'), - ( + ("question", "expected"), + [ ( { - 'default': ['a'], - 'values': [('a', 'A')], + "default": ["a"], + "values": [("a", "A")], }, { - 'default': ['a'], - 'style': 'class:selectmany.answer', - 'values': [('a', 'A')], - + "default": ["a"], + "style": "class:selectmany.answer", + "values": [("a", "A")], }, ), ( - {'values': [('a', 'A')]}, + {"values": [("a", "A")]}, { - 'style': 'class:selectmany.answer', - 'values': [('a', 'A')], + "style": "class:selectmany.answer", + "values": [("a", "A")], }, ), - ), + ], ) def test_selectmany_handler_get_widget_init_kwargs(question, expected): s = SelectManyHandler(question) @@ -389,7 +388,7 @@ def test_selectmany_handler_get_widget_init_kwargs(question, expected): def test_selectmany_handler_get_keybindings(): - s = SelectManyHandler({'values': [('a', 'A')]}) + s = SelectManyHandler({"values": [("a", "A")]}) kb = s.get_keybindings() assert isinstance(kb, KeyBindings) assert kb.get_bindings_for_keys(Keys.ControlC) is not None @@ -398,13 +397,13 @@ def test_selectmany_handler_get_keybindings(): def test_selectmany_handler_get_value(mocker): s = SelectManyHandler({}) widget_mock = mocker.MagicMock() - widget_mock.value = ['a'] + widget_mock.value = ["a"] s.get_widget = mocker.MagicMock(return_value=widget_mock) - assert s.get_value() == ['a'] + assert s.get_value() == ["a"] def test_maskedinput_handler_get_layout(): - question = {'mask': '____-____'} + question = {"mask": "____-____"} s = MaskedInputHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -418,7 +417,7 @@ def test_maskedinput_handler_get_layout(): def test_maskedinput_handler_get_layout_with_msg(): - question = {'mask': '____-____', 'message': 'this is a message'} + question = {"mask": "____-____", "message": "this is a message"} s = MaskedInputHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -429,13 +428,13 @@ def test_maskedinput_handler_get_layout_with_msg(): assert layout.children[0].padding == 1 label_ctrl = layout.children[0].children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text() == 'this is a message' + assert label_ctrl.content.text() == "this is a message" input_ctrl = layout.children[0].children[1] assert isinstance(input_ctrl, MaskedInput) def test_maskedinput_handler_get_layout_with_description(): - question = {'mask': '____-____', 'description': 'this is a description'} + question = {"mask": "____-____", "description": "this is a description"} s = MaskedInputHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -443,7 +442,7 @@ def test_maskedinput_handler_get_layout_with_description(): assert layout.padding == 1 label_ctrl = layout.children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text[0][1] == 'this is a description' + assert label_ctrl.content.text[0][1] == "this is a description" assert isinstance(layout.children[1], VSplit) assert len(layout.children[1].children) == 1 @@ -453,26 +452,26 @@ def test_maskedinput_handler_get_layout_with_description(): def test_maskedinput_handler_get_widget_init_kwargs(): - s = MaskedInputHandler({'mask': '____-____'}) + s = MaskedInputHandler({"mask": "____-____"}) assert s.get_widget_init_kwargs() == { - 'mask': '____-____', - 'style': 'class:input.answer', + "mask": "____-____", + "style": "class:input.answer", } def test_maskedinput_handler_get_keybindings(): - s = MaskedInputHandler({'mask': '____-____'}) + s = MaskedInputHandler({"mask": "____-____"}) kb = s.get_keybindings() assert isinstance(kb, KeyBindings) assert kb.get_bindings_for_keys(Keys.ControlC) is not None def test_maskedinput_handler_get_value(mocker): - s = MaskedInputHandler({'mask': '____-____'}) + s = MaskedInputHandler({"mask": "____-____"}) widget_mock = mocker.MagicMock() - widget_mock.value = 'value' + widget_mock.value = "value" s.get_widget = mocker.MagicMock(return_value=widget_mock) - assert s.get_value() == 'value' + assert s.get_value() == "value" def test_date_handler_get_layout(): @@ -490,7 +489,7 @@ def test_date_handler_get_layout(): def test_date_handler_get_layout_with_msg(): - question = {'message': 'this is a message'} + question = {"message": "this is a message"} s = DateHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -501,13 +500,13 @@ def test_date_handler_get_layout_with_msg(): assert layout.children[0].padding == 1 label_ctrl = layout.children[0].children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text() == 'this is a message' + assert label_ctrl.content.text() == "this is a message" input_ctrl = layout.children[0].children[1] assert isinstance(input_ctrl, MaskedInput) def test_date_handler_get_layout_with_description(): - question = {'description': 'this is a description'} + question = {"description": "this is a description"} s = DateHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -515,7 +514,7 @@ def test_date_handler_get_layout_with_description(): assert layout.padding == 1 label_ctrl = layout.children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text[0][1] == 'this is a description' + assert label_ctrl.content.text[0][1] == "this is a description" assert isinstance(layout.children[1], VSplit) assert len(layout.children[1].children) == 1 @@ -527,9 +526,9 @@ def test_date_handler_get_layout_with_description(): def test_date_handler_get_widget_init_kwargs(): s = DateHandler({}) assert s.get_widget_init_kwargs() == { - 'mask': '____-__-__', - 'style': 'class:input.answer', - 'allowed_chars': string.digits, + "mask": "____-__-__", + "style": "class:input.answer", + "allowed_chars": string.digits, } @@ -544,9 +543,9 @@ def test_date_handler_get_keybindings(): def test_date_handler_get_value(mocker): s = DateHandler({}) widget_mock = mocker.MagicMock() - widget_mock.value = 'value' + widget_mock.value = "value" s.get_widget = mocker.MagicMock(return_value=widget_mock) - assert s.get_value() == 'value' + assert s.get_value() == "value" def test_daterange_handler_get_layout(): @@ -564,7 +563,7 @@ def test_daterange_handler_get_layout(): def test_daterange_handler_get_layout_with_msg(): - question = {'message': 'this is a message'} + question = {"message": "this is a message"} s = DateRangeHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -575,13 +574,13 @@ def test_daterange_handler_get_layout_with_msg(): assert layout.children[0].padding == 1 label_ctrl = layout.children[0].children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text() == 'this is a message' + assert label_ctrl.content.text() == "this is a message" input_ctrl = layout.children[0].children[1] assert isinstance(input_ctrl, DateRange) def test_daterange_handler_get_layout_with_description(): - question = {'description': 'this is a description'} + question = {"description": "this is a description"} s = DateRangeHandler(question) layout = s.get_layout() assert isinstance(layout, HSplit) @@ -589,7 +588,7 @@ def test_daterange_handler_get_layout_with_description(): assert layout.padding == 1 label_ctrl = layout.children[0] assert isinstance(label_ctrl, Window) - assert label_ctrl.content.text[0][1] == 'this is a description' + assert label_ctrl.content.text[0][1] == "this is a description" assert isinstance(layout.children[1], VSplit) assert len(layout.children[1].children) == 1 @@ -599,27 +598,26 @@ def test_daterange_handler_get_layout_with_description(): @pytest.mark.parametrize( - ('question', 'expected'), - ( + ("question", "expected"), + [ ( { - 'from_label': 'From', - 'to_label': 'To', + "from_label": "From", + "to_label": "To", }, { - 'style': 'class:input.answer', - 'from_label': 'From', - 'to_label': 'To', - + "style": "class:input.answer", + "from_label": "From", + "to_label": "To", }, ), ( {}, { - 'style': 'class:input.answer', + "style": "class:input.answer", }, ), - ), + ], ) def test_daterange_handler_get_widget_init_kwargs(question, expected): s = DateRangeHandler(question) @@ -637,6 +635,6 @@ def test_daterange_handler_get_keybindings(): def test_daterange_handler_get_value(mocker): s = DateRangeHandler({}) widget_mock = mocker.MagicMock() - widget_mock.value = 'value' + widget_mock.value = "value" s.get_widget = mocker.MagicMock(return_value=widget_mock) - assert s.get_value() == 'value' + assert s.get_value() == "value" diff --git a/tests/handlers/test_registry.py b/tests/handlers/test_registry.py index 100caa7..8e57cab 100644 --- a/tests/handlers/test_registry.py +++ b/tests/handlers/test_registry.py @@ -3,7 +3,10 @@ from interrogatio.core.exceptions import AlreadyRegisteredError from interrogatio.handlers.base import QHandler from interrogatio.handlers.registry import ( - get_instance, get_registered, QHandlersRegistry, register, + QHandlersRegistry, + get_instance, + get_registered, + register, ) @@ -13,10 +16,10 @@ def test_registry_register(): class TestClass: pass - reg.register('alias', TestClass) + reg.register("alias", TestClass) - assert 'alias' in reg - assert issubclass(reg['alias'], TestClass) + assert "alias" in reg + assert issubclass(reg["alias"], TestClass) def test_registry_register_already_registered(): @@ -25,11 +28,11 @@ def test_registry_register_already_registered(): class TestClass: pass - reg.register('alias', TestClass) + reg.register("alias", TestClass) with pytest.raises(AlreadyRegisteredError) as cv: - reg.register('alias', TestClass) + reg.register("alias", TestClass) - assert str(cv.value) == 'alias `alias` already exists.' + assert str(cv.value) == "alias `alias` already exists." def test_registry_get_registered(): @@ -43,13 +46,13 @@ def test_registry_get_registered(): class TestClass: pass - reg.register('alias', TestClass) + reg.register("alias", TestClass) registered = reg.get_registered() assert isinstance(registered, list) assert len(registered) == 1 - assert registered[0] == 'alias' + assert registered[0] == "alias" def test_registry_get_instance(): @@ -59,9 +62,9 @@ class TestClass: def __init__(self, question): self.question = question - reg.register('test', TestClass) + reg.register("test", TestClass) - question = {'type': 'test'} + question = {"type": "test"} instance = reg.get_instance(question) @@ -70,27 +73,26 @@ def __init__(self, question): def test_register(handlers_registry): - - @register('alias') + @register("alias") class TestClass(QHandler): pass - assert 'alias' in handlers_registry - assert issubclass(handlers_registry['alias'], TestClass) + assert "alias" in handlers_registry + assert issubclass(handlers_registry["alias"], TestClass) def test_register_already_registered(handlers_registry): - - @register('alias') + @register("alias") class TestClass(QHandler): pass with pytest.raises(AlreadyRegisteredError) as cv: - @register('alias') + + @register("alias") class TestClass2(QHandler): pass - assert str(cv.value) == 'The handler `alias` is already registered.' + assert str(cv.value) == "The handler `alias` is already registered." def test_get_registered(handlers_registry): @@ -99,7 +101,7 @@ def test_get_registered(handlers_registry): assert isinstance(registered, list) assert len(registered) == 0 - @register('alias') + @register("alias") class TestClass(QHandler): pass @@ -107,12 +109,11 @@ class TestClass(QHandler): assert isinstance(registered, list) assert len(registered) == 1 - assert registered[0] == 'alias' + assert registered[0] == "alias" def test_get_instance(handlers_registry): - - @register('test') + @register("test") class TestClass(QHandler): def __init__(self, question): self.question = question @@ -129,7 +130,7 @@ def get_widget_init_kwargs(self): def get_widget_class(self): pass - question = {'type': 'test'} + question = {"type": "test"} instance = get_instance(question) diff --git a/tests/shortcuts/test_dialogs.py b/tests/shortcuts/test_dialogs.py index 0657fd0..70a95f1 100644 --- a/tests/shortcuts/test_dialogs.py +++ b/tests/shortcuts/test_dialogs.py @@ -4,178 +4,178 @@ @pytest.mark.parametrize( - ('func', 'kwargs', 'expected_kwargs'), - ( + ("func", "kwargs", "expected_kwargs"), + [ ( dialogs.yes_no_dialog, { - 'title': 'title', - 'text': 'text', - 'yes_text': 'yes_text', - 'no_text': 'no_text', + "title": "title", + "text": "text", + "yes_text": "yes_text", + "no_text": "no_text", }, { - 'title': 'title', - 'text': 'text', - 'yes_text': 'yes_text', - 'no_text': 'no_text', + "title": "title", + "text": "text", + "yes_text": "yes_text", + "no_text": "no_text", }, ), ( dialogs.button_dialog, { - 'title': 'title', - 'text': 'text', + "title": "title", + "text": "text", }, { - 'title': 'title', - 'text': 'text', - 'buttons': [], + "title": "title", + "text": "text", + "buttons": [], }, ), ( dialogs.button_dialog, { - 'title': 'title', - 'text': 'text', - 'buttons': ['btn1', 'btn2'], + "title": "title", + "text": "text", + "buttons": ["btn1", "btn2"], }, { - 'title': 'title', - 'text': 'text', - 'buttons': ['btn1', 'btn2'], + "title": "title", + "text": "text", + "buttons": ["btn1", "btn2"], }, ), ( dialogs.input_dialog, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', - 'cancel_text': 'cancel_text', + "title": "title", + "text": "text", + "ok_text": "ok_text", + "cancel_text": "cancel_text", }, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', - 'cancel_text': 'cancel_text', - 'completer': None, - 'password': False, + "title": "title", + "text": "text", + "ok_text": "ok_text", + "cancel_text": "cancel_text", + "completer": None, + "password": False, }, ), ( dialogs.input_dialog, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', - 'cancel_text': 'cancel_text', - 'completer': 'completer', - 'password': True, + "title": "title", + "text": "text", + "ok_text": "ok_text", + "cancel_text": "cancel_text", + "completer": "completer", + "password": True, }, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', - 'cancel_text': 'cancel_text', - 'completer': 'completer', - 'password': True, + "title": "title", + "text": "text", + "ok_text": "ok_text", + "cancel_text": "cancel_text", + "completer": "completer", + "password": True, }, ), ( dialogs.message_dialog, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', + "title": "title", + "text": "text", + "ok_text": "ok_text", }, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', + "title": "title", + "text": "text", + "ok_text": "ok_text", }, ), ( dialogs.radiolist_dialog, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', - 'cancel_text': 'cancel_text', + "title": "title", + "text": "text", + "ok_text": "ok_text", + "cancel_text": "cancel_text", }, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', - 'cancel_text': 'cancel_text', - 'values': None, + "title": "title", + "text": "text", + "ok_text": "ok_text", + "cancel_text": "cancel_text", + "values": None, }, ), ( dialogs.radiolist_dialog, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', - 'cancel_text': 'cancel_text', - 'values': ['a', 'b'], + "title": "title", + "text": "text", + "ok_text": "ok_text", + "cancel_text": "cancel_text", + "values": ["a", "b"], }, { - 'title': 'title', - 'text': 'text', - 'ok_text': 'ok_text', - 'cancel_text': 'cancel_text', - 'values': ['a', 'b'], + "title": "title", + "text": "text", + "ok_text": "ok_text", + "cancel_text": "cancel_text", + "values": ["a", "b"], }, ), ( dialogs.progress_dialog, { - 'title': 'title', - 'text': 'text', + "title": "title", + "text": "text", }, { - 'title': 'title', - 'text': 'text', - 'run_callback': None, + "title": "title", + "text": "text", + "run_callback": None, }, ), ( dialogs.progress_dialog, { - 'title': 'title', - 'text': 'text', - 'run_callback': 'a function', + "title": "title", + "text": "text", + "run_callback": "a function", }, { - 'title': 'title', - 'text': 'text', - 'run_callback': 'a function', + "title": "title", + "text": "text", + "run_callback": "a function", }, ), - ), + ], ) def test_dialogs(mocker, func, kwargs, expected_kwargs): mocked = mocker.patch( - f'interrogatio.shortcuts.dialogs.pt_{func.__name__}', + f"interrogatio.shortcuts.dialogs.pt_{func.__name__}", ) mocker.patch( - 'interrogatio.shortcuts.dialogs.for_dialog', - return_value='a style', + "interrogatio.shortcuts.dialogs.for_dialog", + return_value="a style", ) func(**kwargs) assert mocked.mock_calls[0].kwargs == { **expected_kwargs, - 'style': 'a style', + "style": "a style", } - kwargs['style'] = 'another style' + kwargs["style"] = "another style" func(**kwargs) assert mocked.mock_calls[1].kwargs == { **expected_kwargs, - 'style': 'another style', + "style": "another style", } diff --git a/tests/validators/test_builtins.py b/tests/validators/test_builtins.py index 3656e10..71c4aab 100644 --- a/tests/validators/test_builtins.py +++ b/tests/validators/test_builtins.py @@ -20,12 +20,12 @@ @pytest.mark.parametrize( - 'value', - ( - '10.0.0.1', - '192.168.1.1', - '192.168.1.255', - ), + "value", + [ + "10.0.0.1", + "192.168.1.1", + "192.168.1.255", + ], ) def test_validate_ipv4_address(value): v = IPv4Validator() @@ -33,12 +33,12 @@ def test_validate_ipv4_address(value): @pytest.mark.parametrize( - 'value', - ( - '10.0.0.256', - '255.255', - 'a.b.c.d', - ), + "value", + [ + "10.0.0.256", + "255.255", + "a.b.c.d", + ], ) def test_validate_ipv4_address_invalid(value): v = IPv4Validator() @@ -47,17 +47,17 @@ def test_validate_ipv4_address_invalid(value): @pytest.mark.parametrize( - 'value', - ( - 'a', - 'd sd d', - ('a',), - ('a', 'b'), - ['a'], + "value", + [ + "a", + "d sd d", + ("a",), + ("a", "b"), + ["a"], [1, 2, 3], - {'a': 'v'}, - {'b': 'a', 'a': 'b'}, - ), + {"a": "v"}, + {"b": "a", "a": "b"}, + ], ) def test_required_validator(value): r = RequiredValidator() @@ -65,15 +65,15 @@ def test_required_validator(value): @pytest.mark.parametrize( - 'value', - ( + "value", + [ None, False, - '', - tuple(), + "", + (), [], {}, - ), + ], ) def test_required_validator_invalid(value): r = RequiredValidator() @@ -82,28 +82,28 @@ def test_required_validator_invalid(value): def test_regex_validator(): - r = RegexValidator(r'^[a-zA-Z]+$') - assert r.validate('aianaBCBCyasgfdBCbB') is None + r = RegexValidator(r"^[a-zA-Z]+$") + assert r.validate("aianaBCBCyasgfdBCbB") is None def test_regex_validator_invalid(): - r = RegexValidator(r'^[a-zA-Z]+$') + r = RegexValidator(r"^[a-zA-Z]+$") with pytest.raises(ValidationError): - r.validate('aianaBCBCya111') + r.validate("aianaBCBCya111") with pytest.raises(ValidationError): - r.validate('a##') + r.validate("a##") @pytest.mark.parametrize( - 'value', - ( + "value", + [ None, - '', - 'gigi@日本語.org', - 'test@gmail.com', - 'hello@microsoft.com', - ), + "", + "gigi@日本語.org", + "test@gmail.com", + "hello@microsoft.com", + ], ) def test_email_validator(value): r = EmailValidator() @@ -111,12 +111,12 @@ def test_email_validator(value): @pytest.mark.parametrize( - 'value', - ( - '日本語.idn.icann.org', - 'microsoft.com', - 'test@domain', - ), + "value", + [ + "日本語.idn.icann.org", + "microsoft.com", + "test@domain", + ], ) def test_email_validator_invalid(value): r = EmailValidator() @@ -125,16 +125,16 @@ def test_email_validator_invalid(value): @pytest.mark.parametrize( - 'value', - ( - 'https://www.日本語.com', - 'https://gmail.com', - 'http://test.app.microsoft.com', - 'https://www.日本語.com:8443', - 'https://gmail.com:9443', - 'http://user:pass@test.app.microsoft.com', - 'ftp://test.local', - ), + "value", + [ + "https://www.日本語.com", + "https://gmail.com", + "http://test.app.microsoft.com", + "https://www.日本語.com:8443", + "https://gmail.com:9443", + "http://user:pass@test.app.microsoft.com", + "ftp://test.local", + ], ) def test_url_validator(value): r = URLValidator() @@ -142,12 +142,12 @@ def test_url_validator(value): @pytest.mark.parametrize( - 'value', - ( - 'https://' + 'a' * 254, - 'https://test', - 'my.url.com', - ), + "value", + [ + "https://" + "a" * 254, + "https://test", + "my.url.com", + ], ) def test_url_validator_invalid(value): r = URLValidator() @@ -156,15 +156,15 @@ def test_url_validator_invalid(value): @pytest.mark.parametrize( - 'value', - ( - '', + "value", + [ + "", [], - 'a' * 99, - 'b' * 100, - ['x' for _ in range(99)], - ['x' for _ in range(100)], - ), + "a" * 99, + "b" * 100, + ["x" for _ in range(99)], + ["x" for _ in range(100)], + ], ) def test_maxlength_validator(value): r = MaxLengthValidator(100) @@ -172,14 +172,14 @@ def test_maxlength_validator(value): @pytest.mark.parametrize( - 'value', - ( - 'a' * 99, - 'b' * 100, - ['x' for _ in range(99)], - ['x' for _ in range(100)], + "value", + [ + "a" * 99, + "b" * 100, + ["x" for _ in range(99)], + ["x" for _ in range(100)], 66, - ), + ], ) def test_maxlength_validator_invalid(value): r = MaxLengthValidator(98) @@ -188,15 +188,15 @@ def test_maxlength_validator_invalid(value): @pytest.mark.parametrize( - 'value', - ( - '0' * 98, - 'a' * 99, - 'b' * 100, - ['x' for _ in range(98)], - ['x' for _ in range(99)], - ['x' for _ in range(100)], - ), + "value", + [ + "0" * 98, + "a" * 99, + "b" * 100, + ["x" for _ in range(98)], + ["x" for _ in range(99)], + ["x" for _ in range(100)], + ], ) def test_minlength_validator(value): r = MinLengthValidator(98) @@ -204,14 +204,14 @@ def test_minlength_validator(value): @pytest.mark.parametrize( - 'value', - ( - 'a' * 99, - 'b' * 100, - ['x' for _ in range(99)], - ['x' for _ in range(100)], + "value", + [ + "a" * 99, + "b" * 100, + ["x" for _ in range(99)], + ["x" for _ in range(100)], 25, - ), + ], ) def test_minlength_validator_invalid(value): r = MinLengthValidator(101) @@ -220,8 +220,8 @@ def test_minlength_validator_invalid(value): @pytest.mark.parametrize( - 'value', - (-1, 0, 1, 20.93, -11.2994, 0xff12, 0o7146, 0b11010011), + "value", + [-1, 0, 1, 20.93, -11.2994, 0xFF12, 0o7146, 0b11010011], ) def test_number_validator(value): r = NumberValidator() @@ -229,8 +229,8 @@ def test_number_validator(value): @pytest.mark.parametrize( - 'value', - ('', 'string', list(), list([1, 2, 3]), dict()), + "value", + ["", "string", [], [1, 2, 3], {}], ) def test_number_validator_invalid(value): r = NumberValidator() @@ -239,8 +239,8 @@ def test_number_validator_invalid(value): @pytest.mark.parametrize( - 'value', - (-1, 0, 1, 0xff12, 0o7146, 0b11010011), + "value", + [-1, 0, 1, 0xFF12, 0o7146, 0b11010011], ) def test_integer_validator(value): r = IntegerValidator() @@ -248,8 +248,8 @@ def test_integer_validator(value): @pytest.mark.parametrize( - 'value', - ('-1', '0', '1', 20.93, -11.2994, [1, 2, 3]), + "value", + ["-1", "0", "1", 20.93, -11.2994, [1, 2, 3]], ) def test_integer_validator_invalid(value): r = IntegerValidator() @@ -258,8 +258,8 @@ def test_integer_validator_invalid(value): @pytest.mark.parametrize( - 'value', - (-1, 0, 1, 3.88, 0o10, 0b1000, 0x0F), + "value", + [-1, 0, 1, 3.88, 0o10, 0x0F], ) def test_min_validator(value): r = MinValidator(-2) @@ -267,8 +267,8 @@ def test_min_validator(value): @pytest.mark.parametrize( - 'value', - (-3.88, -0o10, -0b1000, -0x0F, [1, 2, 3]), + "value", + [-3.88, -0o10, -0x0F, [1, 2, 3]], ) def test_min_validator_invalid(value): r = MinValidator(-2) @@ -277,8 +277,8 @@ def test_min_validator_invalid(value): @pytest.mark.parametrize( - 'value', - (-1, 0, 1, 3.88, 0o10, 0b1000, 0x0F), + "value", + [-1, 0, 1, 3.88, 0o10, 0x0F], ) def test_max_validator(value): r = MaxValidator(16) @@ -286,8 +286,8 @@ def test_max_validator(value): @pytest.mark.parametrize( - 'value', - (-1, 0, 1, 3.88, 0o10, 0b1000, 0x0F, [1, 2, 3]), + "value", + [-1, 0, 1, 3.88, 0o10, 0x0F, [1, 2, 3]], ) def test_max_validator_invalid(value): r = MaxValidator(-2) @@ -296,8 +296,8 @@ def test_max_validator_invalid(value): @pytest.mark.parametrize( - 'value', - (-1, 0, 1, 3.88, 0o10, 0b1000, 0x0F), + "value", + [-1, 0, 1, 3.88, 0o10, 0x0F], ) def test_range_validator(value): r = RangeValidator(-2, 16) @@ -305,8 +305,8 @@ def test_range_validator(value): @pytest.mark.parametrize( - 'value', - (-1, 0, 1, 3.88, 0o10, 0b1000, 0x0F, [1, 2, 3]), + "value", + [-1, 0, 1, 3.88, 0o10, 0x0F, [1, 2, 3]], ) def test_range_validator_invalid(value): r = RangeValidator(-20, -2) @@ -315,13 +315,13 @@ def test_range_validator_invalid(value): @pytest.mark.parametrize( - 'value', - ( - '2020-01-01T12:00:00', - '2020-02-29T23:00:00', - '', + "value", + [ + "2020-01-01T12:00:00", + "2020-02-29T23:00:00", + "", None, - ), + ], ) def test_date_validator(value): r = DateTimeValidator() @@ -329,8 +329,8 @@ def test_date_validator(value): @pytest.mark.parametrize( - 'value', - (-1, 0, 1, 3.88, 0o10, 0b1000, 0x0F, [1, 2, 3], '2020-02-30T23:00:00'), + "value", + [-1, 0, 1, 3.88, 0o10, 0x0F, [1, 2, 3], "2020-02-30T23:00:00"], ) def test_date_validator_invalid(value): r = DateTimeValidator() @@ -339,29 +339,29 @@ def test_date_validator_invalid(value): @pytest.mark.parametrize( - 'value', - ( - {'from': '2020-01-01T12:00:00', 'to': '2020-03-01T12:00:00'}, - {'from': '2020-01-01T12:00:00', 'to': ''}, - {'from': None, 'to': '2020-03-01T12:00:00'}, - '', + "value", + [ + {"from": "2020-01-01T12:00:00", "to": "2020-03-01T12:00:00"}, + {"from": "2020-01-01T12:00:00", "to": ""}, + {"from": None, "to": "2020-03-01T12:00:00"}, + "", None, - ), + ], ) def test_daterange_validator(value): - r = DateTimeRangeValidator(format_pattern='%Y-%m-%dT%H:%M:%S') + r = DateTimeRangeValidator(format_pattern="%Y-%m-%dT%H:%M:%S") assert r.validate(value) is None @pytest.mark.parametrize( - 'value', - ( - {'from': '2020-01-01T12:00:00', 'to': '2019-03-01T12:00:00'}, - {'from': 'xxxx', 'to': 'xxxx'}, + "value", + [ + {"from": "2020-01-01T12:00:00", "to": "2019-03-01T12:00:00"}, + {"from": "xxxx", "to": "xxxx"}, [1, 2, 3], - ), + ], ) def test_daterange_validator_invalid(value): - r = DateTimeRangeValidator(format_pattern='%Y-%m-%dT%H:%M:%S') + r = DateTimeRangeValidator(format_pattern="%Y-%m-%dT%H:%M:%S") with pytest.raises(ValidationError): r.validate(value) diff --git a/tests/validators/test_registry.py b/tests/validators/test_registry.py index 44c08b1..6123c6a 100644 --- a/tests/validators/test_registry.py +++ b/tests/validators/test_registry.py @@ -3,10 +3,10 @@ from interrogatio.core.exceptions import AlreadyRegisteredError from interrogatio.validators.base import Validator from interrogatio.validators.registry import ( + ValidatorsRegistry, get_instance, get_registered, register, - ValidatorsRegistry, ) @@ -16,10 +16,10 @@ def test_registry_register(): class TestClass: pass - reg.register('alias', TestClass) + reg.register("alias", TestClass) - assert 'alias' in reg - assert issubclass(reg['alias'], TestClass) + assert "alias" in reg + assert issubclass(reg["alias"], TestClass) def test_registry_register_already_registered(): @@ -28,11 +28,11 @@ def test_registry_register_already_registered(): class TestClass: pass - reg.register('alias', TestClass) + reg.register("alias", TestClass) with pytest.raises(AlreadyRegisteredError) as cv: - reg.register('alias', TestClass) + reg.register("alias", TestClass) - assert str(cv.value) == 'validator `alias` already exists.' + assert str(cv.value) == "validator `alias` already exists." def test_registry_get_registered(): @@ -46,13 +46,13 @@ def test_registry_get_registered(): class TestClass: pass - reg.register('alias', TestClass) + reg.register("alias", TestClass) registered = reg.get_registered() assert isinstance(registered, list) assert len(registered) == 1 - assert registered[0] == 'alias' + assert registered[0] == "alias" def test_registry_get_instance(): @@ -65,9 +65,9 @@ def __init__(self, message=None): def validate(self, value): pass - reg.register('test', TestClass) + reg.register("test", TestClass) - validator = {'name': 'test'} + validator = {"name": "test"} instance = reg.get_instance(validator) @@ -75,30 +75,29 @@ def validate(self, value): def test_register(validators_registry): - - @register('alias') + @register("alias") class TestClass(Validator): def validate(self, value): pass - assert 'alias' in validators_registry - assert issubclass(validators_registry['alias'], TestClass) + assert "alias" in validators_registry + assert issubclass(validators_registry["alias"], TestClass) def test_register_already_registered(validators_registry): - - @register('alias') + @register("alias") class TestClass(Validator): def validate(self, value): pass with pytest.raises(AlreadyRegisteredError) as cv: - @register('alias') + + @register("alias") class TestClass2(Validator): def validate(self, value): pass - assert str(cv.value) == 'The validator `alias` is already registered.' + assert str(cv.value) == "The validator `alias` is already registered." def test_get_registered(validators_registry): @@ -107,7 +106,7 @@ def test_get_registered(validators_registry): assert isinstance(registered, list) assert len(registered) == 0 - @register('alias') + @register("alias") class TestClass(Validator): def validate(self, value): pass @@ -116,13 +115,12 @@ def validate(self, value): assert isinstance(registered, list) assert len(registered) == 1 - assert registered[0] == 'alias' + assert registered[0] == "alias" -@pytest.mark.parametrize('args', ({}, {'message': 'message'})) +@pytest.mark.parametrize("args", [{}, {"message": "message"}]) def test_get_instance(validators_registry, args): - - @register('test') + @register("test") class TestClass(Validator): def __init__(self, message=None): self.message = message @@ -130,7 +128,7 @@ def __init__(self, message=None): def validate(self, value): pass - validator = {'name': 'test', 'args': args} + validator = {"name": "test", "args": args} instance = get_instance(validator) assert isinstance(instance, TestClass) diff --git a/tests/widgets/test_wizard.py b/tests/widgets/test_wizard.py index 3b6a5d0..e74aeb5 100644 --- a/tests/widgets/test_wizard.py +++ b/tests/widgets/test_wizard.py @@ -1,4 +1,4 @@ -from interrogatio.handlers import get_instance, QHandler +from interrogatio.handlers import QHandler, get_instance from interrogatio.validators import RequiredValidator from interrogatio.widgets.wizard import WizardDialog @@ -6,160 +6,160 @@ def test_wizard_init_default(): questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], - 'disabled': True, + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], + "disabled": True, }, { - 'name': 'question3', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question3", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers) + wz = WizardDialog("title", handlers) assert len(wz.steps) == 3 def test_wizard_init_intro_summary(): questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers, intro='intro', summary=True) + wz = WizardDialog("title", handlers, intro="intro", summary=True) assert len(wz.steps) == 4 def test_wizard_get_title(): questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers) - assert wz.get_title() == 'title - 1 of 2' + wz = WizardDialog("title", handlers) + assert wz.get_title() == "title - 1 of 2" def test_wizard_get_steps_label(): questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question3', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'disabled': True, + "name": "question3", + "type": "input", + "message": "message", + "description": "description", + "disabled": True, }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers) + wz = WizardDialog("title", handlers) steps_lables = wz.get_steps_labels() class_current = steps_lables.children[0].content.text[0][0] - assert 'class:dialog.step.current ' == class_current - assert '1. Question1' == steps_lables.children[0].content.text[0][1] - assert 'class:dialog.step ' == steps_lables.children[1].content.text[0][0] - assert '2. Question2' == steps_lables.children[1].content.text[0][1] - assert 'disabled' in steps_lables.children[2].content.text[0][0] - assert '3. Question3' == steps_lables.children[2].content.text[0][1] + assert "class:dialog.step.current " == class_current + assert "1. Question1" == steps_lables.children[0].content.text[0][1] + assert "class:dialog.step " == steps_lables.children[1].content.text[0][0] + assert "2. Question2" == steps_lables.children[1].content.text[0][1] + assert "disabled" in steps_lables.children[2].content.text[0][0] + assert "3. Question3" == steps_lables.children[2].content.text[0][1] def test_wizard_get_status(): questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers) - assert wz.get_status().text == '' + wz = WizardDialog("title", handlers) + assert wz.get_status().text == "" - wz.error_messages = 'An error' - assert wz.get_status().content.text[0][0] == 'class:error' - assert wz.get_status().content.text[0][1] == 'An error' + wz.error_messages = "An error" + assert wz.get_status().content.text[0][0] == "class:error" + assert wz.get_status().content.text[0][1] == "An error" def test_wizard_cancel(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers) + wz = WizardDialog("title", handlers) wz.cancel() mocked_app.exit.assert_called_once_with(result=False) @@ -169,35 +169,35 @@ def always_true(context): return True mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], - 'disabled': always_true, + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], + "disabled": always_true, }, { - 'name': 'question3', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], - 'disabled': False, + "name": "question3", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], + "disabled": False, }, ] handlers = [get_instance(q) for q in questions] - mocked_validate = mocker.patch.object(WizardDialog, 'validate') - wz = WizardDialog('title', handlers) + mocked_validate = mocker.patch.object(WizardDialog, "validate") + wz = WizardDialog("title", handlers) wz.next() # noqa: B305 assert wz.current_step_idx == 2 assert wz.current_step == wz.steps[2] @@ -209,34 +209,34 @@ def always_true(context): def test_wizard_next_with_disabled(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question3', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], - 'disabled': True, + "name": "question3", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], + "disabled": True, }, ] handlers = [get_instance(q) for q in questions] - mocked_validate = mocker.patch.object(WizardDialog, 'validate') - wz = WizardDialog('title', handlers) + mocked_validate = mocker.patch.object(WizardDialog, "validate") + wz = WizardDialog("title", handlers) wz.next() # noqa: B305 assert wz.current_step_idx == 1 assert wz.current_step == wz.steps[1] @@ -248,41 +248,41 @@ def test_wizard_next_with_disabled(mocker): def test_wizard_previous(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], - 'disabled': True, + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], + "disabled": True, }, { - 'name': 'question3', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question3", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question4', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question4", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - mocker.patch.object(WizardDialog, 'validate') - wz = WizardDialog('title', handlers) + mocker.patch.object(WizardDialog, "validate") + wz = WizardDialog("title", handlers) wz.next() # noqa: B305 wz.previous() assert wz.current_step_idx == 0 @@ -293,26 +293,26 @@ def test_wizard_previous(mocker): def test_wizard_next_latest_step(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - mocked_validate = mocker.patch.object(WizardDialog, 'validate') - wz = WizardDialog('title', handlers) + mocked_validate = mocker.patch.object(WizardDialog, "validate") + wz = WizardDialog("title", handlers) wz.next() # noqa: B305 wz.next() # noqa: B305 assert wz.current_step_idx == 1 @@ -325,26 +325,26 @@ def test_wizard_next_latest_step(mocker): def test_wizard_previous_first_step(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - mocker.patch.object(WizardDialog, 'validate') - wz = WizardDialog('title', handlers) + mocker.patch.object(WizardDialog, "validate") + wz = WizardDialog("title", handlers) wz.next() # noqa: B305 wz.previous() wz.previous() @@ -356,26 +356,26 @@ def test_wizard_previous_first_step(mocker): def test_wizard_next_latest_step_with_summary(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - mocked_validate = mocker.patch.object(WizardDialog, 'validate') - wz = WizardDialog('title', handlers, summary=True) + mocked_validate = mocker.patch.object(WizardDialog, "validate") + wz = WizardDialog("title", handlers, summary=True) wz.next() # noqa: B305 wz.next() # noqa: B305 wz.next() # noqa: B305 @@ -389,49 +389,51 @@ def test_wizard_next_latest_step_with_summary(mocker): def test_get_summary(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] mocker.patch.object( - QHandler, 'get_formatted_value', side_effect=['value1', 'value2'], + QHandler, + "get_formatted_value", + side_effect=["value1", "value2"], ) - wz = WizardDialog('title', handlers, summary=True) + wz = WizardDialog("title", handlers, summary=True) summary = wz.get_summary() expected_text1 = summary.content.text[0][1] + summary.content.text[1][1] expected_text2 = summary.content.text[2][1] + summary.content.text[3][1] - assert 'Question1: value1' in expected_text1 - assert 'Question2: value2' in expected_text2 + assert "Question1: value1" in expected_text1 + assert "Question2: value2" in expected_text2 def test_single_step(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', + "name": "question1", + "type": "input", + "message": "message", + "description": "description", }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers) + wz = WizardDialog("title", handlers) wz.next() # noqa: B305 assert wz.current_step_idx == 0 assert wz.current_step == wz.steps[0] @@ -442,127 +444,127 @@ def test_single_step(mocker): def test_wizard_next_validate_invalid(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [RequiredValidator('This field is required')], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "validators": [RequiredValidator("This field is required")], }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers) + wz = WizardDialog("title", handlers) wz.next() # noqa: B305 assert wz.current_step_idx == 0 assert wz.current_step == wz.steps[0] assert len(wz.buttons) == 2 - assert wz.error_messages == 'This field is required' + assert wz.error_messages == "This field is required" def test_wizard_get_current_step_container(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', + "name": "question1", + "type": "input", + "message": "message", + "description": "description", }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers) - assert wz.get_current_step_container() == wz.steps[0]['layout'] + wz = WizardDialog("title", handlers) + assert wz.get_current_step_container() == wz.steps[0]["layout"] def test_wizard_get_buttons_container(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', + "name": "question1", + "type": "input", + "message": "message", + "description": "description", }, ] handlers = [get_instance(q) for q in questions] - wz = WizardDialog('title', handlers) + wz = WizardDialog("title", handlers) assert wz.get_buttons_container() is not None def test_wizard_fast_forward(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'default': 'value', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "default": "value", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], - 'disabled': True, + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], + "disabled": True, }, { - 'name': 'question3', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'default': 'value', - 'validators': [{'name': 'required'}], + "name": "question3", + "type": "input", + "message": "message", + "description": "description", + "default": "value", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] - mocker.patch.object(WizardDialog, 'validate') - wz = WizardDialog('title', handlers, fast_forward=True) + mocker.patch.object(WizardDialog, "validate") + wz = WizardDialog("title", handlers, fast_forward=True) assert wz.current_step_idx == 2 assert wz.current_step == wz.steps[-1] def test_wizard_fast_forward_with_error(mocker): mocked_app = mocker.MagicMock() - mocker.patch('interrogatio.widgets.wizard.get_app', return_value=mocked_app) + mocker.patch("interrogatio.widgets.wizard.get_app", return_value=mocked_app) questions = [ { - 'name': 'question1', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'default': 'value', - 'validators': [{'name': 'required'}], + "name": "question1", + "type": "input", + "message": "message", + "description": "description", + "default": "value", + "validators": [{"name": "required"}], }, { - 'name': 'question2', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], - 'disabled': True, + "name": "question2", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], + "disabled": True, }, { - 'name': 'question3', - 'type': 'input', - 'message': 'message', - 'description': 'description', - 'validators': [{'name': 'required'}], + "name": "question3", + "type": "input", + "message": "message", + "description": "description", + "validators": [{"name": "required"}], }, ] handlers = [get_instance(q) for q in questions] mocker.patch.object( WizardDialog, - 'validate', + "validate", side_effect=[True, True, False], ) - wz = WizardDialog('title', handlers, summary=True, fast_forward=True) + wz = WizardDialog("title", handlers, summary=True, fast_forward=True) assert wz.current_step_idx == 2 assert wz.current_step == wz.steps[2]