summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-12-23 18:53:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-12-23 18:53:19 +0000
commit38d39f536e5a6cff5a218c5dc16994d6eee087e9 (patch)
tree151b916ddadb35113bac2cd954d99ea26ec64cc0
parentUpdating source url in copyright. (diff)
downloadterminaltables-38d39f536e5a6cff5a218c5dc16994d6eee087e9.tar.xz
terminaltables-38d39f536e5a6cff5a218c5dc16994d6eee087e9.zip
Merging upstream version 4.0.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.converagerc25
-rw-r--r--.env_example1
-rw-r--r--.github/workflows/build.yml57
-rw-r--r--.gitignore2
-rw-r--r--.pre-commit-config.yaml95
-rw-r--r--.pylintrc633
-rw-r--r--CHANGELOG.md15
-rw-r--r--Makefile104
-rw-r--r--Pipfile16
-rw-r--r--README.md30
-rw-r--r--dead_code/.travis.yml49
-rw-r--r--dead_code/README.rst162
-rw-r--r--dead_code/appveyor.yml27
-rw-r--r--dead_code/setup.py109
-rw-r--r--docs/conf.py55
-rwxr-xr-xexample1.py19
-rwxr-xr-xexample2.py52
-rwxr-xr-xexample3.py24
-rw-r--r--poetry.lock1058
-rw-r--r--pyproject-whl.toml66
-rw-r--r--pyproject.toml67
-rw-r--r--terminaltables/__init__.py17
-rw-r--r--terminaltables/other_tables.py177
-rw-r--r--terminaltables3/__init__.py17
-rw-r--r--terminaltables3/ascii_table.py (renamed from terminaltables/ascii_table.py)28
-rw-r--r--terminaltables3/base_table.py (renamed from terminaltables/base_table.py)183
-rw-r--r--terminaltables3/build.py (renamed from terminaltables/build.py)45
-rw-r--r--terminaltables3/github_table.py (renamed from terminaltables/github_table.py)31
-rw-r--r--terminaltables3/other_tables.py173
-rw-r--r--terminaltables3/terminal_io.py (renamed from terminaltables/terminal_io.py)32
-rw-r--r--terminaltables3/width_and_alignment.py (renamed from terminaltables/width_and_alignment.py)90
-rw-r--r--tests/__init__.py2
-rw-r--r--tests/screenshot.py106
-rw-r--r--tests/test_all_tables_e2e/test_ascii_table.py117
-rw-r--r--tests/test_all_tables_e2e/test_double_table.py288
-rw-r--r--tests/test_all_tables_e2e/test_github_table.py73
-rw-r--r--tests/test_all_tables_e2e/test_porcelain_table.py55
-rw-r--r--tests/test_all_tables_e2e/test_single_table.py226
-rw-r--r--tests/test_all_tables_e2e/test_single_table_windows.py288
-rw-r--r--tests/test_ascii_table.py100
-rw-r--r--tests/test_base_table/__init__.py0
-rw-r--r--tests/test_base_table/test_gen_row_lines.py34
-rw-r--r--tests/test_base_table/test_gen_table.py224
-rw-r--r--tests/test_base_table/test_horizontal_border.py98
-rw-r--r--tests/test_base_table/test_table.py162
-rw-r--r--tests/test_build/__init__.py0
-rw-r--r--tests/test_build/test_build_border.py463
-rw-r--r--tests/test_build/test_build_row.py74
-rw-r--r--tests/test_build/test_combine.py24
-rw-r--r--tests/test_build/test_flatten.py13
-rw-r--r--tests/test_examples.py10
-rw-r--r--tests/test_terminal_io/__init__.py14
-rw-r--r--tests/test_terminal_io/test_get_console_info.py7
-rw-r--r--tests/test_terminal_io/test_set_terminal_title.py60
-rw-r--r--tests/test_terminal_io/test_terminal_size.py17
-rw-r--r--tests/test_width_and_alignment/__init__.py0
-rw-r--r--tests/test_width_and_alignment/test_align_and_pad_cell.py349
-rw-r--r--tests/test_width_and_alignment/test_column_max_width.py59
-rw-r--r--tests/test_width_and_alignment/test_max_dimensions.py93
-rw-r--r--tests/test_width_and_alignment/test_table_width.py47
-rw-r--r--tests/test_width_and_alignment/test_visible_width.py88
-rw-r--r--tox.ini69
62 files changed, 4198 insertions, 2421 deletions
diff --git a/.converagerc b/.converagerc
new file mode 100644
index 0000000..98306ea
--- /dev/null
+++ b/.converagerc
@@ -0,0 +1,25 @@
+[run]
+branch = True
+
+[report]
+; Regexes for lines to exclude from consideration
+exclude_also =
+ ; Don't complain about missing debug-only code:
+ def __repr__
+ if self\.debug
+
+ ; Don't complain if tests don't hit defensive assertion code:
+ raise AssertionError
+ raise NotImplementedError
+
+ ; Don't complain if non-runnable code isn't run:
+ if 0:
+ if __name__ == .__main__.:
+
+ ; Don't complain about abstract methods, they aren't run:
+ @(abc\.)?abstractmethod
+
+ignore_errors = True
+
+[html]
+directory = coverage_html_report \ No newline at end of file
diff --git a/.env_example b/.env_example
index 0048805..47c32b4 100644
--- a/.env_example
+++ b/.env_example
@@ -1,3 +1,4 @@
export PYTHONIOENCODING=utf-8
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
+export FORCE_COLOR=true \ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..938602c
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,57 @@
+name: Build and Test
+
+on: [ push ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+ # cache: 'pipenv' # caching pipenv dependencies
+ - name: Install poetry and pipx
+ run: |
+ pip install poetry && pip install pipx
+
+ - name: Install global dependencies
+ run: |
+ pipx install isort && pipx install black && pipx install bandit && \
+ pipx install pylint && pipx install pre-commit && pipx install poetry
+
+ - name: Install Dependencies
+ run: poetry install --with dev
+
+ - name: Run Makefile
+ run: make check
+ - name: Run make
+ run: poetry run make publish
+ - name: Upload Package
+ uses: actions/upload-artifact@v3.1.2
+ with:
+ name: packages
+ path: dist/
+ if-no-files-found: error
+ retention-days: 1
+
+
+ pypi-publish:
+ name: Upload release to PyPI
+ runs-on: ubuntu-latest
+ environment:
+ name: pypi
+ url: https://pypi.org/p/terminaltables3
+ permissions:
+ id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
+ # if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
+ steps:
+ - name: Get packages
+ uses: actions/download-artifact@v3.0.2
+ with:
+ name: packages
+ path: dist/
+ - name: Publish package distributions to PyPI
+ uses: pypa/gh-action-pypi-publish@release/v1
+ needs: build \ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 53889c8..536d481 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,3 +94,5 @@ test*.png
.idea/
requirements*.txt
.DS_Store
+
+.build_history/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..37c4248
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,95 @@
+---
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.6.0
+ hooks:
+ # each hook takes about 1s to run. These are expensive-ish checks
+ - id: check-added-large-files
+ - id: check-yaml
+ - id: check-builtin-literals
+ - id: check-byte-order-marker
+ - id: check-case-conflict
+ - id: check-merge-conflict
+ - id: check-symlinks
+ - id: check-toml
+ - id: debug-statements
+ - id: detect-private-key
+ - id: fix-encoding-pragma
+ args: [ --remove ]
+ - id: forbid-new-submodules
+ - repo: https://github.com/asottile/pyupgrade
+ rev: v3.16.0
+ hooks:
+ - id: pyupgrade
+ args: [ --py37-plus ]
+ # Buggy? Reports no files change, "FAILURE"
+ # - repo: https://github.com/tox-dev/pyproject-fmt
+ # rev: "0.4.1"
+ # hooks:
+ # - id: pyproject-fmt
+ # works for me, don't know why it is complaining
+ # - repo: https://github.com/abravalheri/validate-pyproject
+ # rev: v0.10.1
+ # hooks:
+ # - id: validate-pyproject
+ - repo: https://github.com/myint/autoflake
+ rev: v2.3.1
+ hooks:
+ - id: autoflake
+ args:
+ - --in-place
+ - --recursive
+ - --expand-star-imports
+ - --remove-all-unused-imports
+ - --remove-duplicate-keys
+ - --remove-unused-variables
+# black is conflicting with something else
+# - repo: https://github.com/psf/black
+# rev: 23.12.1
+# hooks:
+# - id: black
+# language_version: python3.10
+ # - repo: https://github.com/pycqa/isort
+ # rev: 5.11.4
+ # hooks:
+ # - id: isort
+ # name: isort
+ # args:
+ # - --profile black
+ - repo: https://github.com/charliermarsh/ruff-pre-commit
+ rev: v0.5.2
+ hooks:
+ - id: ruff
+ exclude: ^dead_code/
+ args: [
+ "--config",
+ "pyproject.toml",
+ "--fix",
+ ]
+ - repo: https://github.com/pre-commit/pygrep-hooks
+ rev: v1.10.0 # Use the ref you want to point at
+ hooks:
+ - id: python-use-type-annotations
+ - id: python-no-eval
+ - id: python-no-log-warn
+ - id: text-unicode-replacement-char
+# - repo: https://github.com/igorshubovych/markdownlint-cli
+# rev: v0.38.0
+# hooks:
+# - id: markdownlint
+# # '--fix'
+# args: [ 'content/**/*.md', '--config', '.markdownlintrc' ]
+# - repo: https://github.com/executablebooks/mdformat
+# rev: 0.7.17 # Use the ref you want to point at
+# hooks:
+# - id: mdformat
+# # Optionally add plugins
+# additional_dependencies:
+# - mdformat-gfm
+# - mdformat-black
+# - repo: https://github.com/adamchainz/blacken-docs
+# rev: 1.18.0
+# hooks:
+# - id: blacken-docs
+# additional_dependencies:
+# - black==23.12.1
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 0000000..5a53fb6
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,633 @@
+[MAIN]
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Load and enable all available extensions. Use --list-extensions to see a list
+# all available extensions.
+#enable-all-extensions=
+
+# In error mode, checkers without error messages are disabled and for others,
+# only the ERROR messages are displayed, and no reports are done by default.
+#errors-only=
+
+# Always return a 0 (non-error) status code, even if lint errors are found.
+# This is primarily useful in continuous integration scripts.
+#exit-zero=
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code.
+extension-pkg-allow-list=
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
+# for backward compatibility.)
+extension-pkg-whitelist=
+
+# Return non-zero exit code if any of these messages/categories are detected,
+# even if score is above --fail-under value. Syntax same as enable. Messages
+# specified are enabled, while categories only check already-enabled messages.
+fail-on=
+
+# Specify a score threshold to be exceeded before program exits with error.
+fail-under=10
+
+# Interpret the stdin as a python script, whose filename needs to be passed as
+# the module_or_package argument.
+#from-stdin=
+
+# Files or directories to be skipped. They should be base names, not paths.
+ignore=CVS
+
+# Add files or directories matching the regex patterns to the ignore-list. The
+# regex matches against paths and can be in Posix or Windows format.
+ignore-paths=
+
+# Files or directories matching the regex patterns are skipped. The regex
+# matches against base names, not paths. The default value ignores Emacs file
+# locks
+ignore-patterns=^\.#
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis). It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
+# number of processors available to use.
+jobs=1
+
+# Control the amount of potential inferred values when inferring a single
+# object. This can help the performance when dealing with large functions or
+# complex, nested conditions.
+limit-inference-results=100
+
+# List of plugins (as comma separated values of python module names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# Minimum Python version to use for version dependent checks. Will default to
+# the version used to run pylint.
+py-version=3.10
+
+# Discover python modules and packages in the file system subtree.
+recursive=no
+
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages.
+suggestion-mode=yes
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+# In verbose mode, extra non-checker-related info will be displayed.
+#verbose=
+
+
+[REPORTS]
+
+# Python expression which should return a score less than or equal to 10. You
+# have access to the variables 'fatal', 'error', 'warning', 'refactor',
+# 'convention', and 'info' which contain the number of messages in each
+# category, as well as 'statement' which is the total number of statements
+# analyzed. This score is used by the global evaluation report (RP0004).
+evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details.
+msg-template=
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio). You can also give a reporter class, e.g.
+# mypackage.mymodule.MyReporterClass.
+#output-format=
+
+# Tells whether to display a full report or only the messages.
+reports=no
+
+# Activate the evaluation score.
+score=yes
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
+# UNDEFINED.
+confidence=HIGH,
+ CONTROL_FLOW,
+ INFERENCE,
+ INFERENCE_FAILURE,
+ UNDEFINED
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once). You can also use "--disable=all" to
+# disable everything first and then re-enable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use "--disable=all --enable=classes
+# --disable=W".
+disable=raw-checker-failed,
+ bad-inline-option,
+ locally-disabled,
+ file-ignored,
+ suppressed-message,
+ useless-suppression,
+ deprecated-pragma,
+ use-symbolic-message-instead,
+
+ # can't care
+ fixme,
+ too-many-lines,
+ too-many-branches,
+ import-error,
+ too-many-statements,
+ useless-import-alias,
+ too-many-locals,
+ consider-using-from-import, # pylint is wrong
+ duplicate-code,
+ too-many-arguments,
+ logging-fstring-interpolation,
+ too-many-instance-attributes,
+ too-many-return-statements,
+ unnecessary-direct-lambda-call,
+ too-few-public-methods,
+ logging-not-lazy,
+ line-too-long,
+ too-many-public-methods,
+
+ # backwards compatibility forever!
+ consider-using-f-string,
+ super-with-arguments
+
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+enable=c-extension-no-member
+
+
+[BASIC]
+
+# Naming style matching correct argument names.
+argument-naming-style=snake_case
+
+# Regular expression matching correct argument names. Overrides argument-
+# naming-style. If left empty, argument names will be checked with the set
+# naming style.
+#argument-rgx=
+
+# Naming style matching correct attribute names.
+attr-naming-style=snake_case
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style. If left empty, attribute names will be checked with the set naming
+# style.
+#attr-rgx=
+
+# Bad variable names which should always be refused, separated by a comma.
+bad-names=foo,
+ bar,
+ baz,
+ toto,
+ tutu,
+ tata
+
+# Bad variable names regexes, separated by a comma. If names match any regex,
+# they will always be refused
+bad-names-rgxs=
+
+# Naming style matching correct class attribute names.
+class-attribute-naming-style=any
+
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style. If left empty, class attribute names will be checked
+# with the set naming style.
+#class-attribute-rgx=
+
+# Naming style matching correct class constant names.
+class-const-naming-style=UPPER_CASE
+
+# Regular expression matching correct class constant names. Overrides class-
+# const-naming-style. If left empty, class constant names will be checked with
+# the set naming style.
+#class-const-rgx=
+
+# Naming style matching correct class names.
+class-naming-style=PascalCase
+
+# Regular expression matching correct class names. Overrides class-naming-
+# style. If left empty, class names will be checked with the set naming style.
+#class-rgx=
+
+# Naming style matching correct constant names.
+const-naming-style=UPPER_CASE
+
+# Regular expression matching correct constant names. Overrides const-naming-
+# style. If left empty, constant names will be checked with the set naming
+# style.
+#const-rgx=
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+# Naming style matching correct function names.
+function-naming-style=snake_case
+
+# Regular expression matching correct function names. Overrides function-
+# naming-style. If left empty, function names will be checked with the set
+# naming style.
+#function-rgx=
+
+# Good variable names which should always be accepted, separated by a comma.
+good-names=i,
+ j,
+ k,
+ ex,
+ Run,
+ _
+
+# Good variable names regexes, separated by a comma. If names match any regex,
+# they will always be accepted
+good-names-rgxs=
+
+# Include a hint for the correct naming format with invalid-name.
+include-naming-hint=no
+
+# Naming style matching correct inline iteration names.
+inlinevar-naming-style=any
+
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style. If left empty, inline iteration names will be checked
+# with the set naming style.
+#inlinevar-rgx=
+
+# Naming style matching correct method names.
+method-naming-style=snake_case
+
+# Regular expression matching correct method names. Overrides method-naming-
+# style. If left empty, method names will be checked with the set naming style.
+#method-rgx=
+
+# Naming style matching correct module names.
+module-naming-style=snake_case
+
+# Regular expression matching correct module names. Overrides module-naming-
+# style. If left empty, module names will be checked with the set naming style.
+#module-rgx=
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+# These decorators are taken in consideration only for invalid-name.
+property-classes=abc.abstractproperty
+
+# Regular expression matching correct type variable names. If left empty, type
+# variable names will be checked with the set naming style.
+#typevar-rgx=
+
+# Naming style matching correct variable names.
+variable-naming-style=snake_case
+
+# Regular expression matching correct variable names. Overrides variable-
+# naming-style. If left empty, variable names will be checked with the set
+# naming style.
+#variable-rgx=
+
+
+[CLASSES]
+
+# Warn about protected attribute access inside special methods
+check-protected-access-in-special-methods=no
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+ __new__,
+ setUp,
+ __post_init__
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+ _fields,
+ _replace,
+ _source,
+ _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=cls
+
+
+[DESIGN]
+
+# List of regular expressions of class ancestor names to ignore when counting
+# public methods (see R0903)
+exclude-too-few-public-methods=
+
+# List of qualified class names to ignore when counting class parents (see
+# R0901)
+ignored-parents=
+
+# Maximum number of arguments for function / method.
+max-args=5
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Maximum number of boolean expressions in an if statement (see R0916).
+max-bool-expr=5
+
+# Maximum number of branch for function / method body.
+max-branches=12
+
+# Maximum number of locals for function / method body.
+max-locals=15
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of return / yield for function / method body.
+max-returns=6
+
+# Maximum number of statements in function / method body.
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when caught.
+overgeneral-exceptions=builtins.BaseException,
+ builtins.Exception
+
+
+[FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+# Maximum number of characters on a single line.
+max-line-length=120
+
+# Maximum number of lines in a module.
+max-module-lines=1000
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+
+[IMPORTS]
+
+# List of modules that can be imported at any level, not just the top level
+# one.
+allow-any-import-level=
+
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Deprecated modules which should not be used, separated by a comma.
+deprecated-modules=
+
+# Output a graph (.gv or any supported image format) of external dependencies
+# to the given file (report RP0402 must not be disabled).
+ext-import-graph=
+
+# Output a graph (.gv or any supported image format) of all (i.e. internal and
+# external) dependencies to the given file (report RP0402 must not be
+# disabled).
+import-graph=
+
+# Output a graph (.gv or any supported image format) of internal dependencies
+# to the given file (report RP0402 must not be disabled).
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
+
+# Couples of modules and preferred modules, separated by a comma.
+preferred-modules=
+
+
+[LOGGING]
+
+# The type of string formatting that logging methods do. `old` means using %
+# formatting, `new` is for `{}` formatting.
+logging-format-style=old
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format.
+logging-modules=logging
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,
+ XXX,
+ TODO
+
+# Regular expression of note tags to take in consideration.
+notes-rgx=
+
+
+[REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+# Complete name of functions that never returns. When checking for
+# inconsistent-return-statements if a never returning function is called then
+# it will be considered as an explicit return statement and no message will be
+# printed.
+never-returning-functions=sys.exit,argparse.parse_error
+
+
+[SIMILARITIES]
+
+# Comments are removed from the similarity computation
+ignore-comments=yes
+
+# Docstrings are removed from the similarity computation
+ignore-docstrings=yes
+
+# Imports are removed from the similarity computation
+ignore-imports=yes
+
+# Signatures are removed from the similarity computation
+ignore-signatures=yes
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+
+[SPELLING]
+
+# Limits count of emitted suggestions for spelling mistakes.
+max-spelling-suggestions=4
+
+# Spelling dictionary name. Available dictionaries: none. To make it work,
+# install the 'python-enchant' package.
+spelling-dict=
+
+# List of comma separated words that should be considered directives if they
+# appear at the beginning of a comment and should not be checked.
+spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains the private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to the private dictionary (see the
+# --spelling-private-dict-file option) instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[STRING]
+
+# This flag controls whether inconsistent-quotes generates a warning when the
+# character used as a quote delimiter is used inconsistently within a module.
+check-quote-consistency=no
+
+# This flag controls whether the implicit-str-concat should generate a warning
+# on implicit string concatenation in sequences defined over several lines.
+check-str-concat-over-line-jumps=no
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+# Tells whether to warn about missing members when the owner of the attribute
+# is inferred to be None.
+ignore-none=yes
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
+
+# List of symbolic message names to ignore for Mixin members.
+ignored-checks-for-mixins=no-member,
+ not-async-context-manager,
+ not-context-manager,
+ attribute-defined-outside-init
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+# Regex pattern to define which classes are considered mixins.
+mixin-class-rgx=.*[Mm]ixin
+
+# List of decorators that change the signature of a decorated function.
+signature-mutators=
+
+
+[VARIABLES]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid defining new builtins when possible.
+additional-builtins=
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of names allowed to shadow builtins
+allowed-redefined-builtins=
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,
+ _cb
+
+# A regular expression matching the name of dummy variables (i.e. expected to
+# not be used).
+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore.
+ignored-argument-names=_.*|^ignored_|^unused_
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e8706fe..fa06ec6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,20 @@ Changelog
This project adheres to `Semantic Versioning <http://semver.org/>`_.
-3.1.7 - 2016-12-7
+4.0.0 - 2024-1-1
+------------------
+
+Changed
+ * New namespace and package name: terminaltables3
+ * No changes made to the License.
+
+Added
+ * Started on type annotations
+
+Removed
+ * Removed Python 2 support. Possibly supports earlier 3.x versions but no longer checking in build script.
+
+3.1.7 - 2021-1-1
------------------
Added
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4b57351
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,104 @@
+# isort . && black . && bandit -r . && pylint && pre-commit run --all-files
+# Get changed files
+
+FILES := $(wildcard **/*.py)
+
+# if you wrap everything in pipenv run, it runs slower.
+ifeq ($(origin VIRTUAL_ENV),undefined)
+ VENV := poetry run
+else
+ VENV :=
+endif
+
+
+
+clean-pyc:
+ @echo "Removing compiled files"
+ @find . -name '*.pyc' -exec rm -f {} + || true
+ @find . -name '*.pyo' -exec rm -f {} + || true
+ @find . -name '__pycache__' -exec rm -fr {} + || true
+
+clean-test:
+ @echo "Removing coverage data"
+ @rm -f .coverage || true
+ @rm -f .coverage.* || true
+
+clean: clean-pyc clean-test
+
+# tests can't be expected to pass if dependencies aren't installed.
+# tests are often slow and linting is fast, so run tests on linted code.
+test: clean .build_history/pylint .build_history/bandit
+ @echo "Running unit tests"
+ export FORCE_COLOR=true
+ # $(VENV) pytest terminaltables3 --doctest-modules
+ # $(VENV) python -m unittest discover
+ # not all tests run in all OSs, giving seemingly low coverage.
+ FORCE_COLOR=true $(VENV) py.test tests --cov=terminaltables3 --cov-report=html --cov-fail-under 75
+
+.build_history:
+ @mkdir -p .build_history
+
+.build_history/isort: .build_history $(FILES)
+ @echo "Formatting imports"
+ $(VENV) isort terminaltables3
+ @touch .build_history/isort
+
+.PHONY: isort
+isort: .build_history/isort
+
+.build_history/black: .build_history .build_history/isort $(FILES)
+ @echo "Formatting code"
+ $(VENV) black . --exclude .virtualenv --exclude .tox
+ @touch .build_history/black
+
+.PHONY: black
+black: .build_history/black
+
+.build_history/pre-commit: .build_history .build_history/isort .build_history/black
+ @echo "Pre-commit checks"
+ $(VENV) pre-commit run --all-files
+ @touch .build_history/pre-commit
+
+.PHONY: pre-commit
+pre-commit: .build_history/pre-commit
+
+.build_history/bandit: .build_history $(FILES)
+ @echo "Security checks"
+ $(VENV) bandit .
+ @touch .build_history/bandit
+
+.PHONY: bandit
+bandit: .build_history/bandit
+
+.PHONY: pylint
+.build_history/pylint: .build_history .build_history/isort .build_history/black $(FILES)
+ @echo "Linting with pylint"
+ # TODO lint tests
+ $(VENV) pylint terminaltables3 --fail-under 10
+ @touch .build_history/pylint
+
+.PHONY: ruff
+.build_history/ruff: .build_history .build_history/isort .build_history/black $(FILES)
+ @echo "Linting with ruff"
+ $(VENV) ruff check terminaltables3 tests --fix
+ @touch .build_history/ruff
+
+.PHONY: ruff
+ruff: .build_history/ruff
+
+# for when using -j (jobs, run in parallel)
+.NOTPARALLEL: .build_history/isort .build_history/black
+
+check: test pylint ruff bandit pre-commit
+
+.PHONY: publish
+publish: check
+ rm -rf dist && poetry build
+
+.PHONY: build
+build: check
+ rm -rf dist && poetry build
+
+.PHONY: mypy
+mypy:
+ $(VENV) mypy terminaltables3 --ignore-missing-imports --check-untyped-defs \ No newline at end of file
diff --git a/Pipfile b/Pipfile
deleted file mode 100644
index 829b4c6..0000000
--- a/Pipfile
+++ /dev/null
@@ -1,16 +0,0 @@
-[[source]]
-url = "https://pypi.org/simple"
-verify_ssl = true
-name = "pypi"
-
-[packages]
-
-[dev-packages]
-colorama=">=0.3.7"
-colorclass=">=2.2.0"
-pytest-cov=">=2.4.0"
-termcolor = "*"
-check-wheel-contents = "*"
-
-[requires]
-python_version = "3.9"
diff --git a/README.md b/README.md
index 98e626a..31762ed 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,19 @@
-## terminaltables
-
# What is it
Easily draw tables in terminal/console applications from a list of lists of strings. Supports multi-line rows.
-- Python 2.6, 2.7, PyPy, PyPy3, 3.3, 3.4, and 3.5+ supported on Linux and OS X.
-- Python 2.7, 3.3, 3.4, and 3.5+ supported on Windows (both 32 and 64 bit versions of Python).
+Tested on Python 3.8+
+
+**This is a fork of the terminaltables project. Which is archived and unmaintained. This library is in a new namespace
+but should otherwise be a drop in replacement. Maintaining goals consist of maintaining ecosystem compatibility, type
+annotations and responding to community pull requests.**
+
+To Upgrade
+==========
+Replace all instances of `terminaltables` with `terminaltables3` in your code. If other libraries depend on `terminaltables`
+in your venv they will not conflict because it is a new namespace.
+
+As of right now, the documentation as the robpol86 version.
📖 Full documentation: https://robpol86.github.io/terminaltables
@@ -15,19 +23,19 @@ Quickstart
Install:
```bash
-pip install terminaltables
+pip install terminaltables3
```
Usage:
```python
-from terminaltables import AsciiTable
+from terminaltables3 import AsciiTable
table_data = [
- ['Heading1', 'Heading2'],
- ['row1 column1', 'row1 column2'],
- ['row2 column1', 'row2 column2'],
- ['row3 column1', 'row3 column2']
+ ["Heading1", "Heading2"],
+ ["row1 column1", "row1 column2"],
+ ["row2 column1", "row2 column2"],
+ ["row3 column1", "row3 column2"],
]
table = AsciiTable(table_data)
print
@@ -54,4 +62,4 @@ Source code for examples:
- [example2.py](https://github.com/matthewdeanmartin/terminaltables/blob/master/example2.py)
- [example3.py](https://github.com/matthewdeanmartin/terminaltables/blob/master/example3.py)
-[Change Log](https://github.com/matthewdeanmartin/terminaltables/blob/master/CHANGELOG.md) \ No newline at end of file
+[Change Log](https://github.com/matthewdeanmartin/terminaltables/blob/master/CHANGELOG.md)
diff --git a/dead_code/.travis.yml b/dead_code/.travis.yml
deleted file mode 100644
index 02cf421..0000000
--- a/dead_code/.travis.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-# Configure.
-language: python
-python:
- - 3.5
- - 3.4
- - 3.3
- - pypy3
- - pypy
- - 2.7
- - 2.6
-sudo: false
-
-# Environment and matrix.
-env: TOX_ENV=py
-matrix:
- include:
- - python: 3.5
- env: TOX_ENV=lint
- after_success: []
- - python: 3.5
- env: TOX_ENV=docs
- after_success:
- - eval "$(ssh-agent -s)"; touch docs/key; chmod 0600 $_
- - openssl aes-256-cbc -d -K "$encrypted_c89fed6a587d_key" -iv "$encrypted_c89fed6a587d_iv" -out docs/key
- < docs/key.enc && ssh-add $_
- - git config --global user.email "builds@travis-ci.com"
- - git config --global user.name "Travis CI"
- - git remote set-url --push origin "git@github.com:$TRAVIS_REPO_SLUG"
- - export ${!TRAVIS*}
- - tox -e docsV
-
-# Run.
-install: pip install tox
-script: tox -e $TOX_ENV
-after_success:
- - bash <(curl -s https://codecov.io/bash)
-
-# Deploy.
-deploy:
- provider: pypi
- user: Robpol86
- password:
- secure:
- "aj+Hl25+NbtmKpHcqxxNJhaMmawgzEPdLX+NwxwAZuTrvUCdiMtYhF9qxN0USHIlXSGDNc\
- 7ua6nNpYPhjRv7j5YM4uLlK+4Fv/iU+iQcVfy89BS4vlXzUoje6nLIhogsxytb+FjdGZ0PK\
- JzzxfYr0relUjui/gPYmTQoZ1IiT8A="
- on:
- condition: $TRAVIS_PYTHON_VERSION = 3.4
- tags: true
diff --git a/dead_code/README.rst b/dead_code/README.rst
deleted file mode 100644
index fe9044f..0000000
--- a/dead_code/README.rst
+++ /dev/null
@@ -1,162 +0,0 @@
-==============
-terminaltables
-==============
-
-Easily draw tables in terminal/console applications from a list of lists of strings. Supports multi-line rows.
-
-* Python 2.6, 2.7, PyPy, PyPy3, 3.3, 3.4, and 3.5 supported on Linux and OS X.
-* Python 2.7, 3.3, 3.4, and 3.5 supported on Windows (both 32 and 64 bit versions of Python).
-
-📖 Full documentation: https://robpol86.github.io/terminaltables
-
-.. image:: https://img.shields.io/appveyor/ci/Robpol86/terminaltables/master.svg?style=flat-square&label=AppVeyor%20CI
- :target: https://ci.appveyor.com/project/Robpol86/terminaltables
- :alt: Build Status Windows
-
-.. image:: https://img.shields.io/travis/Robpol86/terminaltables/master.svg?style=flat-square&label=Travis%20CI
- :target: https://travis-ci.org/Robpol86/terminaltables
- :alt: Build Status
-
-.. image:: https://img.shields.io/codecov/c/github/Robpol86/terminaltables/master.svg?style=flat-square&label=Codecov
- :target: https://codecov.io/gh/Robpol86/terminaltables
- :alt: Coverage Status
-
-.. image:: https://img.shields.io/pypi/v/terminaltables.svg?style=flat-square&label=Latest
- :target: https://pypi.python.org/pypi/terminaltables
- :alt: Latest Version
-
-Quickstart
-==========
-
-Install:
-
-.. code:: bash
-
- pip install terminaltables
-
-Usage:
-
-.. code::
-
- from terminaltables import AsciiTable
- table_data = [
- ['Heading1', 'Heading2'],
- ['row1 column1', 'row1 column2'],
- ['row2 column1', 'row2 column2'],
- ['row3 column1', 'row3 column2']
- ]
- table = AsciiTable(table_data)
- print table.table
- +--------------+--------------+
- | Heading1 | Heading2 |
- +--------------+--------------+
- | row1 column1 | row1 column2 |
- | row2 column1 | row2 column2 |
- | row3 column1 | row3 column2 |
- +--------------+--------------+
-
-Example Implementations
-=======================
-
-.. image:: docs/examples.png?raw=true
- :alt: Example Scripts Screenshot
-
-Source code for examples: `example1.py <https://github.com/Robpol86/terminaltables/blob/master/example1.py>`_,
-`example2.py <https://github.com/Robpol86/terminaltables/blob/master/example2.py>`_, and
-`example3.py <https://github.com/Robpol86/terminaltables/blob/master/example3.py>`_
-
-.. changelog-section-start
-
-Changelog
-=========
-
-This project adheres to `Semantic Versioning <http://semver.org/>`_.
-
-3.1.0 - 2016-10-16
-------------------
-
-Added
- * ``git --porcelain``-like table by liiight: https://github.com/Robpol86/terminaltables/pull/31
-
-3.0.0 - 2016-05-30
-------------------
-
-Added
- * Support for https://pypi.python.org/pypi/colorama
- * Support for https://pypi.python.org/pypi/termcolor
- * Support for RTL characters (Arabic and Hebrew).
- * Support for non-string items in ``table_data`` like integers.
-
-Changed
- * Refactored again, but this time entire project including tests.
-
-Removed
- * ``padded_table_data`` property and ``join_row()``. Moving away from repeated string joining/splitting.
-
-Fixed
- * ``set_terminal_title()`` Unicode handling on Windows.
- * https://github.com/Robpol86/terminaltables/issues/18
- * https://github.com/Robpol86/terminaltables/issues/20
- * https://github.com/Robpol86/terminaltables/issues/23
- * https://github.com/Robpol86/terminaltables/issues/26
-
-2.1.0 - 2015-11-02
-------------------
-
-Added
- * GitHub Flavored Markdown table by bcho: https://github.com/Robpol86/terminaltables/pull/12
- * Python 3.5 support (Linux/OS X and Windows).
-
-2.0.0 - 2015-10-11
-------------------
-
-Changed
- * Refactored code. No new features.
- * Breaking changes: ``UnixTable``/``WindowsTable``/``WindowsTableDouble`` moved. Use ``SingleTable``/``DoubleTable``
- instead.
-
-1.2.1 - 2015-09-03
-------------------
-
-Fixed
- * CJK character width fixed by zqqf16 and bcho: https://github.com/Robpol86/terminaltables/pull/9
-
-1.2.0 - 2015-05-31
-------------------
-
-Added
- * Bottom row separator.
-
-1.1.1 - 2014-11-03
-------------------
-
-Fixed
- * Python 2.7 64-bit terminal width bug on Windows.
-
-1.1.0 - 2014-11-02
-------------------
-
-Added
- * Windows support.
- * Double-lined table.
-
-1.0.2 - 2014-09-18
-------------------
-
-Added
- * ``table_width`` and ``ok`` properties.
-
-1.0.1 - 2014-09-12
-------------------
-
-Added
- * Terminal width/height defaults for testing.
- * ``terminaltables.DEFAULT_TERMINAL_WIDTH``
- * ``terminaltables.DEFAULT_TERMINAL_HEIGHT``
-
-1.0.0 - 2014-09-11
-------------------
-
-* Initial release.
-
-.. changelog-section-end
diff --git a/dead_code/appveyor.yml b/dead_code/appveyor.yml
deleted file mode 100644
index 8b7d1c9..0000000
--- a/dead_code/appveyor.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-# Configure.
-environment:
- PATH: C:\%PYTHON%;C:\%PYTHON%\Scripts;%PATH%
- PYTHON: Python35
- matrix:
- - TOX_ENV: lint
- - TOX_ENV: py35
- - TOX_ENV: py34
- - TOX_ENV: py33
- - TOX_ENV: py27
- - TOX_ENV: py
- PYTHON: Python35-x64
- - TOX_ENV: py
- PYTHON: Python34-x64
- - TOX_ENV: py
- PYTHON: Python33-x64
- - TOX_ENV: py
- PYTHON: Python27-x64
-
-# Run.
-build_script: pip install tox
-test_script: tox -e %TOX_ENV%
-on_success: IF %TOX_ENV% NEQ lint pip install codecov & codecov
-
-# Post.
-on_finish:
- - FOR %%F IN (test*.png) DO appveyor PushArtifact %%F
diff --git a/dead_code/setup.py b/dead_code/setup.py
deleted file mode 100644
index a947444..0000000
--- a/dead_code/setup.py
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env python
-"""Setup script for the project."""
-
-import codecs
-import os
-import re
-
-from setuptools import Command, setup
-
-INSTALL_REQUIRES = []
-LICENSE = 'MIT'
-NAME = IMPORT = 'terminaltables'
-VERSION = '3.1.0'
-
-
-def readme(path='README.rst'):
- """Try to read README.rst or return empty string if failed.
-
- :param str path: Path to README file.
-
- :return: File contents.
- :rtype: str
- """
- path = os.path.realpath(os.path.join(os.path.dirname(__file__), path))
- handle = None
- url_prefix = 'https://raw.githubusercontent.com/Robpol86/{name}/v{version}/'.format(name=NAME, version=VERSION)
- try:
- handle = codecs.open(path, encoding='utf-8')
- return handle.read(131072).replace('.. image:: docs', '.. image:: {0}docs'.format(url_prefix))
- except IOError:
- return ''
- finally:
- getattr(handle, 'close', lambda: None)()
-
-
-class CheckVersion(Command):
- """Make sure version strings and other metadata match here, in module/package, tox, and other places."""
-
- description = 'verify consistent version/etc strings in project'
- user_options = []
-
- @classmethod
- def initialize_options(cls):
- """Required by distutils."""
- pass
-
- @classmethod
- def finalize_options(cls):
- """Required by distutils."""
- pass
-
- @classmethod
- def run(cls):
- """Check variables."""
- project = __import__(IMPORT, fromlist=[''])
- for expected, var in [('@Robpol86', '__author__'), (LICENSE, '__license__'), (VERSION, '__version__')]:
- if getattr(project, var) != expected:
- raise SystemExit('Mismatch: {0}'.format(var))
- # Check changelog.
- if not re.compile(r'^%s - \d{4}-\d{2}-\d{2}[\r\n]' % VERSION, re.MULTILINE).search(readme()):
- raise SystemExit('Version not found in readme/changelog file.')
- # Check tox.
- if INSTALL_REQUIRES:
- contents = readme('tox.ini')
- section = re.compile(r'[\r\n]+install_requires =[\r\n]+(.+?)[\r\n]+\w', re.DOTALL).findall(contents)
- if not section:
- raise SystemExit('Missing install_requires section in tox.ini.')
- in_tox = re.findall(r' ([^=]+)==[\w\d.-]+', section[0])
- if INSTALL_REQUIRES != in_tox:
- raise SystemExit('Missing/unordered pinned dependencies in tox.ini.')
-
-
-if __name__ == '__main__':
- setup(
- author='@Robpol86',
- author_email='robpol86@gmail.com',
- classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Environment :: Console',
- 'Environment :: MacOS X',
- 'Environment :: Win32 (MS Windows)',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: MIT License',
- 'Operating System :: MacOS :: MacOS X',
- 'Operating System :: Microsoft :: Windows',
- 'Operating System :: POSIX :: Linux',
- 'Operating System :: POSIX',
- 'Programming Language :: Python :: 2.6',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3.3',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: Implementation :: PyPy',
- 'Topic :: Software Development :: Libraries',
- 'Topic :: Terminals',
- 'Topic :: Text Processing :: Markup',
- ],
- cmdclass=dict(check_version=CheckVersion),
- description='Generate simple tables in terminals from a nested list of strings.',
- install_requires=INSTALL_REQUIRES,
- keywords='Shell Bash ANSI ASCII terminal tables',
- license=LICENSE,
- long_description=readme(),
- name=NAME,
- packages=[IMPORT],
- url='https://github.com/Robpol86/' + NAME,
- version=VERSION,
- zip_safe=True,
- )
diff --git a/docs/conf.py b/docs/conf.py
index 0e8b9c0..dd96129 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -6,50 +6,55 @@ import time
# General configuration.
-sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), '..')))
-author = '@Robpol86'
-copyright = '{}, {}'.format(time.strftime('%Y'), author)
-html_last_updated_fmt = '%c {}'.format(time.tzname[time.localtime().tm_isdst])
-master_doc = 'index'
-project = __import__('setup').NAME
-pygments_style = 'friendly'
-release = version = __import__('setup').VERSION
-templates_path = ['_templates']
-extensions = list()
+sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), "..")))
+author = "@Robpol86"
+copyright = "{}, {}".format(time.strftime("%Y"), author)
+html_last_updated_fmt = f"%c {time.tzname[time.localtime().tm_isdst]}"
+master_doc = "index"
+project = __import__("setup").NAME
+pygments_style = "friendly"
+release = version = __import__("setup").VERSION
+templates_path = ["_templates"]
+extensions = []
# Options for HTML output.
html_context = dict(
- conf_py_path='/docs/',
+ conf_py_path="/docs/",
display_github=True,
- github_repo=os.environ.get('TRAVIS_REPO_SLUG', '/' + project).split('/', 1)[1],
- github_user=os.environ.get('TRAVIS_REPO_SLUG', 'robpol86/').split('/', 1)[0],
- github_version=os.environ.get('TRAVIS_BRANCH', 'master'),
- source_suffix='.rst',
+ github_repo=os.environ.get("TRAVIS_REPO_SLUG", "/" + project).split("/", 1)[1],
+ github_user=os.environ.get("TRAVIS_REPO_SLUG", "robpol86/").split("/", 1)[0],
+ github_version=os.environ.get("TRAVIS_BRANCH", "master"),
+ source_suffix=".rst",
)
html_copy_source = False
-html_favicon = 'favicon.ico'
-html_theme = 'sphinx_rtd_theme'
+html_favicon = "favicon.ico"
+html_theme = "sphinx_rtd_theme"
html_title = project
# autodoc
-extensions.append('sphinx.ext.autodoc')
+extensions.append("sphinx.ext.autodoc")
# extlinks.
-extensions.append('sphinx.ext.extlinks')
-extlinks = {'github': ('https://github.com/robpol86/{0}/blob/v{1}/%s'.format(project, version), '')}
+extensions.append("sphinx.ext.extlinks")
+extlinks = {
+ "github": (
+ f"https://github.com/robpol86/{project}/blob/v{version}/%s",
+ "",
+ )
+}
# google analytics
-extensions.append('sphinxcontrib.googleanalytics')
-googleanalytics_id = 'UA-82627369-1'
+extensions.append("sphinxcontrib.googleanalytics")
+googleanalytics_id = "UA-82627369-1"
# SCVersioning.
scv_banner_greatest_tag = True
-scv_grm_exclude = ('.gitignore', '.nojekyll', 'README.rst')
-scv_overflow = ('-W',)
+scv_grm_exclude = (".gitignore", ".nojekyll", "README.rst")
+scv_overflow = ("-W",)
scv_show_banner = True
-scv_sort = ('semver', 'time')
+scv_sort = ("semver", "time")
diff --git a/example1.py b/example1.py
index daf1fbf..4006eac 100755
--- a/example1.py
+++ b/example1.py
@@ -4,39 +4,38 @@
Just prints sample text and exits.
"""
-from __future__ import print_function
-from terminaltables import AsciiTable, DoubleTable, SingleTable
+from terminaltables3 import AsciiTable, DoubleTable, SingleTable
TABLE_DATA = (
- ('Platform', 'Years', 'Notes'),
- ('Mk5', '2007-2009', 'The Golf Mk5 Variant was\nintroduced in 2007.'),
- ('MKVI', '2009-2013', 'Might actually be Mk5.'),
+ ("Platform", "Years", "Notes"),
+ ("Mk5", "2007-2009", "The Golf Mk5 Variant was\nintroduced in 2007."),
+ ("MKVI", "2009-2013", "Might actually be Mk5."),
)
def main():
"""Main function."""
- title = 'Jetta SportWagen'
+ title = "Jetta SportWagen"
# AsciiTable.
table_instance = AsciiTable(TABLE_DATA, title)
- table_instance.justify_columns[2] = 'right'
+ table_instance.justify_columns[2] = "right"
print(table_instance.table)
print()
# SingleTable.
table_instance = SingleTable(TABLE_DATA, title)
- table_instance.justify_columns[2] = 'right'
+ table_instance.justify_columns[2] = "right"
print(table_instance.table)
print()
# DoubleTable.
table_instance = DoubleTable(TABLE_DATA, title)
- table_instance.justify_columns[2] = 'right'
+ table_instance.justify_columns[2] = "right"
print(table_instance.table)
print()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/example2.py b/example2.py
index 51644f8..b644d62 100755
--- a/example2.py
+++ b/example2.py
@@ -4,19 +4,21 @@
Just prints sample text and exits.
"""
-from __future__ import print_function
from colorclass import Color, Windows
-from terminaltables import SingleTable
+from terminaltables3 import SingleTable
def table_server_timings():
"""Return table string to be printed."""
table_data = [
- [Color('{autogreen}<10ms{/autogreen}'), '192.168.0.100, 192.168.0.101'],
- [Color('{autoyellow}10ms <= 100ms{/autoyellow}'), '192.168.0.102, 192.168.0.103'],
- [Color('{autored}>100ms{/autored}'), '192.168.0.105'],
+ [Color("{autogreen}<10ms{/autogreen}"), "192.168.0.100, 192.168.0.101"],
+ [
+ Color("{autoyellow}10ms <= 100ms{/autoyellow}"),
+ "192.168.0.102, 192.168.0.103",
+ ],
+ [Color("{autored}>100ms{/autored}"), "192.168.0.105"],
]
table_instance = SingleTable(table_data)
table_instance.inner_heading_row_border = False
@@ -26,20 +28,32 @@ def table_server_timings():
def table_server_status():
"""Return table string to be printed."""
table_data = [
- [Color('Low Space'), Color('{autocyan}Nominal Space{/autocyan}'), Color('Excessive Space')],
- [Color('Low Load'), Color('Nominal Load'), Color('{autored}High Load{/autored}')],
- [Color('{autocyan}Low Free RAM{/autocyan}'), Color('Nominal Free RAM'), Color('High Free RAM')],
+ [
+ Color("Low Space"),
+ Color("{autocyan}Nominal Space{/autocyan}"),
+ Color("Excessive Space"),
+ ],
+ [
+ Color("Low Load"),
+ Color("Nominal Load"),
+ Color("{autored}High Load{/autored}"),
+ ],
+ [
+ Color("{autocyan}Low Free RAM{/autocyan}"),
+ Color("Nominal Free RAM"),
+ Color("High Free RAM"),
+ ],
]
- table_instance = SingleTable(table_data, '192.168.0.105')
+ table_instance = SingleTable(table_data, "192.168.0.105")
table_instance.inner_heading_row_border = False
table_instance.inner_row_border = True
- table_instance.justify_columns = {0: 'center', 1: 'center', 2: 'center'}
+ table_instance.justify_columns = {0: "center", 1: "center", 2: "center"}
return table_instance.table
def table_abcd():
"""Return table string to be printed. Two tables on one line."""
- table_instance = SingleTable([['A', 'B'], ['C', 'D']])
+ table_instance = SingleTable([["A", "B"], ["C", "D"]])
# Get first table lines.
table_instance.outer_border = False
@@ -53,16 +67,18 @@ def table_abcd():
# Combine.
smallest, largest = sorted([table_inner_borders, table_outer_borders], key=len)
- smallest += [''] * (len(largest) - len(smallest)) # Make both same size.
- combined = list()
+ smallest += [""] * (len(largest) - len(smallest)) # Make both same size.
+ combined = []
for i, row in enumerate(largest):
- combined.append(row.ljust(10) + ' ' + smallest[i])
- return '\n'.join(combined)
+ combined.append(row.ljust(10) + " " + smallest[i])
+ return "\n".join(combined)
def main():
"""Main function."""
- Windows.enable(auto_colors=True, reset_atexit=True) # Does nothing if not on Windows.
+ Windows.enable(
+ auto_colors=True, reset_atexit=True
+ ) # Does nothing if not on Windows.
# Server timings.
print(table_server_timings())
@@ -77,10 +93,10 @@ def main():
print()
# Instructions.
- table_instance = SingleTable([['Obey Obey Obey Obey']], 'Instructions')
+ table_instance = SingleTable([["Obey Obey Obey Obey"]], "Instructions")
print(table_instance.table)
print()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/example3.py b/example3.py
index bec5500..c32d842 100755
--- a/example3.py
+++ b/example3.py
@@ -4,33 +4,37 @@
Just prints sample text and exits.
"""
-from __future__ import print_function
from textwrap import wrap
-from terminaltables import SingleTable
+from terminaltables3 import SingleTable
-LONG_STRING = ('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore '
- 'et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut '
- 'aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum '
- 'dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui '
- 'officia deserunt mollit anim id est laborum.')
+LONG_STRING = (
+ "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore "
+ "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut "
+ "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum "
+ "dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui "
+ "officia deserunt mollit anim id est laborum."
+)
def main():
"""Main function."""
table_data = [
- ['Long String', ''], # One row. Two columns. Long string will replace this empty string.
+ [
+ "Long String",
+ "",
+ ], # One row. Two columns. Long string will replace this empty string.
]
table = SingleTable(table_data)
# Calculate newlines.
max_width = table.column_max_width(1)
- wrapped_string = '\n'.join(wrap(LONG_STRING, max_width))
+ wrapped_string = "\n".join(wrap(LONG_STRING, max_width))
table.table_data[0][1] = wrapped_string
print(table.table)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/poetry.lock b/poetry.lock
new file mode 100644
index 0000000..b7f1f5e
--- /dev/null
+++ b/poetry.lock
@@ -0,0 +1,1058 @@
+# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
+
+[[package]]
+name = "astroid"
+version = "3.2.3"
+description = "An abstract syntax tree for Python with inference support."
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "astroid-3.2.3-py3-none-any.whl", hash = "sha256:3eae9ea67c11c858cdd2c91337d2e816bd019ac897ca07d7b346ac10105fceb3"},
+ {file = "astroid-3.2.3.tar.gz", hash = "sha256:7099b5a60985529d8d46858befa103b82d0d05a5a5e8b816b5303ed96075e1d9"},
+]
+
+[package.dependencies]
+typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""}
+
+[[package]]
+name = "bandit"
+version = "1.7.9"
+description = "Security oriented static analyser for python code."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "bandit-1.7.9-py3-none-any.whl", hash = "sha256:52077cb339000f337fb25f7e045995c4ad01511e716e5daac37014b9752de8ec"},
+ {file = "bandit-1.7.9.tar.gz", hash = "sha256:7c395a436743018f7be0a4cbb0a4ea9b902b6d87264ddecf8cfdc73b4f78ff61"},
+]
+
+[package.dependencies]
+colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""}
+PyYAML = ">=5.3.1"
+rich = "*"
+stevedore = ">=1.20.0"
+
+[package.extras]
+baseline = ["GitPython (>=3.1.30)"]
+sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"]
+test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"]
+toml = ["tomli (>=1.1.0)"]
+yaml = ["PyYAML"]
+
+[[package]]
+name = "black"
+version = "24.4.2"
+description = "The uncompromising code formatter."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"},
+ {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"},
+ {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"},
+ {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"},
+ {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"},
+ {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"},
+ {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"},
+ {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"},
+ {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"},
+ {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"},
+ {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"},
+ {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"},
+ {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"},
+ {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"},
+ {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"},
+ {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"},
+ {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"},
+ {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"},
+ {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"},
+ {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"},
+ {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"},
+ {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"},
+]
+
+[package.dependencies]
+click = ">=8.0.0"
+mypy-extensions = ">=0.4.3"
+packaging = ">=22.0"
+pathspec = ">=0.9.0"
+platformdirs = ">=2"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
+
+[package.extras]
+colorama = ["colorama (>=0.4.3)"]
+d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
+jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
+uvloop = ["uvloop (>=0.15.2)"]
+
+[[package]]
+name = "cachetools"
+version = "5.3.3"
+description = "Extensible memoizing collections and decorators"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"},
+ {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"},
+]
+
+[[package]]
+name = "cfgv"
+version = "3.4.0"
+description = "Validate configuration and produce human readable error messages."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
+ {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
+]
+
+[[package]]
+name = "chardet"
+version = "5.2.0"
+description = "Universal encoding detector for Python 3"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"},
+ {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"},
+]
+
+[[package]]
+name = "click"
+version = "8.1.7"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
+ {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "colorclass"
+version = "2.2.2"
+description = "Colorful worry-free console applications for Linux, Mac OS X, and Windows."
+optional = false
+python-versions = ">=2.6"
+files = [
+ {file = "colorclass-2.2.2-py2.py3-none-any.whl", hash = "sha256:6f10c273a0ef7a1150b1120b6095cbdd68e5cf36dfd5d0fc957a2500bbf99a55"},
+ {file = "colorclass-2.2.2.tar.gz", hash = "sha256:6d4fe287766166a98ca7bc6f6312daf04a0481b1eda43e7173484051c0ab4366"},
+]
+
+[[package]]
+name = "coverage"
+version = "7.6.0"
+description = "Code coverage measurement for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "coverage-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd"},
+ {file = "coverage-7.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c"},
+ {file = "coverage-7.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463"},
+ {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791"},
+ {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c"},
+ {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783"},
+ {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6"},
+ {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb"},
+ {file = "coverage-7.6.0-cp310-cp310-win32.whl", hash = "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c"},
+ {file = "coverage-7.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169"},
+ {file = "coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933"},
+ {file = "coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d"},
+ {file = "coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94"},
+ {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1"},
+ {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac"},
+ {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57"},
+ {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d"},
+ {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63"},
+ {file = "coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713"},
+ {file = "coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1"},
+ {file = "coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"},
+ {file = "coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8"},
+ {file = "coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5"},
+ {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807"},
+ {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382"},
+ {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b"},
+ {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee"},
+ {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605"},
+ {file = "coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da"},
+ {file = "coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67"},
+ {file = "coverage-7.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b"},
+ {file = "coverage-7.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d"},
+ {file = "coverage-7.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca"},
+ {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b"},
+ {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44"},
+ {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03"},
+ {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6"},
+ {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b"},
+ {file = "coverage-7.6.0-cp38-cp38-win32.whl", hash = "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428"},
+ {file = "coverage-7.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8"},
+ {file = "coverage-7.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c"},
+ {file = "coverage-7.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2"},
+ {file = "coverage-7.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390"},
+ {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b"},
+ {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450"},
+ {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6"},
+ {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166"},
+ {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd"},
+ {file = "coverage-7.6.0-cp39-cp39-win32.whl", hash = "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2"},
+ {file = "coverage-7.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca"},
+ {file = "coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6"},
+ {file = "coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51"},
+]
+
+[package.dependencies]
+tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
+
+[package.extras]
+toml = ["tomli"]
+
+[[package]]
+name = "dill"
+version = "0.3.8"
+description = "serialize all of Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"},
+ {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"},
+]
+
+[package.extras]
+graph = ["objgraph (>=1.7.2)"]
+profile = ["gprof2dot (>=2022.7.29)"]
+
+[[package]]
+name = "distlib"
+version = "0.3.8"
+description = "Distribution utilities"
+optional = false
+python-versions = "*"
+files = [
+ {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
+ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.2.2"
+description = "Backport of PEP 654 (exception groups)"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
+ {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
+]
+
+[package.extras]
+test = ["pytest (>=6)"]
+
+[[package]]
+name = "execnet"
+version = "2.1.1"
+description = "execnet: rapid multi-Python deployment"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"},
+ {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"},
+]
+
+[package.extras]
+testing = ["hatch", "pre-commit", "pytest", "tox"]
+
+[[package]]
+name = "filelock"
+version = "3.15.4"
+description = "A platform independent file lock."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"},
+ {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"]
+typing = ["typing-extensions (>=4.8)"]
+
+[[package]]
+name = "identify"
+version = "2.6.0"
+description = "File identification library for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"},
+ {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"},
+]
+
+[package.extras]
+license = ["ukkonen"]
+
+[[package]]
+name = "importlib-metadata"
+version = "8.0.0"
+description = "Read metadata from Python packages"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"},
+ {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"},
+]
+
+[package.dependencies]
+zipp = ">=0.5"
+
+[package.extras]
+doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+perf = ["ipython"]
+test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"]
+
+[[package]]
+name = "iniconfig"
+version = "2.0.0"
+description = "brain-dead simple config-ini parsing"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
+ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
+]
+
+[[package]]
+name = "isort"
+version = "5.13.2"
+description = "A Python utility / library to sort Python imports."
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
+ {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
+]
+
+[package.extras]
+colors = ["colorama (>=0.4.6)"]
+
+[[package]]
+name = "markdown-it-py"
+version = "3.0.0"
+description = "Python port of markdown-it. Markdown parsing, done right!"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
+ {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
+]
+
+[package.dependencies]
+mdurl = ">=0.1,<1.0"
+
+[package.extras]
+benchmarking = ["psutil", "pytest", "pytest-benchmark"]
+code-style = ["pre-commit (>=3.0,<4.0)"]
+compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
+linkify = ["linkify-it-py (>=1,<3)"]
+plugins = ["mdit-py-plugins"]
+profiling = ["gprof2dot"]
+rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
+testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
+
+[[package]]
+name = "mccabe"
+version = "0.7.0"
+description = "McCabe checker, plugin for flake8"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
+ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+description = "Markdown URL utilities"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
+ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
+]
+
+[[package]]
+name = "mypy"
+version = "1.10.1"
+description = "Optional static typing for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"},
+ {file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"},
+ {file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"},
+ {file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"},
+ {file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"},
+ {file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"},
+ {file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"},
+ {file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"},
+ {file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"},
+ {file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"},
+ {file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"},
+ {file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"},
+ {file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"},
+ {file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"},
+ {file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"},
+ {file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"},
+ {file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"},
+ {file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"},
+ {file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"},
+ {file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"},
+ {file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"},
+ {file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"},
+ {file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"},
+ {file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"},
+ {file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"},
+ {file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"},
+ {file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"},
+]
+
+[package.dependencies]
+mypy-extensions = ">=1.0.0"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typing-extensions = ">=4.1.0"
+
+[package.extras]
+dmypy = ["psutil (>=4.0)"]
+install-types = ["pip"]
+mypyc = ["setuptools (>=50)"]
+reports = ["lxml"]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.0.0"
+description = "Type system extensions for programs checked with the mypy type checker."
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
+ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
+]
+
+[[package]]
+name = "nodeenv"
+version = "1.9.1"
+description = "Node.js virtual environment builder"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
+ {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
+]
+
+[[package]]
+name = "packaging"
+version = "24.1"
+description = "Core utilities for Python packages"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
+ {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
+]
+
+[[package]]
+name = "pathspec"
+version = "0.12.1"
+description = "Utility library for gitignore style pattern matching of file paths."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
+ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
+]
+
+[[package]]
+name = "pbr"
+version = "6.0.0"
+description = "Python Build Reasonableness"
+optional = false
+python-versions = ">=2.6"
+files = [
+ {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"},
+ {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"},
+]
+
+[[package]]
+name = "pillow"
+version = "10.4.0"
+description = "Python Imaging Library (Fork)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"},
+ {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"},
+ {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"},
+ {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"},
+ {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"},
+ {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"},
+ {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"},
+ {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"},
+ {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"},
+ {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"},
+ {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"},
+ {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"},
+ {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"},
+ {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"},
+ {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"},
+ {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"},
+ {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"},
+ {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"},
+ {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"},
+ {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"},
+ {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"},
+ {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"},
+ {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"},
+ {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"},
+ {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"},
+ {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"},
+ {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"},
+ {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"},
+ {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"},
+ {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"},
+ {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"},
+ {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"},
+ {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"},
+ {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"},
+ {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"},
+ {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"},
+ {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"},
+ {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"},
+ {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"},
+ {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"},
+ {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"},
+ {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"},
+ {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"},
+ {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"},
+ {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"},
+ {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"},
+ {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"},
+ {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"},
+ {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"},
+ {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"},
+ {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"},
+ {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"},
+ {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"},
+ {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"},
+ {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"},
+ {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"},
+ {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"},
+ {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"},
+ {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"},
+ {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"},
+ {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"},
+ {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"},
+ {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"},
+ {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"},
+ {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"},
+ {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"},
+ {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"},
+ {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"},
+]
+
+[package.extras]
+docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
+fpx = ["olefile"]
+mic = ["olefile"]
+tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
+typing = ["typing-extensions"]
+xmp = ["defusedxml"]
+
+[[package]]
+name = "platformdirs"
+version = "4.2.2"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
+ {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
+type = ["mypy (>=1.8)"]
+
+[[package]]
+name = "pluggy"
+version = "1.5.0"
+description = "plugin and hook calling mechanisms for python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
+ {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
+]
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
+
+[[package]]
+name = "pre-commit"
+version = "3.5.0"
+description = "A framework for managing and maintaining multi-language pre-commit hooks."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"},
+ {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"},
+]
+
+[package.dependencies]
+cfgv = ">=2.0.0"
+identify = ">=1.0.0"
+nodeenv = ">=0.11.1"
+pyyaml = ">=5.1"
+virtualenv = ">=20.10.0"
+
+[[package]]
+name = "pygments"
+version = "2.18.0"
+description = "Pygments is a syntax highlighting package written in Python."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
+ {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
+]
+
+[package.extras]
+windows-terminal = ["colorama (>=0.4.6)"]
+
+[[package]]
+name = "pylint"
+version = "3.2.5"
+description = "python code static checker"
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "pylint-3.2.5-py3-none-any.whl", hash = "sha256:32cd6c042b5004b8e857d727708720c54a676d1e22917cf1a2df9b4d4868abd6"},
+ {file = "pylint-3.2.5.tar.gz", hash = "sha256:e9b7171e242dcc6ebd0aaa7540481d1a72860748a0a7816b8fe6cf6c80a6fe7e"},
+]
+
+[package.dependencies]
+astroid = ">=3.2.2,<=3.3.0-dev0"
+colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
+dill = [
+ {version = ">=0.2", markers = "python_version < \"3.11\""},
+ {version = ">=0.3.7", markers = "python_version >= \"3.12\""},
+ {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
+]
+isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
+mccabe = ">=0.6,<0.8"
+platformdirs = ">=2.2.0"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+tomlkit = ">=0.10.1"
+typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
+
+[package.extras]
+spelling = ["pyenchant (>=3.2,<4.0)"]
+testutils = ["gitpython (>3)"]
+
+[[package]]
+name = "pyproject-api"
+version = "1.7.1"
+description = "API to interact with the python pyproject.toml based projects"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pyproject_api-1.7.1-py3-none-any.whl", hash = "sha256:2dc1654062c2b27733d8fd4cdda672b22fe8741ef1dde8e3a998a9547b071eeb"},
+ {file = "pyproject_api-1.7.1.tar.gz", hash = "sha256:7ebc6cd10710f89f4cf2a2731710a98abce37ebff19427116ff2174c9236a827"},
+]
+
+[package.dependencies]
+packaging = ">=24.1"
+tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
+
+[package.extras]
+docs = ["furo (>=2024.5.6)", "sphinx-autodoc-typehints (>=2.2.1)"]
+testing = ["covdefaults (>=2.3)", "pytest (>=8.2.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "setuptools (>=70.1)"]
+
+[[package]]
+name = "pytest"
+version = "8.2.2"
+description = "pytest: simple powerful testing with Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"},
+ {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=1.5,<2.0"
+tomli = {version = ">=1", markers = "python_version < \"3.11\""}
+
+[package.extras]
+dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
+
+[[package]]
+name = "pytest-cov"
+version = "5.0.0"
+description = "Pytest plugin for measuring coverage."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"},
+ {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"},
+]
+
+[package.dependencies]
+coverage = {version = ">=5.2.1", extras = ["toml"]}
+pytest = ">=4.6"
+
+[package.extras]
+testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"]
+
+[[package]]
+name = "pytest-network"
+version = "0.0.1"
+description = "A simple plugin to disable network on socket level."
+optional = false
+python-versions = "*"
+files = [
+ {file = "pytest_network-0.0.1.tar.gz", hash = "sha256:7b109e2ad27f4ab0f13c1796a9b419bab1d503ea3b5ae3ca37363486ccceaa3f"},
+]
+
+[package.dependencies]
+pytest = ">=5.3.1"
+
+[[package]]
+name = "pytest-randomly"
+version = "3.15.0"
+description = "Pytest plugin to randomly order tests and control random.seed."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pytest_randomly-3.15.0-py3-none-any.whl", hash = "sha256:0516f4344b29f4e9cdae8bce31c4aeebf59d0b9ef05927c33354ff3859eeeca6"},
+ {file = "pytest_randomly-3.15.0.tar.gz", hash = "sha256:b908529648667ba5e54723088edd6f82252f540cc340d748d1fa985539687047"},
+]
+
+[package.dependencies]
+importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""}
+pytest = "*"
+
+[[package]]
+name = "pytest-sugar"
+version = "1.0.0"
+description = "pytest-sugar is a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly)."
+optional = false
+python-versions = "*"
+files = [
+ {file = "pytest-sugar-1.0.0.tar.gz", hash = "sha256:6422e83258f5b0c04ce7c632176c7732cab5fdb909cb39cca5c9139f81276c0a"},
+ {file = "pytest_sugar-1.0.0-py3-none-any.whl", hash = "sha256:70ebcd8fc5795dc457ff8b69d266a4e2e8a74ae0c3edc749381c64b5246c8dfd"},
+]
+
+[package.dependencies]
+packaging = ">=21.3"
+pytest = ">=6.2.0"
+termcolor = ">=2.1.0"
+
+[package.extras]
+dev = ["black", "flake8", "pre-commit"]
+
+[[package]]
+name = "pytest-xdist"
+version = "3.6.1"
+description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"},
+ {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"},
+]
+
+[package.dependencies]
+execnet = ">=2.1"
+pytest = ">=7.0.0"
+
+[package.extras]
+psutil = ["psutil (>=3.0)"]
+setproctitle = ["setproctitle"]
+testing = ["filelock"]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.1"
+description = "YAML parser and emitter for Python"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
+ {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
+ {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
+ {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
+ {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
+ {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
+ {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
+ {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
+ {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
+ {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
+ {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
+ {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
+ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
+]
+
+[[package]]
+name = "rich"
+version = "13.7.1"
+description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
+optional = false
+python-versions = ">=3.7.0"
+files = [
+ {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"},
+ {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
+]
+
+[package.dependencies]
+markdown-it-py = ">=2.2.0"
+pygments = ">=2.13.0,<3.0.0"
+typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""}
+
+[package.extras]
+jupyter = ["ipywidgets (>=7.5.1,<9)"]
+
+[[package]]
+name = "ruff"
+version = "0.5.2"
+description = "An extremely fast Python linter and code formatter, written in Rust."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "ruff-0.5.2-py3-none-linux_armv6l.whl", hash = "sha256:7bab8345df60f9368d5f4594bfb8b71157496b44c30ff035d1d01972e764d3be"},
+ {file = "ruff-0.5.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1aa7acad382ada0189dbe76095cf0a36cd0036779607c397ffdea16517f535b1"},
+ {file = "ruff-0.5.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:aec618d5a0cdba5592c60c2dee7d9c865180627f1a4a691257dea14ac1aa264d"},
+ {file = "ruff-0.5.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b62adc5ce81780ff04077e88bac0986363e4a3260ad3ef11ae9c14aa0e67ef"},
+ {file = "ruff-0.5.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc42ebf56ede83cb080a50eba35a06e636775649a1ffd03dc986533f878702a3"},
+ {file = "ruff-0.5.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c15c6e9f88c67ffa442681365d11df38afb11059fc44238e71a9d9f1fd51de70"},
+ {file = "ruff-0.5.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d3de9a5960f72c335ef00763d861fc5005ef0644cb260ba1b5a115a102157251"},
+ {file = "ruff-0.5.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe5a968ae933e8f7627a7b2fc8893336ac2be0eb0aace762d3421f6e8f7b7f83"},
+ {file = "ruff-0.5.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a04f54a9018f75615ae52f36ea1c5515e356e5d5e214b22609ddb546baef7132"},
+ {file = "ruff-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed02fb52e3741f0738db5f93e10ae0fb5c71eb33a4f2ba87c9a2fa97462a649"},
+ {file = "ruff-0.5.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3cf8fe659f6362530435d97d738eb413e9f090e7e993f88711b0377fbdc99f60"},
+ {file = "ruff-0.5.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:237a37e673e9f3cbfff0d2243e797c4862a44c93d2f52a52021c1a1b0899f846"},
+ {file = "ruff-0.5.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2a2949ce7c1cbd8317432ada80fe32156df825b2fd611688814c8557824ef060"},
+ {file = "ruff-0.5.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:481af57c8e99da92ad168924fd82220266043c8255942a1cb87958b108ac9335"},
+ {file = "ruff-0.5.2-py3-none-win32.whl", hash = "sha256:f1aea290c56d913e363066d83d3fc26848814a1fed3d72144ff9c930e8c7c718"},
+ {file = "ruff-0.5.2-py3-none-win_amd64.whl", hash = "sha256:8532660b72b5d94d2a0a7a27ae7b9b40053662d00357bb2a6864dd7e38819084"},
+ {file = "ruff-0.5.2-py3-none-win_arm64.whl", hash = "sha256:73439805c5cb68f364d826a5c5c4b6c798ded6b7ebaa4011f01ce6c94e4d5583"},
+ {file = "ruff-0.5.2.tar.gz", hash = "sha256:2c0df2d2de685433794a14d8d2e240df619b748fbe3367346baa519d8e6f1ca2"},
+]
+
+[[package]]
+name = "stevedore"
+version = "5.2.0"
+description = "Manage dynamic plugins for Python applications"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "stevedore-5.2.0-py3-none-any.whl", hash = "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9"},
+ {file = "stevedore-5.2.0.tar.gz", hash = "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d"},
+]
+
+[package.dependencies]
+pbr = ">=2.0.0,<2.1.0 || >2.1.0"
+
+[[package]]
+name = "termcolor"
+version = "2.4.0"
+description = "ANSI color formatting for output in terminal"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"},
+ {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"},
+]
+
+[package.extras]
+tests = ["pytest", "pytest-cov"]
+
+[[package]]
+name = "tomli"
+version = "2.0.1"
+description = "A lil' TOML parser"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
+ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
+]
+
+[[package]]
+name = "tomlkit"
+version = "0.13.0"
+description = "Style preserving TOML library"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "tomlkit-0.13.0-py3-none-any.whl", hash = "sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264"},
+ {file = "tomlkit-0.13.0.tar.gz", hash = "sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72"},
+]
+
+[[package]]
+name = "tox"
+version = "4.16.0"
+description = "tox is a generic virtualenv management and test command line tool"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "tox-4.16.0-py3-none-any.whl", hash = "sha256:61e101061b977b46cf00093d4319438055290ad0009f84497a07bf2d2d7a06d0"},
+ {file = "tox-4.16.0.tar.gz", hash = "sha256:43499656f9949edb681c0f907f86fbfee98677af9919d8b11ae5ad77cb800748"},
+]
+
+[package.dependencies]
+cachetools = ">=5.3.3"
+chardet = ">=5.2"
+colorama = ">=0.4.6"
+filelock = ">=3.15.4"
+packaging = ">=24.1"
+platformdirs = ">=4.2.2"
+pluggy = ">=1.5"
+pyproject-api = ">=1.7.1"
+tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
+virtualenv = ">=20.26.3"
+
+[package.extras]
+docs = ["furo (>=2024.5.6)", "sphinx (>=7.3.7)", "sphinx-argparse-cli (>=1.16)", "sphinx-autodoc-typehints (>=2.2.2)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.11)"]
+testing = ["build[virtualenv] (>=1.2.1)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.2)", "devpi-process (>=1)", "diff-cover (>=9.1)", "distlib (>=0.3.8)", "flaky (>=3.8.1)", "hatch-vcs (>=0.4)", "hatchling (>=1.25)", "psutil (>=6)", "pytest (>=8.2.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-xdist (>=3.6.1)", "re-assert (>=1.1)", "setuptools (>=70.2)", "time-machine (>=2.14.2)", "wheel (>=0.43)"]
+
+[[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 = "vermin"
+version = "1.6.0"
+description = "Concurrently detect the minimum Python versions needed to run code"
+optional = false
+python-versions = ">=3.0"
+files = [
+ {file = "vermin-1.6.0-py2.py3-none-any.whl", hash = "sha256:f1fa9ee40f59983dc40e0477eb2b1fa8061a3df4c3b2bcf349add462a5610efb"},
+ {file = "vermin-1.6.0.tar.gz", hash = "sha256:6266ca02f55d1c2aa189a610017c132eb2d1934f09e72a955b1eb3820ee6d4ef"},
+]
+
+[[package]]
+name = "virtualenv"
+version = "20.26.3"
+description = "Virtual Python Environment builder"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"},
+ {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"},
+]
+
+[package.dependencies]
+distlib = ">=0.3.7,<1"
+filelock = ">=3.12.2,<4"
+platformdirs = ">=3.9.1,<5"
+
+[package.extras]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
+test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
+
+[[package]]
+name = "zipp"
+version = "3.19.2"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"},
+ {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"},
+]
+
+[package.extras]
+doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
+
+[metadata]
+lock-version = "2.0"
+python-versions = ">=3.8"
+content-hash = "606c91a442e97c389b0e113520eef888b302b71d9d24ae48f90915cc30ec7190"
diff --git a/pyproject-whl.toml b/pyproject-whl.toml
deleted file mode 100644
index 3c186b7..0000000
--- a/pyproject-whl.toml
+++ /dev/null
@@ -1,66 +0,0 @@
-[tool.poetry]
-name = "terminaltables-whl"
-version = "3.1.0"
-description = "Generate simple tables in terminals from a nested list of strings."
-authors = [
- "Matthew Martin <matthewdeanmartin@gmail.com>",
- "Robpol86 <robpol86@gmail.com>",
-]
-keywords = ["Shell","Bash","ANSI","ASCII","terminal","tables"]
-classifiers = [
- "Development Status :: 5 - Production/Stable",
- "Environment :: Console",
- "Environment :: MacOS X",
- "Environment :: Win32 (MS Windows)",
- "Intended Audience :: Developers",
- "License :: OSI Approved :: MIT License",
- "Operating System :: MacOS :: MacOS X",
- "Operating System :: Microsoft :: Windows",
- "Operating System :: POSIX :: Linux",
- "Operating System :: POSIX",
- "Programming Language :: Python :: 2.6",
- "Programming Language :: Python :: 2.7",
- "Programming Language :: Python :: 3.3",
- "Programming Language :: Python :: 3.4",
- "Programming Language :: Python :: 3.5",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: Implementation :: PyPy",
- "Topic :: Software Development :: Libraries",
- "Topic :: Terminals",
- "Topic :: Text Processing :: Markup",
-]
-packages = [
- { include = "terminaltables" },
-]
-include = [
- "terminaltables/**/*.py",
-]
-exclude = [
-]
-license = "MIT"
-readme = "README.md"
-repository = "https://github.com/matthewdeanmartin/terminaltables"
-homepage = "https://github.com/matthewdeanmartin/terminaltables"
-documentation = "https://github.com/matthewdeanmartin/terminaltables"
-
-[tool.poetry.urls]
-"Bug Tracker" = "https://github.com/matthewdeanmartin/terminaltables/issues"
-"Change Log" = "https://github.com/matthewdeanmartin/terminaltables/blob/main/docs/CHANGES.MD"
-
-[tool.poetry.scripts]
-
-
-[tool.poetry.dependencies]
-# per vermin's estimation
-python = ">=2.6 || >=3.0"
-
-[tool.poetry.dev-dependencies]
-pytest = "==6.0.1"
-
-[build-system]
-requires = ["poetry>=0.12"]
-build-backend = "poetry.masonry.api"
diff --git a/pyproject.toml b/pyproject.toml
index bdcd0ce..49dfb74 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[tool.poetry]
-name = "terminaltables"
-version = "3.1.10"
-description = "Generate simple tables in terminals from a nested list of strings."
+name = "terminaltables3"
+version = "4.0.0"
+description = "Generate simple tables in terminals from a nested list of strings. Fork of terminaltables."
authors = [
"Robpol86 <robpol86@gmail.com>",
"Matthew Martin <matthewdeanmartin@gmail.com>"
@@ -18,49 +18,74 @@ classifiers = [
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Operating System :: POSIX",
- "Programming Language :: Python :: 2.6",
- "Programming Language :: Python :: 2.7",
- "Programming Language :: Python :: 3.3",
- "Programming Language :: Python :: 3.4",
- "Programming Language :: Python :: 3.5",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
"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",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Software Development :: Libraries",
"Topic :: Terminals",
"Topic :: Text Processing :: Markup",
]
packages = [
- { include = "terminaltables" },
+ { include = "terminaltables3" },
]
include = [
- "terminaltables/**/*.py",
+ "terminaltables3/**/*.py",
]
exclude = [
]
license = "MIT"
readme = "README.md"
-repository = "https://github.com/matthewdeanmartin/terminaltables"
-homepage = "https://github.com/matthewdeanmartin/terminaltables"
-documentation = "https://github.com/matthewdeanmartin/terminaltables"
+repository = "https://github.com/matthewdeanmartin/terminaltables3"
+homepage = "https://github.com/matthewdeanmartin/terminaltables3"
+documentation = "https://github.com/matthewdeanmartin/terminaltables3"
[tool.poetry.urls]
-"Bug Tracker" = "https://github.com/matthewdeanmartin/terminaltables/issues"
-"Change Log" = "https://github.com/matthewdeanmartin/terminaltables/blob/master/CHANGELOG.md"
+"Bug Tracker" = "https://github.com/matthewdeanmartin/terminaltables3/issues"
+"Change Log" = "https://github.com/matthewdeanmartin/terminaltables3/blob/master/CHANGELOG.md"
[tool.poetry.scripts]
[tool.poetry.dependencies]
# per vermin's estimation
-python = ">=2.6 || >=3.0"
+python = ">=3.8"
[tool.poetry.dev-dependencies]
-pytest = "==6.0.1"
+# complementary deps
+colorama=">=0.3.7"
+colorclass=">=2.2.0"
+termcolor = "*"
+
+# build deps
+pytest = ">=8.2.1"
+pytest-cov = ">=5.0.0"
+vermin = ">=1.6.0"
+tox = ">=4.15.0"
+isort = ">=5.13.2"
+bandit = ">=1.7.8"
+black = ">=24.4.2"
+pylint = ">=3.2.2"
+ruff = ">=0.4.5"
+mypy = ">=1.10.0"
+pillow = ">=10.3.0"
+pre-commit = ">=2"
+
+# pytest = ">=7.4.3"
+pytest-xdist =">=3.5.0"
+pytest-randomly=">=3.15.0"
+pytest-sugar =">=0.9.7"
+
+# pytest-snapshot = "*"
+# pytest-asyncio = "*"
+pytest-network= "*"
+
+
+# check-wheel-contents = "*" # requires <4
[build-system]
-requires = ["poetry>=0.12"]
-build-backend = "poetry.masonry.api"
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
diff --git a/terminaltables/__init__.py b/terminaltables/__init__.py
deleted file mode 100644
index 6cea813..0000000
--- a/terminaltables/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Generate simple tables in terminals from a nested list of strings.
-
-Use SingleTable or DoubleTable instead of AsciiTable for box-drawing characters.
-
-https://github.com/Robpol86/terminaltables
-https://pypi.python.org/pypi/terminaltables
-"""
-
-from terminaltables.ascii_table import AsciiTable # noqa
-from terminaltables.github_table import GithubFlavoredMarkdownTable # noqa
-from terminaltables.other_tables import DoubleTable # noqa
-from terminaltables.other_tables import SingleTable # noqa
-from terminaltables.other_tables import PorcelainTable # noqa
-
-__author__ = '@Robpol86'
-__license__ = 'MIT'
-__version__ = '3.1.0'
diff --git a/terminaltables/other_tables.py b/terminaltables/other_tables.py
deleted file mode 100644
index 50c0bcd..0000000
--- a/terminaltables/other_tables.py
+++ /dev/null
@@ -1,177 +0,0 @@
-"""Additional simple tables defined here."""
-
-from terminaltables.ascii_table import AsciiTable
-from terminaltables.terminal_io import IS_WINDOWS
-
-
-class UnixTable(AsciiTable):
- """Draw a table using box-drawing characters on Unix platforms. Table borders won't have any gaps between lines.
-
- Similar to the tables shown on PC BIOS boot messages, but not double-lined.
- """
-
- CHAR_F_INNER_HORIZONTAL = '\033(0\x71\033(B'
- CHAR_F_INNER_INTERSECT = '\033(0\x6e\033(B'
- CHAR_F_INNER_VERTICAL = '\033(0\x78\033(B'
- CHAR_F_OUTER_LEFT_INTERSECT = '\033(0\x74\033(B'
- CHAR_F_OUTER_LEFT_VERTICAL = '\033(0\x78\033(B'
- CHAR_F_OUTER_RIGHT_INTERSECT = '\033(0\x75\033(B'
- CHAR_F_OUTER_RIGHT_VERTICAL = '\033(0\x78\033(B'
- CHAR_H_INNER_HORIZONTAL = '\033(0\x71\033(B'
- CHAR_H_INNER_INTERSECT = '\033(0\x6e\033(B'
- CHAR_H_INNER_VERTICAL = '\033(0\x78\033(B'
- CHAR_H_OUTER_LEFT_INTERSECT = '\033(0\x74\033(B'
- CHAR_H_OUTER_LEFT_VERTICAL = '\033(0\x78\033(B'
- CHAR_H_OUTER_RIGHT_INTERSECT = '\033(0\x75\033(B'
- CHAR_H_OUTER_RIGHT_VERTICAL = '\033(0\x78\033(B'
- CHAR_INNER_HORIZONTAL = '\033(0\x71\033(B'
- CHAR_INNER_INTERSECT = '\033(0\x6e\033(B'
- CHAR_INNER_VERTICAL = '\033(0\x78\033(B'
- CHAR_OUTER_BOTTOM_HORIZONTAL = '\033(0\x71\033(B'
- CHAR_OUTER_BOTTOM_INTERSECT = '\033(0\x76\033(B'
- CHAR_OUTER_BOTTOM_LEFT = '\033(0\x6d\033(B'
- CHAR_OUTER_BOTTOM_RIGHT = '\033(0\x6a\033(B'
- CHAR_OUTER_LEFT_INTERSECT = '\033(0\x74\033(B'
- CHAR_OUTER_LEFT_VERTICAL = '\033(0\x78\033(B'
- CHAR_OUTER_RIGHT_INTERSECT = '\033(0\x75\033(B'
- CHAR_OUTER_RIGHT_VERTICAL = '\033(0\x78\033(B'
- CHAR_OUTER_TOP_HORIZONTAL = '\033(0\x71\033(B'
- CHAR_OUTER_TOP_INTERSECT = '\033(0\x77\033(B'
- CHAR_OUTER_TOP_LEFT = '\033(0\x6c\033(B'
- CHAR_OUTER_TOP_RIGHT = '\033(0\x6b\033(B'
-
- @property
- def table(self):
- """Return a large string of the entire table ready to be printed to the terminal."""
- ascii_table = super(UnixTable, self).table
- optimized = ascii_table.replace('\033(B\033(0', '')
- return optimized
-
-
-class WindowsTable(AsciiTable):
- """Draw a table using box-drawing characters on Windows platforms. This uses Code Page 437. Single-line borders.
-
- From: http://en.wikipedia.org/wiki/Code_page_437#Characters
- """
-
- CHAR_F_INNER_HORIZONTAL = b'\xc4'.decode('ibm437')
- CHAR_F_INNER_INTERSECT = b'\xc5'.decode('ibm437')
- CHAR_F_INNER_VERTICAL = b'\xb3'.decode('ibm437')
- CHAR_F_OUTER_LEFT_INTERSECT = b'\xc3'.decode('ibm437')
- CHAR_F_OUTER_LEFT_VERTICAL = b'\xb3'.decode('ibm437')
- CHAR_F_OUTER_RIGHT_INTERSECT = b'\xb4'.decode('ibm437')
- CHAR_F_OUTER_RIGHT_VERTICAL = b'\xb3'.decode('ibm437')
- CHAR_H_INNER_HORIZONTAL = b'\xc4'.decode('ibm437')
- CHAR_H_INNER_INTERSECT = b'\xc5'.decode('ibm437')
- CHAR_H_INNER_VERTICAL = b'\xb3'.decode('ibm437')
- CHAR_H_OUTER_LEFT_INTERSECT = b'\xc3'.decode('ibm437')
- CHAR_H_OUTER_LEFT_VERTICAL = b'\xb3'.decode('ibm437')
- CHAR_H_OUTER_RIGHT_INTERSECT = b'\xb4'.decode('ibm437')
- CHAR_H_OUTER_RIGHT_VERTICAL = b'\xb3'.decode('ibm437')
- CHAR_INNER_HORIZONTAL = b'\xc4'.decode('ibm437')
- CHAR_INNER_INTERSECT = b'\xc5'.decode('ibm437')
- CHAR_INNER_VERTICAL = b'\xb3'.decode('ibm437')
- CHAR_OUTER_BOTTOM_HORIZONTAL = b'\xc4'.decode('ibm437')
- CHAR_OUTER_BOTTOM_INTERSECT = b'\xc1'.decode('ibm437')
- CHAR_OUTER_BOTTOM_LEFT = b'\xc0'.decode('ibm437')
- CHAR_OUTER_BOTTOM_RIGHT = b'\xd9'.decode('ibm437')
- CHAR_OUTER_LEFT_INTERSECT = b'\xc3'.decode('ibm437')
- CHAR_OUTER_LEFT_VERTICAL = b'\xb3'.decode('ibm437')
- CHAR_OUTER_RIGHT_INTERSECT = b'\xb4'.decode('ibm437')
- CHAR_OUTER_RIGHT_VERTICAL = b'\xb3'.decode('ibm437')
- CHAR_OUTER_TOP_HORIZONTAL = b'\xc4'.decode('ibm437')
- CHAR_OUTER_TOP_INTERSECT = b'\xc2'.decode('ibm437')
- CHAR_OUTER_TOP_LEFT = b'\xda'.decode('ibm437')
- CHAR_OUTER_TOP_RIGHT = b'\xbf'.decode('ibm437')
-
-
-class WindowsTableDouble(AsciiTable):
- """Draw a table using box-drawing characters on Windows platforms. This uses Code Page 437. Double-line borders."""
-
- CHAR_F_INNER_HORIZONTAL = b'\xcd'.decode('ibm437')
- CHAR_F_INNER_INTERSECT = b'\xce'.decode('ibm437')
- CHAR_F_INNER_VERTICAL = b'\xba'.decode('ibm437')
- CHAR_F_OUTER_LEFT_INTERSECT = b'\xcc'.decode('ibm437')
- CHAR_F_OUTER_LEFT_VERTICAL = b'\xba'.decode('ibm437')
- CHAR_F_OUTER_RIGHT_INTERSECT = b'\xb9'.decode('ibm437')
- CHAR_F_OUTER_RIGHT_VERTICAL = b'\xba'.decode('ibm437')
- CHAR_H_INNER_HORIZONTAL = b'\xcd'.decode('ibm437')
- CHAR_H_INNER_INTERSECT = b'\xce'.decode('ibm437')
- CHAR_H_INNER_VERTICAL = b'\xba'.decode('ibm437')
- CHAR_H_OUTER_LEFT_INTERSECT = b'\xcc'.decode('ibm437')
- CHAR_H_OUTER_LEFT_VERTICAL = b'\xba'.decode('ibm437')
- CHAR_H_OUTER_RIGHT_INTERSECT = b'\xb9'.decode('ibm437')
- CHAR_H_OUTER_RIGHT_VERTICAL = b'\xba'.decode('ibm437')
- CHAR_INNER_HORIZONTAL = b'\xcd'.decode('ibm437')
- CHAR_INNER_INTERSECT = b'\xce'.decode('ibm437')
- CHAR_INNER_VERTICAL = b'\xba'.decode('ibm437')
- CHAR_OUTER_BOTTOM_HORIZONTAL = b'\xcd'.decode('ibm437')
- CHAR_OUTER_BOTTOM_INTERSECT = b'\xca'.decode('ibm437')
- CHAR_OUTER_BOTTOM_LEFT = b'\xc8'.decode('ibm437')
- CHAR_OUTER_BOTTOM_RIGHT = b'\xbc'.decode('ibm437')
- CHAR_OUTER_LEFT_INTERSECT = b'\xcc'.decode('ibm437')
- CHAR_OUTER_LEFT_VERTICAL = b'\xba'.decode('ibm437')
- CHAR_OUTER_RIGHT_INTERSECT = b'\xb9'.decode('ibm437')
- CHAR_OUTER_RIGHT_VERTICAL = b'\xba'.decode('ibm437')
- CHAR_OUTER_TOP_HORIZONTAL = b'\xcd'.decode('ibm437')
- CHAR_OUTER_TOP_INTERSECT = b'\xcb'.decode('ibm437')
- CHAR_OUTER_TOP_LEFT = b'\xc9'.decode('ibm437')
- CHAR_OUTER_TOP_RIGHT = b'\xbb'.decode('ibm437')
-
-
-class SingleTable(WindowsTable if IS_WINDOWS else UnixTable):
- """Cross-platform table with single-line box-drawing characters.
-
- :ivar iter table_data: List (empty or list of lists of strings) representing the table.
- :ivar str title: Optional title to show within the top border of the table.
- :ivar bool inner_column_border: Separates columns.
- :ivar bool inner_footing_row_border: Show a border before the last row.
- :ivar bool inner_heading_row_border: Show a border after the first row.
- :ivar bool inner_row_border: Show a border in between every row.
- :ivar bool outer_border: Show the top, left, right, and bottom border.
- :ivar dict justify_columns: Horizontal justification. Keys are column indexes (int). Values are right/left/center.
- :ivar int padding_left: Number of spaces to pad on the left side of every cell.
- :ivar int padding_right: Number of spaces to pad on the right side of every cell.
- """
-
- pass
-
-
-class DoubleTable(WindowsTableDouble):
- """Cross-platform table with box-drawing characters. On Windows it's double borders, on Linux/OSX it's unicode.
-
- :ivar iter table_data: List (empty or list of lists of strings) representing the table.
- :ivar str title: Optional title to show within the top border of the table.
- :ivar bool inner_column_border: Separates columns.
- :ivar bool inner_footing_row_border: Show a border before the last row.
- :ivar bool inner_heading_row_border: Show a border after the first row.
- :ivar bool inner_row_border: Show a border in between every row.
- :ivar bool outer_border: Show the top, left, right, and bottom border.
- :ivar dict justify_columns: Horizontal justification. Keys are column indexes (int). Values are right/left/center.
- :ivar int padding_left: Number of spaces to pad on the left side of every cell.
- :ivar int padding_right: Number of spaces to pad on the right side of every cell.
- """
-
- pass
-
-
-class PorcelainTable(AsciiTable):
- """An AsciiTable stripped to a minimum.
-
- Meant to be machine passable and roughly follow format set by git --porcelain option (hence the name).
-
- :ivar iter table_data: List (empty or list of lists of strings) representing the table.
- """
-
- def __init__(self, table_data):
- """Constructor.
-
- :param iter table_data: List (empty or list of lists of strings) representing the table.
- """
- # Porcelain table won't support title since it has no outer birders.
- super(PorcelainTable, self).__init__(table_data)
-
- # Removes outer border, and inner footing and header row borders.
- self.inner_footing_row_border = False
- self.inner_heading_row_border = False
- self.outer_border = False
diff --git a/terminaltables3/__init__.py b/terminaltables3/__init__.py
new file mode 100644
index 0000000..f0b4858
--- /dev/null
+++ b/terminaltables3/__init__.py
@@ -0,0 +1,17 @@
+"""Generate simple tables in terminals from a nested list of strings.
+
+Use SingleTable or DoubleTable instead of AsciiTable for box-drawing characters.
+
+https://github.com/Robpol86/terminaltables3
+https://pypi.python.org/pypi/terminaltables3
+"""
+
+from terminaltables3.ascii_table import AsciiTable # noqa
+from terminaltables3.github_table import GithubFlavoredMarkdownTable # noqa
+from terminaltables3.other_tables import DoubleTable # noqa
+from terminaltables3.other_tables import PorcelainTable # noqa
+from terminaltables3.other_tables import SingleTable # noqa
+
+__author__ = "@Robpol86"
+__license__ = "MIT"
+__version__ = "3.1.0"
diff --git a/terminaltables/ascii_table.py b/terminaltables3/ascii_table.py
index 3623918..4630f74 100644
--- a/terminaltables/ascii_table.py
+++ b/terminaltables3/ascii_table.py
@@ -1,8 +1,12 @@
"""AsciiTable is the main table class. To be inherited by other tables. Define convenience methods here."""
-from terminaltables.base_table import BaseTable
-from terminaltables.terminal_io import terminal_size
-from terminaltables.width_and_alignment import column_max_width, max_dimensions, table_width
+from terminaltables3.base_table import BaseTable
+from terminaltables3.terminal_io import terminal_size
+from terminaltables3.width_and_alignment import (
+ column_max_width,
+ max_dimensions,
+ table_width,
+)
class AsciiTable(BaseTable):
@@ -20,7 +24,7 @@ class AsciiTable(BaseTable):
:ivar int padding_right: Number of spaces to pad on the right side of every cell.
"""
- def column_max_width(self, column_number):
+ def column_max_width(self, column_number: int) -> int:
"""Return the maximum width of a column based on the current terminal width.
:param int column_number: The column number to query.
@@ -32,24 +36,28 @@ class AsciiTable(BaseTable):
outer_border = 2 if self.outer_border else 0
inner_border = 1 if self.inner_column_border else 0
padding = self.padding_left + self.padding_right
- return column_max_width(inner_widths, column_number, outer_border, inner_border, padding)
+ return column_max_width(
+ inner_widths, column_number, outer_border, inner_border, padding
+ )
@property
- def column_widths(self):
+ def column_widths(self) -> list[int]:
"""Return a list of integers representing the widths of each table column without padding."""
if not self.table_data:
- return list()
+ return []
return max_dimensions(self.table_data)[0]
@property
- def ok(self): # Too late to change API. # pylint: disable=invalid-name
+ def ok(self) -> bool: # Too late to change API. # pylint: disable=invalid-name
"""Return True if the table fits within the terminal width, False if the table breaks."""
return self.table_width <= terminal_size()[0]
@property
- def table_width(self):
+ def table_width(self) -> int:
"""Return the width of the table including padding and borders."""
- outer_widths = max_dimensions(self.table_data, self.padding_left, self.padding_right)[2]
+ outer_widths = max_dimensions(
+ self.table_data, self.padding_left, self.padding_right
+ )[2]
outer_border = 2 if self.outer_border else 0
inner_border = 1 if self.inner_column_border else 0
return table_width(outer_widths, outer_border, inner_border)
diff --git a/terminaltables/base_table.py b/terminaltables3/base_table.py
index 281d5a3..4c375af 100644
--- a/terminaltables/base_table.py
+++ b/terminaltables3/base_table.py
@@ -1,10 +1,12 @@
"""Base table class. Define just the bare minimum to build tables."""
-from terminaltables.build import build_border, build_row, flatten
-from terminaltables.width_and_alignment import align_and_pad_cell, max_dimensions
+from typing import Generator, Optional, Sequence, Tuple
+from terminaltables3.build import build_border, build_row, flatten
+from terminaltables3.width_and_alignment import align_and_pad_cell, max_dimensions
-class BaseTable(object):
+
+class BaseTable:
"""Base table class.
:ivar iter table_data: List (empty or list of lists of strings) representing the table.
@@ -19,37 +21,39 @@ class BaseTable(object):
:ivar int padding_right: Number of spaces to pad on the right side of every cell.
"""
- CHAR_F_INNER_HORIZONTAL = '-'
- CHAR_F_INNER_INTERSECT = '+'
- CHAR_F_INNER_VERTICAL = '|'
- CHAR_F_OUTER_LEFT_INTERSECT = '+'
- CHAR_F_OUTER_LEFT_VERTICAL = '|'
- CHAR_F_OUTER_RIGHT_INTERSECT = '+'
- CHAR_F_OUTER_RIGHT_VERTICAL = '|'
- CHAR_H_INNER_HORIZONTAL = '-'
- CHAR_H_INNER_INTERSECT = '+'
- CHAR_H_INNER_VERTICAL = '|'
- CHAR_H_OUTER_LEFT_INTERSECT = '+'
- CHAR_H_OUTER_LEFT_VERTICAL = '|'
- CHAR_H_OUTER_RIGHT_INTERSECT = '+'
- CHAR_H_OUTER_RIGHT_VERTICAL = '|'
- CHAR_INNER_HORIZONTAL = '-'
- CHAR_INNER_INTERSECT = '+'
- CHAR_INNER_VERTICAL = '|'
- CHAR_OUTER_BOTTOM_HORIZONTAL = '-'
- CHAR_OUTER_BOTTOM_INTERSECT = '+'
- CHAR_OUTER_BOTTOM_LEFT = '+'
- CHAR_OUTER_BOTTOM_RIGHT = '+'
- CHAR_OUTER_LEFT_INTERSECT = '+'
- CHAR_OUTER_LEFT_VERTICAL = '|'
- CHAR_OUTER_RIGHT_INTERSECT = '+'
- CHAR_OUTER_RIGHT_VERTICAL = '|'
- CHAR_OUTER_TOP_HORIZONTAL = '-'
- CHAR_OUTER_TOP_INTERSECT = '+'
- CHAR_OUTER_TOP_LEFT = '+'
- CHAR_OUTER_TOP_RIGHT = '+'
-
- def __init__(self, table_data, title=None):
+ CHAR_F_INNER_HORIZONTAL = "-"
+ CHAR_F_INNER_INTERSECT = "+"
+ CHAR_F_INNER_VERTICAL = "|"
+ CHAR_F_OUTER_LEFT_INTERSECT = "+"
+ CHAR_F_OUTER_LEFT_VERTICAL = "|"
+ CHAR_F_OUTER_RIGHT_INTERSECT = "+"
+ CHAR_F_OUTER_RIGHT_VERTICAL = "|"
+ CHAR_H_INNER_HORIZONTAL = "-"
+ CHAR_H_INNER_INTERSECT = "+"
+ CHAR_H_INNER_VERTICAL = "|"
+ CHAR_H_OUTER_LEFT_INTERSECT = "+"
+ CHAR_H_OUTER_LEFT_VERTICAL = "|"
+ CHAR_H_OUTER_RIGHT_INTERSECT = "+"
+ CHAR_H_OUTER_RIGHT_VERTICAL = "|"
+ CHAR_INNER_HORIZONTAL = "-"
+ CHAR_INNER_INTERSECT = "+"
+ CHAR_INNER_VERTICAL = "|"
+ CHAR_OUTER_BOTTOM_HORIZONTAL = "-"
+ CHAR_OUTER_BOTTOM_INTERSECT = "+"
+ CHAR_OUTER_BOTTOM_LEFT = "+"
+ CHAR_OUTER_BOTTOM_RIGHT = "+"
+ CHAR_OUTER_LEFT_INTERSECT = "+"
+ CHAR_OUTER_LEFT_VERTICAL = "|"
+ CHAR_OUTER_RIGHT_INTERSECT = "+"
+ CHAR_OUTER_RIGHT_VERTICAL = "|"
+ CHAR_OUTER_TOP_HORIZONTAL = "-"
+ CHAR_OUTER_TOP_INTERSECT = "+"
+ CHAR_OUTER_TOP_LEFT = "+"
+ CHAR_OUTER_TOP_RIGHT = "+"
+
+ def __init__(
+ self, table_data: Sequence[Sequence[str]], title: Optional[str] = None
+ ):
"""Constructor.
:param iter table_data: List (empty or list of lists of strings) representing the table.
@@ -64,11 +68,13 @@ class BaseTable(object):
self.inner_row_border = False
self.outer_border = True
- self.justify_columns = dict() # {0: 'right', 1: 'left', 2: 'center'}
+ self.justify_columns = {} # {0: 'right', 1: 'left', 2: 'center'}
self.padding_left = 1
self.padding_right = 1
- def horizontal_border(self, style, outer_widths):
+ def horizontal_border(
+ self, style: str, outer_widths: Sequence[int]
+ ) -> Tuple[str, ...]:
"""Build any kind of horizontal border for the table.
:param str style: Type of border to return.
@@ -77,39 +83,45 @@ class BaseTable(object):
:return: Prepared border as a tuple of strings.
:rtype: tuple
"""
- if style == 'top':
+ if style == "top":
horizontal = self.CHAR_OUTER_TOP_HORIZONTAL
left = self.CHAR_OUTER_TOP_LEFT
- intersect = self.CHAR_OUTER_TOP_INTERSECT if self.inner_column_border else ''
+ intersect = (
+ self.CHAR_OUTER_TOP_INTERSECT if self.inner_column_border else ""
+ )
right = self.CHAR_OUTER_TOP_RIGHT
title = self.title
- elif style == 'bottom':
+ elif style == "bottom":
horizontal = self.CHAR_OUTER_BOTTOM_HORIZONTAL
left = self.CHAR_OUTER_BOTTOM_LEFT
- intersect = self.CHAR_OUTER_BOTTOM_INTERSECT if self.inner_column_border else ''
+ intersect = (
+ self.CHAR_OUTER_BOTTOM_INTERSECT if self.inner_column_border else ""
+ )
right = self.CHAR_OUTER_BOTTOM_RIGHT
title = None
- elif style == 'heading':
+ elif style == "heading":
horizontal = self.CHAR_H_INNER_HORIZONTAL
- left = self.CHAR_H_OUTER_LEFT_INTERSECT if self.outer_border else ''
- intersect = self.CHAR_H_INNER_INTERSECT if self.inner_column_border else ''
- right = self.CHAR_H_OUTER_RIGHT_INTERSECT if self.outer_border else ''
+ left = self.CHAR_H_OUTER_LEFT_INTERSECT if self.outer_border else ""
+ intersect = self.CHAR_H_INNER_INTERSECT if self.inner_column_border else ""
+ right = self.CHAR_H_OUTER_RIGHT_INTERSECT if self.outer_border else ""
title = None
- elif style == 'footing':
+ elif style == "footing":
horizontal = self.CHAR_F_INNER_HORIZONTAL
- left = self.CHAR_F_OUTER_LEFT_INTERSECT if self.outer_border else ''
- intersect = self.CHAR_F_INNER_INTERSECT if self.inner_column_border else ''
- right = self.CHAR_F_OUTER_RIGHT_INTERSECT if self.outer_border else ''
+ left = self.CHAR_F_OUTER_LEFT_INTERSECT if self.outer_border else ""
+ intersect = self.CHAR_F_INNER_INTERSECT if self.inner_column_border else ""
+ right = self.CHAR_F_OUTER_RIGHT_INTERSECT if self.outer_border else ""
title = None
else:
horizontal = self.CHAR_INNER_HORIZONTAL
- left = self.CHAR_OUTER_LEFT_INTERSECT if self.outer_border else ''
- intersect = self.CHAR_INNER_INTERSECT if self.inner_column_border else ''
- right = self.CHAR_OUTER_RIGHT_INTERSECT if self.outer_border else ''
+ left = self.CHAR_OUTER_LEFT_INTERSECT if self.outer_border else ""
+ intersect = self.CHAR_INNER_INTERSECT if self.inner_column_border else ""
+ right = self.CHAR_OUTER_RIGHT_INTERSECT if self.outer_border else ""
title = None
return build_border(outer_widths, horizontal, left, intersect, right, title)
- def gen_row_lines(self, row, style, inner_widths, height):
+ def gen_row_lines(
+ self, row: Sequence[str], style: str, inner_widths: Sequence[int], height: int
+ ) -> Generator[Tuple[str, ...], None, None]:
r"""Combine cells in row and group them into lines with vertical borders.
Caller is expected to pass yielded lines to ''.join() to combine them into a printable line. Caller must append
@@ -137,38 +149,44 @@ class BaseTable(object):
:return: Yields lines split into components in a list. Caller must ''.join() line.
"""
- cells_in_row = list()
+ cells_in_row = []
# Resize row if it doesn't have enough cells.
if len(row) != len(inner_widths):
- row = row + [''] * (len(inner_widths) - len(row))
+ row = row + [""] * (len(inner_widths) - len(row))
# Pad and align each cell. Split each cell into lines to support multi-line cells.
for i, cell in enumerate(row):
align = (self.justify_columns.get(i),)
inner_dimensions = (inner_widths[i], height)
padding = (self.padding_left, self.padding_right, 0, 0)
- cells_in_row.append(align_and_pad_cell(cell, align, inner_dimensions, padding))
+ cells_in_row.append(
+ align_and_pad_cell(cell, align, inner_dimensions, padding)
+ )
# Determine border characters.
- if style == 'heading':
- left = self.CHAR_H_OUTER_LEFT_VERTICAL if self.outer_border else ''
- center = self.CHAR_H_INNER_VERTICAL if self.inner_column_border else ''
- right = self.CHAR_H_OUTER_RIGHT_VERTICAL if self.outer_border else ''
- elif style == 'footing':
- left = self.CHAR_F_OUTER_LEFT_VERTICAL if self.outer_border else ''
- center = self.CHAR_F_INNER_VERTICAL if self.inner_column_border else ''
- right = self.CHAR_F_OUTER_RIGHT_VERTICAL if self.outer_border else ''
+ if style == "heading":
+ left = self.CHAR_H_OUTER_LEFT_VERTICAL if self.outer_border else ""
+ center = self.CHAR_H_INNER_VERTICAL if self.inner_column_border else ""
+ right = self.CHAR_H_OUTER_RIGHT_VERTICAL if self.outer_border else ""
+ elif style == "footing":
+ left = self.CHAR_F_OUTER_LEFT_VERTICAL if self.outer_border else ""
+ center = self.CHAR_F_INNER_VERTICAL if self.inner_column_border else ""
+ right = self.CHAR_F_OUTER_RIGHT_VERTICAL if self.outer_border else ""
else:
- left = self.CHAR_OUTER_LEFT_VERTICAL if self.outer_border else ''
- center = self.CHAR_INNER_VERTICAL if self.inner_column_border else ''
- right = self.CHAR_OUTER_RIGHT_VERTICAL if self.outer_border else ''
+ left = self.CHAR_OUTER_LEFT_VERTICAL if self.outer_border else ""
+ center = self.CHAR_INNER_VERTICAL if self.inner_column_border else ""
+ right = self.CHAR_OUTER_RIGHT_VERTICAL if self.outer_border else ""
# Yield each line.
- for line in build_row(cells_in_row, left, center, right):
- yield line
-
- def gen_table(self, inner_widths, inner_heights, outer_widths):
+ yield from build_row(cells_in_row, left, center, right)
+
+ def gen_table(
+ self,
+ inner_widths: Sequence[int],
+ inner_heights: Sequence[int],
+ outer_widths: Sequence[int],
+ ) -> Generator[Tuple[str, ...], None, None]:
"""Combine everything and yield every line of the entire table with borders.
:param iter inner_widths: List of widths (no padding) for each column.
@@ -178,7 +196,7 @@ class BaseTable(object):
"""
# Yield top border.
if self.outer_border:
- yield self.horizontal_border('top', outer_widths)
+ yield self.horizontal_border("top", outer_widths)
# Yield table body.
row_count = len(self.table_data)
@@ -186,32 +204,33 @@ class BaseTable(object):
for i, row in enumerate(self.table_data):
# Yield the row line by line (e.g. multi-line rows).
if self.inner_heading_row_border and i == 0:
- style = 'heading'
+ style = "heading"
elif self.inner_footing_row_border and i == last_row_index:
- style = 'footing'
+ style = "footing"
else:
- style = 'row'
- for line in self.gen_row_lines(row, style, inner_widths, inner_heights[i]):
- yield line
+ style = "row"
+ yield from self.gen_row_lines(row, style, inner_widths, inner_heights[i])
# If this is the last row then break. No separator needed.
if i == last_row_index:
break
# Yield heading separator.
if self.inner_heading_row_border and i == 0:
- yield self.horizontal_border('heading', outer_widths)
+ yield self.horizontal_border("heading", outer_widths)
# Yield footing separator.
elif self.inner_footing_row_border and i == before_last_row_index:
- yield self.horizontal_border('footing', outer_widths)
+ yield self.horizontal_border("footing", outer_widths)
# Yield row separator.
elif self.inner_row_border:
- yield self.horizontal_border('row', outer_widths)
+ yield self.horizontal_border("row", outer_widths)
# Yield bottom border.
if self.outer_border:
- yield self.horizontal_border('bottom', outer_widths)
+ yield self.horizontal_border("bottom", outer_widths)
@property
- def table(self):
+ def table(self) -> str:
"""Return a large string of the entire table ready to be printed to the terminal."""
- dimensions = max_dimensions(self.table_data, self.padding_left, self.padding_right)[:3]
+ dimensions = max_dimensions(
+ self.table_data, self.padding_left, self.padding_right
+ )[:3]
return flatten(self.gen_table(*dimensions))
diff --git a/terminaltables/build.py b/terminaltables3/build.py
index 6b23b2f..c01349f 100644
--- a/terminaltables/build.py
+++ b/terminaltables3/build.py
@@ -1,9 +1,18 @@
"""Combine cells into rows."""
-from terminaltables.width_and_alignment import visible_width
+from typing import Generator, Iterator, Optional, Sequence, Union
+from terminaltables3.width_and_alignment import visible_width
-def combine(line, left, intersect, right):
+
+def combine(
+ line: Union[
+ Generator[Union[int, str], None, None], Iterator[Optional[Union[int, str]]]
+ ],
+ left: str,
+ intersect: Optional[str],
+ right: str,
+) -> Generator[int, None, None]:
"""Zip borders between items in `line`.
e.g. ('l', '1', 'c', '2', 'c', '3', 'r')
@@ -41,15 +50,21 @@ def combine(line, left, intersect, right):
yield intersect
item = peek
else:
- for i in line:
- yield i
+ yield from line
- # Yield right border.
+ # Yield right border.
if right:
yield right
-def build_border(outer_widths, horizontal, left, intersect, right, title=None):
+def build_border(
+ outer_widths: Sequence[int],
+ horizontal: str,
+ left: str,
+ intersect: str,
+ right: str,
+ title: Optional[str] = None,
+):
"""Build the top/bottom/middle row. Optionally embed the table title within the border.
Title is hidden if it doesn't fit between the left/right characters/edges.
@@ -86,9 +101,13 @@ def build_border(outer_widths, horizontal, left, intersect, right, title=None):
# Handle title fitting in the first column.
if length == outer_widths[0]:
- return combine([title] + [horizontal * c for c in outer_widths[1:]], left, intersect, right)
+ return combine(
+ [title] + [horizontal * c for c in outer_widths[1:]], left, intersect, right
+ )
if length < outer_widths[0]:
- columns = [title + horizontal * (outer_widths[0] - length)] + [horizontal * c for c in outer_widths[1:]]
+ columns = [title + horizontal * (outer_widths[0] - length)] + [
+ horizontal * c for c in outer_widths[1:]
+ ]
return combine(columns, left, intersect, right)
# Handle wide titles/narrow columns.
@@ -96,7 +115,9 @@ def build_border(outer_widths, horizontal, left, intersect, right, title=None):
for width in combine(outer_widths, None, bool(intersect), None):
# If title is taken care of.
if length < 1:
- columns_and_intersects.append(intersect if width is True else horizontal * width)
+ columns_and_intersects.append(
+ intersect if width is True else horizontal * width
+ )
# If title's last character overrides an intersect character.
elif width is True and length == 1:
length = 0
@@ -105,7 +126,9 @@ def build_border(outer_widths, horizontal, left, intersect, right, title=None):
length -= 1
# If title's last character is within a column.
elif width >= length:
- columns_and_intersects[0] += horizontal * (width - length) # Append horizontal chars to title.
+ columns_and_intersects[0] += horizontal * (
+ width - length
+ ) # Append horizontal chars to title.
length = 0
# If remainder of title won't fit in a column.
else:
@@ -148,4 +171,4 @@ def flatten(table):
:return: Joined rows/cells.
:rtype: str
"""
- return '\n'.join(''.join(r) for r in table)
+ return "\n".join("".join(r) for r in table)
diff --git a/terminaltables/github_table.py b/terminaltables3/github_table.py
index 7eb1be7..a00d189 100644
--- a/terminaltables/github_table.py
+++ b/terminaltables3/github_table.py
@@ -1,7 +1,9 @@
"""GithubFlavoredMarkdownTable class."""
-from terminaltables.ascii_table import AsciiTable
-from terminaltables.build import combine
+from typing import Sequence
+
+from terminaltables3.ascii_table import AsciiTable
+from terminaltables3.build import combine
class GithubFlavoredMarkdownTable(AsciiTable):
@@ -13,13 +15,13 @@ class GithubFlavoredMarkdownTable(AsciiTable):
:ivar dict justify_columns: Horizontal justification. Keys are column indexes (int). Values are right/left/center.
"""
- def __init__(self, table_data):
+ def __init__(self, table_data: Sequence[Sequence[str]]):
"""Constructor.
:param iter table_data: List (empty or list of lists of strings) representing the table.
"""
# Github flavored markdown table won't support title.
- super(GithubFlavoredMarkdownTable, self).__init__(table_data)
+ super().__init__(table_data)
def horizontal_border(self, _, outer_widths):
"""Handle the GitHub heading border.
@@ -38,16 +40,18 @@ class GithubFlavoredMarkdownTable(AsciiTable):
intersect = self.CHAR_INNER_VERTICAL
right = self.CHAR_OUTER_RIGHT_VERTICAL
- columns = list()
+ columns = []
for i, width in enumerate(outer_widths):
justify = self.justify_columns.get(i)
- width = max(3, width) # Width should be at least 3 so justification can be applied.
- if justify == 'left':
- columns.append(':' + horizontal * (width - 1))
- elif justify == 'right':
- columns.append(horizontal * (width - 1) + ':')
- elif justify == 'center':
- columns.append(':' + horizontal * (width - 2) + ':')
+ width = max(
+ 3, width
+ ) # Width should be at least 3 so justification can be applied.
+ if justify == "left":
+ columns.append(":" + horizontal * (width - 1))
+ elif justify == "right":
+ columns.append(horizontal * (width - 1) + ":")
+ elif justify == "center":
+ columns.append(":" + horizontal * (width - 2) + ":")
else:
columns.append(horizontal * width)
@@ -63,8 +67,7 @@ class GithubFlavoredMarkdownTable(AsciiTable):
"""
for i, row in enumerate(self.table_data):
# Yield the row line by line (e.g. multi-line rows).
- for line in self.gen_row_lines(row, 'row', inner_widths, inner_heights[i]):
- yield line
+ yield from self.gen_row_lines(row, "row", inner_widths, inner_heights[i])
# Yield heading separator.
if i == 0:
yield self.horizontal_border(None, outer_widths)
diff --git a/terminaltables3/other_tables.py b/terminaltables3/other_tables.py
new file mode 100644
index 0000000..9fb1b05
--- /dev/null
+++ b/terminaltables3/other_tables.py
@@ -0,0 +1,173 @@
+"""Additional simple tables defined here."""
+
+from terminaltables3.ascii_table import AsciiTable
+from terminaltables3.terminal_io import IS_WINDOWS
+
+
+class UnixTable(AsciiTable):
+ """Draw a table using box-drawing characters on Unix platforms. Table borders won't have any gaps between lines.
+
+ Similar to the tables shown on PC BIOS boot messages, but not double-lined.
+ """
+
+ CHAR_F_INNER_HORIZONTAL = "\033(0\x71\033(B"
+ CHAR_F_INNER_INTERSECT = "\033(0\x6e\033(B"
+ CHAR_F_INNER_VERTICAL = "\033(0\x78\033(B"
+ CHAR_F_OUTER_LEFT_INTERSECT = "\033(0\x74\033(B"
+ CHAR_F_OUTER_LEFT_VERTICAL = "\033(0\x78\033(B"
+ CHAR_F_OUTER_RIGHT_INTERSECT = "\033(0\x75\033(B"
+ CHAR_F_OUTER_RIGHT_VERTICAL = "\033(0\x78\033(B"
+ CHAR_H_INNER_HORIZONTAL = "\033(0\x71\033(B"
+ CHAR_H_INNER_INTERSECT = "\033(0\x6e\033(B"
+ CHAR_H_INNER_VERTICAL = "\033(0\x78\033(B"
+ CHAR_H_OUTER_LEFT_INTERSECT = "\033(0\x74\033(B"
+ CHAR_H_OUTER_LEFT_VERTICAL = "\033(0\x78\033(B"
+ CHAR_H_OUTER_RIGHT_INTERSECT = "\033(0\x75\033(B"
+ CHAR_H_OUTER_RIGHT_VERTICAL = "\033(0\x78\033(B"
+ CHAR_INNER_HORIZONTAL = "\033(0\x71\033(B"
+ CHAR_INNER_INTERSECT = "\033(0\x6e\033(B"
+ CHAR_INNER_VERTICAL = "\033(0\x78\033(B"
+ CHAR_OUTER_BOTTOM_HORIZONTAL = "\033(0\x71\033(B"
+ CHAR_OUTER_BOTTOM_INTERSECT = "\033(0\x76\033(B"
+ CHAR_OUTER_BOTTOM_LEFT = "\033(0\x6d\033(B"
+ CHAR_OUTER_BOTTOM_RIGHT = "\033(0\x6a\033(B"
+ CHAR_OUTER_LEFT_INTERSECT = "\033(0\x74\033(B"
+ CHAR_OUTER_LEFT_VERTICAL = "\033(0\x78\033(B"
+ CHAR_OUTER_RIGHT_INTERSECT = "\033(0\x75\033(B"
+ CHAR_OUTER_RIGHT_VERTICAL = "\033(0\x78\033(B"
+ CHAR_OUTER_TOP_HORIZONTAL = "\033(0\x71\033(B"
+ CHAR_OUTER_TOP_INTERSECT = "\033(0\x77\033(B"
+ CHAR_OUTER_TOP_LEFT = "\033(0\x6c\033(B"
+ CHAR_OUTER_TOP_RIGHT = "\033(0\x6b\033(B"
+
+ @property
+ def table(self):
+ """Return a large string of the entire table ready to be printed to the terminal."""
+ ascii_table = super().table
+ optimized = ascii_table.replace("\033(B\033(0", "")
+ return optimized
+
+
+class WindowsTable(AsciiTable):
+ """Draw a table using box-drawing characters on Windows platforms. This uses Code Page 437. Single-line borders.
+
+ From: http://en.wikipedia.org/wiki/Code_page_437#Characters
+ """
+
+ CHAR_F_INNER_HORIZONTAL = b"\xc4".decode("ibm437")
+ CHAR_F_INNER_INTERSECT = b"\xc5".decode("ibm437")
+ CHAR_F_INNER_VERTICAL = b"\xb3".decode("ibm437")
+ CHAR_F_OUTER_LEFT_INTERSECT = b"\xc3".decode("ibm437")
+ CHAR_F_OUTER_LEFT_VERTICAL = b"\xb3".decode("ibm437")
+ CHAR_F_OUTER_RIGHT_INTERSECT = b"\xb4".decode("ibm437")
+ CHAR_F_OUTER_RIGHT_VERTICAL = b"\xb3".decode("ibm437")
+ CHAR_H_INNER_HORIZONTAL = b"\xc4".decode("ibm437")
+ CHAR_H_INNER_INTERSECT = b"\xc5".decode("ibm437")
+ CHAR_H_INNER_VERTICAL = b"\xb3".decode("ibm437")
+ CHAR_H_OUTER_LEFT_INTERSECT = b"\xc3".decode("ibm437")
+ CHAR_H_OUTER_LEFT_VERTICAL = b"\xb3".decode("ibm437")
+ CHAR_H_OUTER_RIGHT_INTERSECT = b"\xb4".decode("ibm437")
+ CHAR_H_OUTER_RIGHT_VERTICAL = b"\xb3".decode("ibm437")
+ CHAR_INNER_HORIZONTAL = b"\xc4".decode("ibm437")
+ CHAR_INNER_INTERSECT = b"\xc5".decode("ibm437")
+ CHAR_INNER_VERTICAL = b"\xb3".decode("ibm437")
+ CHAR_OUTER_BOTTOM_HORIZONTAL = b"\xc4".decode("ibm437")
+ CHAR_OUTER_BOTTOM_INTERSECT = b"\xc1".decode("ibm437")
+ CHAR_OUTER_BOTTOM_LEFT = b"\xc0".decode("ibm437")
+ CHAR_OUTER_BOTTOM_RIGHT = b"\xd9".decode("ibm437")
+ CHAR_OUTER_LEFT_INTERSECT = b"\xc3".decode("ibm437")
+ CHAR_OUTER_LEFT_VERTICAL = b"\xb3".decode("ibm437")
+ CHAR_OUTER_RIGHT_INTERSECT = b"\xb4".decode("ibm437")
+ CHAR_OUTER_RIGHT_VERTICAL = b"\xb3".decode("ibm437")
+ CHAR_OUTER_TOP_HORIZONTAL = b"\xc4".decode("ibm437")
+ CHAR_OUTER_TOP_INTERSECT = b"\xc2".decode("ibm437")
+ CHAR_OUTER_TOP_LEFT = b"\xda".decode("ibm437")
+ CHAR_OUTER_TOP_RIGHT = b"\xbf".decode("ibm437")
+
+
+class WindowsTableDouble(AsciiTable):
+ """Draw a table using box-drawing characters on Windows platforms. This uses Code Page 437. Double-line borders."""
+
+ CHAR_F_INNER_HORIZONTAL = b"\xcd".decode("ibm437")
+ CHAR_F_INNER_INTERSECT = b"\xce".decode("ibm437")
+ CHAR_F_INNER_VERTICAL = b"\xba".decode("ibm437")
+ CHAR_F_OUTER_LEFT_INTERSECT = b"\xcc".decode("ibm437")
+ CHAR_F_OUTER_LEFT_VERTICAL = b"\xba".decode("ibm437")
+ CHAR_F_OUTER_RIGHT_INTERSECT = b"\xb9".decode("ibm437")
+ CHAR_F_OUTER_RIGHT_VERTICAL = b"\xba".decode("ibm437")
+ CHAR_H_INNER_HORIZONTAL = b"\xcd".decode("ibm437")
+ CHAR_H_INNER_INTERSECT = b"\xce".decode("ibm437")
+ CHAR_H_INNER_VERTICAL = b"\xba".decode("ibm437")
+ CHAR_H_OUTER_LEFT_INTERSECT = b"\xcc".decode("ibm437")
+ CHAR_H_OUTER_LEFT_VERTICAL = b"\xba".decode("ibm437")
+ CHAR_H_OUTER_RIGHT_INTERSECT = b"\xb9".decode("ibm437")
+ CHAR_H_OUTER_RIGHT_VERTICAL = b"\xba".decode("ibm437")
+ CHAR_INNER_HORIZONTAL = b"\xcd".decode("ibm437")
+ CHAR_INNER_INTERSECT = b"\xce".decode("ibm437")
+ CHAR_INNER_VERTICAL = b"\xba".decode("ibm437")
+ CHAR_OUTER_BOTTOM_HORIZONTAL = b"\xcd".decode("ibm437")
+ CHAR_OUTER_BOTTOM_INTERSECT = b"\xca".decode("ibm437")
+ CHAR_OUTER_BOTTOM_LEFT = b"\xc8".decode("ibm437")
+ CHAR_OUTER_BOTTOM_RIGHT = b"\xbc".decode("ibm437")
+ CHAR_OUTER_LEFT_INTERSECT = b"\xcc".decode("ibm437")
+ CHAR_OUTER_LEFT_VERTICAL = b"\xba".decode("ibm437")
+ CHAR_OUTER_RIGHT_INTERSECT = b"\xb9".decode("ibm437")
+ CHAR_OUTER_RIGHT_VERTICAL = b"\xba".decode("ibm437")
+ CHAR_OUTER_TOP_HORIZONTAL = b"\xcd".decode("ibm437")
+ CHAR_OUTER_TOP_INTERSECT = b"\xcb".decode("ibm437")
+ CHAR_OUTER_TOP_LEFT = b"\xc9".decode("ibm437")
+ CHAR_OUTER_TOP_RIGHT = b"\xbb".decode("ibm437")
+
+
+class SingleTable(WindowsTable if IS_WINDOWS else UnixTable):
+ """Cross-platform table with single-line box-drawing characters.
+
+ :ivar iter table_data: List (empty or list of lists of strings) representing the table.
+ :ivar str title: Optional title to show within the top border of the table.
+ :ivar bool inner_column_border: Separates columns.
+ :ivar bool inner_footing_row_border: Show a border before the last row.
+ :ivar bool inner_heading_row_border: Show a border after the first row.
+ :ivar bool inner_row_border: Show a border in between every row.
+ :ivar bool outer_border: Show the top, left, right, and bottom border.
+ :ivar dict justify_columns: Horizontal justification. Keys are column indexes (int). Values are right/left/center.
+ :ivar int padding_left: Number of spaces to pad on the left side of every cell.
+ :ivar int padding_right: Number of spaces to pad on the right side of every cell.
+ """
+
+
+class DoubleTable(WindowsTableDouble):
+ """Cross-platform table with box-drawing characters. On Windows it's double borders, on Linux/OSX it's unicode.
+
+ :ivar iter table_data: List (empty or list of lists of strings) representing the table.
+ :ivar str title: Optional title to show within the top border of the table.
+ :ivar bool inner_column_border: Separates columns.
+ :ivar bool inner_footing_row_border: Show a border before the last row.
+ :ivar bool inner_heading_row_border: Show a border after the first row.
+ :ivar bool inner_row_border: Show a border in between every row.
+ :ivar bool outer_border: Show the top, left, right, and bottom border.
+ :ivar dict justify_columns: Horizontal justification. Keys are column indexes (int). Values are right/left/center.
+ :ivar int padding_left: Number of spaces to pad on the left side of every cell.
+ :ivar int padding_right: Number of spaces to pad on the right side of every cell.
+ """
+
+
+class PorcelainTable(AsciiTable):
+ """An AsciiTable stripped to a minimum.
+
+ Meant to be machine passable and roughly follow format set by git --porcelain option (hence the name).
+
+ :ivar iter table_data: List (empty or list of lists of strings) representing the table.
+ """
+
+ def __init__(self, table_data):
+ """Constructor.
+
+ :param iter table_data: List (empty or list of lists of strings) representing the table.
+ """
+ # Porcelain table won't support title since it has no outer birders.
+ super().__init__(table_data)
+
+ # Removes outer border, and inner footing and header row borders.
+ self.inner_footing_row_border = False
+ self.inner_heading_row_border = False
+ self.outer_border = False
diff --git a/terminaltables/terminal_io.py b/terminaltables3/terminal_io.py
index 8b8c10d..dc04431 100644
--- a/terminaltables/terminal_io.py
+++ b/terminaltables3/terminal_io.py
@@ -3,16 +3,17 @@
import ctypes
import struct
import sys
+from typing import Tuple, Union
DEFAULT_HEIGHT = 24
DEFAULT_WIDTH = 79
INVALID_HANDLE_VALUE = -1
-IS_WINDOWS = sys.platform == 'win32'
+IS_WINDOWS = sys.platform == "win32"
STD_ERROR_HANDLE = -12
STD_OUTPUT_HANDLE = -11
-def get_console_info(kernel32, handle):
+def get_console_info(kernel32, handle: int) -> Tuple[int, int]:
"""Get information about this current console window (Windows only).
https://github.com/Robpol86/colorclass/blob/ab42da59/colorclass/windows.py#L111
@@ -26,7 +27,7 @@ def get_console_info(kernel32, handle):
:rtype: tuple
"""
if handle == INVALID_HANDLE_VALUE:
- raise OSError('Invalid handle.')
+ raise OSError("Invalid handle.")
# Query Win32 API.
lpcsbi = ctypes.create_string_buffer(22) # Populated by GetConsoleScreenBufferInfo.
@@ -34,12 +35,12 @@ def get_console_info(kernel32, handle):
raise ctypes.WinError() # Subclass of OSError.
# Parse data.
- left, top, right, bottom = struct.unpack('hhhhHhhhhhh', lpcsbi.raw)[5:-2]
+ left, top, right, bottom = struct.unpack("hhhhHhhhhhh", lpcsbi.raw)[5:-2]
width, height = right - left, bottom - top
return width, height
-def terminal_size(kernel32=None):
+def terminal_size(kernel32=None) -> Tuple[int, int]:
"""Get the width and height of the terminal.
http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/
@@ -56,19 +57,23 @@ def terminal_size(kernel32=None):
return get_console_info(kernel32, kernel32.GetStdHandle(STD_ERROR_HANDLE))
except OSError:
try:
- return get_console_info(kernel32, kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
+ return get_console_info(
+ kernel32, kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
+ )
except OSError:
return DEFAULT_WIDTH, DEFAULT_HEIGHT
try:
- device = __import__('fcntl').ioctl(0, __import__('termios').TIOCGWINSZ, '\0\0\0\0\0\0\0\0')
- except IOError:
+ device = __import__("fcntl").ioctl(
+ 0, __import__("termios").TIOCGWINSZ, "\0\0\0\0\0\0\0\0"
+ )
+ except OSError:
return DEFAULT_WIDTH, DEFAULT_HEIGHT
- height, width = struct.unpack('hhhh', device)[:2]
+ height, width = struct.unpack("hhhh", device)[:2]
return width, height
-def set_terminal_title(title, kernel32=None):
+def set_terminal_title(title: Union[str, bytes], kernel32=None) -> bool:
"""Set the terminal title.
:param title: The title to set (string, unicode, bytes accepted).
@@ -78,7 +83,7 @@ def set_terminal_title(title, kernel32=None):
:rtype: bool
"""
try:
- title_bytes = title.encode('utf-8')
+ title_bytes = title.encode("utf-8")
except AttributeError:
title_bytes = title
@@ -90,9 +95,8 @@ def set_terminal_title(title, kernel32=None):
is_ascii = all(c < 128 for c in title) # bytes.
if is_ascii:
return kernel32.SetConsoleTitleA(title_bytes) != 0
- else:
- return kernel32.SetConsoleTitleW(title) != 0
+ return kernel32.SetConsoleTitleW(title) != 0
# Linux/OSX.
- sys.stdout.write(b'\033]0;' + title_bytes + b'\007')
+ sys.stdout.write(b"\033]0;" + title_bytes + b"\007")
return True
diff --git a/terminaltables/width_and_alignment.py b/terminaltables3/width_and_alignment.py
index 057e800..6f7d807 100644
--- a/terminaltables/width_and_alignment.py
+++ b/terminaltables3/width_and_alignment.py
@@ -2,36 +2,37 @@
import re
import unicodedata
+from typing import Sequence, Tuple
-from terminaltables.terminal_io import terminal_size
+from terminaltables3.terminal_io import terminal_size
-RE_COLOR_ANSI = re.compile(r'(\033\[[\d;]+m)')
+RE_COLOR_ANSI = re.compile(r"(\033\[[\d;]+m)")
-def visible_width(string):
+def visible_width(string: str) -> int:
"""Get the visible width of a unicode string.
Some CJK unicode characters are more than one byte unlike ASCII and latin unicode characters.
- From: https://github.com/Robpol86/terminaltables/pull/9
+ From: https://github.com/Robpol86/terminaltables3/pull/9
:param str string: String to measure.
:return: String's width.
:rtype: int
"""
- if '\033' in string:
- string = RE_COLOR_ANSI.sub('', string)
+ if "\033" in string:
+ string = RE_COLOR_ANSI.sub("", string)
# Convert to unicode.
try:
- string = string.decode('u8')
+ string = string.decode("u8")
except (AttributeError, UnicodeEncodeError):
pass
width = 0
for char in string:
- if unicodedata.east_asian_width(char) in ('F', 'W'):
+ if unicodedata.east_asian_width(char) in ("F", "W"):
width += 2
else:
width += 1
@@ -39,7 +40,13 @@ def visible_width(string):
return width
-def align_and_pad_cell(string, align, inner_dimensions, padding, space=' '):
+def align_and_pad_cell(
+ string: str,
+ align: Tuple,
+ inner_dimensions: Tuple,
+ padding: Sequence[int],
+ space: str = " ",
+) -> list[str]:
"""Align a string horizontally and vertically. Also add additional padding in both dimensions.
:param str string: Input string to operate on.
@@ -51,37 +58,55 @@ def align_and_pad_cell(string, align, inner_dimensions, padding, space=' '):
:return: Padded cell split into lines.
:rtype: list
"""
- if not hasattr(string, 'splitlines'):
+ if not hasattr(string, "splitlines"):
string = str(string)
# Handle trailing newlines or empty strings, str.splitlines() does not satisfy.
- lines = string.splitlines() or ['']
- if string.endswith('\n'):
- lines.append('')
+ lines = string.splitlines() or [""]
+ if string.endswith("\n"):
+ lines.append("")
# Vertically align and pad.
- if 'bottom' in align:
- lines = ([''] * (inner_dimensions[1] - len(lines) + padding[2])) + lines + ([''] * padding[3])
- elif 'middle' in align:
+ if "bottom" in align:
+ lines = (
+ ([""] * (inner_dimensions[1] - len(lines) + padding[2]))
+ + lines
+ + ([""] * padding[3])
+ )
+ elif "middle" in align:
delta = inner_dimensions[1] - len(lines)
- lines = ([''] * (delta // 2 + delta % 2 + padding[2])) + lines + ([''] * (delta // 2 + padding[3]))
+ lines = (
+ ([""] * (delta // 2 + delta % 2 + padding[2]))
+ + lines
+ + ([""] * (delta // 2 + padding[3]))
+ )
else:
- lines = ([''] * padding[2]) + lines + ([''] * (inner_dimensions[1] - len(lines) + padding[3]))
+ lines = (
+ ([""] * padding[2])
+ + lines
+ + ([""] * (inner_dimensions[1] - len(lines) + padding[3]))
+ )
# Horizontally align and pad.
for i, line in enumerate(lines):
new_width = inner_dimensions[0] + len(line) - visible_width(line)
- if 'right' in align:
+ if "right" in align:
lines[i] = line.rjust(padding[0] + new_width, space) + (space * padding[1])
- elif 'center' in align:
- lines[i] = (space * padding[0]) + line.center(new_width, space) + (space * padding[1])
+ elif "center" in align:
+ lines[i] = (
+ (space * padding[0])
+ + line.center(new_width, space)
+ + (space * padding[1])
+ )
else:
lines[i] = (space * padding[0]) + line.ljust(new_width + padding[1], space)
return lines
-def max_dimensions(table_data, padding_left=0, padding_right=0, padding_top=0, padding_bottom=0):
+def max_dimensions(
+ table_data, padding_left=0, padding_right=0, padding_top=0, padding_bottom=0
+):
"""Get maximum widths of each column and maximum height of each row.
:param iter table_data: List of list of strings (unmodified table data).
@@ -99,12 +124,15 @@ def max_dimensions(table_data, padding_left=0, padding_right=0, padding_top=0, p
# Find max width and heights.
for j, row in enumerate(table_data):
for i, cell in enumerate(row):
- if not hasattr(cell, 'count') or not hasattr(cell, 'splitlines'):
+ if not hasattr(cell, "count") or not hasattr(cell, "splitlines"):
cell = str(cell)
if not cell:
continue
- inner_heights[j] = max(inner_heights[j], cell.count('\n') + 1)
- inner_widths[i] = max(inner_widths[i], *[visible_width(l) for l in cell.splitlines()])
+ inner_heights[j] = max(inner_heights[j], cell.count("\n") + 1)
+ inner_widths[i] = max(
+ inner_widths[i],
+ *[visible_width(the_line) for the_line in cell.splitlines()]
+ )
# Calculate with padding.
outer_widths = [padding_left + i + padding_right for i in inner_widths]
@@ -113,7 +141,13 @@ def max_dimensions(table_data, padding_left=0, padding_right=0, padding_top=0, p
return inner_widths, inner_heights, outer_widths, outer_heights
-def column_max_width(inner_widths, column_number, outer_border, inner_border, padding):
+def column_max_width(
+ inner_widths: Sequence[int],
+ column_number: int,
+ outer_border: int,
+ inner_border: int,
+ padding: int,
+) -> int:
"""Determine the maximum width of a column based on the current terminal width.
:param iter inner_widths: List of widths (no padding) for each column.
@@ -138,7 +172,9 @@ def column_max_width(inner_widths, column_number, outer_border, inner_border, pa
return terminal_width - data_space - non_data_space
-def table_width(outer_widths, outer_border, inner_border):
+def table_width(
+ outer_widths: Sequence[int], outer_border: int, inner_border: int
+) -> int:
"""Determine the width of the entire table including borders and padding.
:param iter outer_widths: List of widths (with padding) for each column.
diff --git a/tests/__init__.py b/tests/__init__.py
index b91337b..7baf433 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -2,4 +2,4 @@
import py
-PROJECT_ROOT = py.path.local(__file__).dirpath().join('..')
+PROJECT_ROOT = py.path.local(__file__).dirpath().join("..")
diff --git a/tests/screenshot.py b/tests/screenshot.py
index 6ccb593..0786d48 100644
--- a/tests/screenshot.py
+++ b/tests/screenshot.py
@@ -14,7 +14,7 @@ except ImportError:
from tests import PROJECT_ROOT
-STARTF_USESHOWWINDOW = getattr(subprocess, 'STARTF_USESHOWWINDOW', 1)
+STARTF_USESHOWWINDOW = getattr(subprocess, "STARTF_USESHOWWINDOW", 1)
STILL_ACTIVE = 259
SW_MAXIMIZE = 3
@@ -23,24 +23,24 @@ class StartupInfo(ctypes.Structure):
"""STARTUPINFO structure."""
_fields_ = [
- ('cb', ctypes.c_ulong),
- ('lpReserved', ctypes.c_char_p),
- ('lpDesktop', ctypes.c_char_p),
- ('lpTitle', ctypes.c_char_p),
- ('dwX', ctypes.c_ulong),
- ('dwY', ctypes.c_ulong),
- ('dwXSize', ctypes.c_ulong),
- ('dwYSize', ctypes.c_ulong),
- ('dwXCountChars', ctypes.c_ulong),
- ('dwYCountChars', ctypes.c_ulong),
- ('dwFillAttribute', ctypes.c_ulong),
- ('dwFlags', ctypes.c_ulong),
- ('wShowWindow', ctypes.c_ushort),
- ('cbReserved2', ctypes.c_ushort),
- ('lpReserved2', ctypes.c_char_p),
- ('hStdInput', ctypes.c_ulong),
- ('hStdOutput', ctypes.c_ulong),
- ('hStdError', ctypes.c_ulong),
+ ("cb", ctypes.c_ulong),
+ ("lpReserved", ctypes.c_char_p),
+ ("lpDesktop", ctypes.c_char_p),
+ ("lpTitle", ctypes.c_char_p),
+ ("dwX", ctypes.c_ulong),
+ ("dwY", ctypes.c_ulong),
+ ("dwXSize", ctypes.c_ulong),
+ ("dwYSize", ctypes.c_ulong),
+ ("dwXCountChars", ctypes.c_ulong),
+ ("dwYCountChars", ctypes.c_ulong),
+ ("dwFillAttribute", ctypes.c_ulong),
+ ("dwFlags", ctypes.c_ulong),
+ ("wShowWindow", ctypes.c_ushort),
+ ("cbReserved2", ctypes.c_ushort),
+ ("lpReserved2", ctypes.c_char_p),
+ ("hStdInput", ctypes.c_ulong),
+ ("hStdOutput", ctypes.c_ulong),
+ ("hStdError", ctypes.c_ulong),
]
def __init__(self, maximize=False, title=None):
@@ -49,7 +49,7 @@ class StartupInfo(ctypes.Structure):
:param bool maximize: Start process in new console window, maximized.
:param bytes title: Set new window title to this instead of exe path.
"""
- super(StartupInfo, self).__init__()
+ super().__init__()
self.cb = ctypes.sizeof(self)
if maximize:
self.dwFlags |= STARTF_USESHOWWINDOW
@@ -62,14 +62,14 @@ class ProcessInfo(ctypes.Structure):
"""PROCESS_INFORMATION structure."""
_fields_ = [
- ('hProcess', ctypes.c_void_p),
- ('hThread', ctypes.c_void_p),
- ('dwProcessId', ctypes.c_ulong),
- ('dwThreadId', ctypes.c_ulong),
+ ("hProcess", ctypes.c_void_p),
+ ("hThread", ctypes.c_void_p),
+ ("dwProcessId", ctypes.c_ulong),
+ ("dwThreadId", ctypes.c_ulong),
]
-class RunNewConsole(object):
+class RunNewConsole:
"""Run the command in a new console window. Windows only. Use in a with statement.
subprocess sucks and really limits your access to the win32 API. Its implementation is half-assed. Using this so
@@ -84,20 +84,27 @@ class RunNewConsole(object):
:param bytes title: Set new window title to this. Needed by user32.FindWindow.
"""
if title is None:
- title = 'pytest-{0}-{1}'.format(os.getpid(), random.randint(1000, 9999)).encode('ascii')
+ title = "pytest-{}-{}".format(
+ os.getpid(), random.randint(1000, 9999)
+ ).encode("ascii")
self.startup_info = StartupInfo(maximize=maximized, title=title)
self.process_info = ProcessInfo()
- self.command_str = subprocess.list2cmdline(command).encode('ascii')
- self._handles = list()
+ self.command_str = subprocess.list2cmdline(command).encode("ascii")
+ self._handles = []
self._kernel32 = ctypes.LibraryLoader(ctypes.WinDLL).kernel32
- self._kernel32.GetExitCodeProcess.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_ulong)]
+ self._kernel32.GetExitCodeProcess.argtypes = [
+ ctypes.c_void_p,
+ ctypes.POINTER(ctypes.c_ulong),
+ ]
self._kernel32.GetExitCodeProcess.restype = ctypes.c_long
def __del__(self):
"""Close win32 handles."""
while self._handles:
try:
- self._kernel32.CloseHandle(self._handles.pop(0)) # .pop() is thread safe.
+ self._kernel32.CloseHandle(
+ self._handles.pop(0)
+ ) # .pop() is thread safe.
except IndexError:
break
@@ -111,9 +118,9 @@ class RunNewConsole(object):
False, # bInheritHandles
subprocess.CREATE_NEW_CONSOLE, # dwCreationFlags
None, # lpEnvironment
- str(PROJECT_ROOT).encode('ascii'), # lpCurrentDirectory
+ str(PROJECT_ROOT).encode("ascii"), # lpCurrentDirectory
ctypes.byref(self.startup_info), # lpStartupInfo
- ctypes.byref(self.process_info) # lpProcessInformation
+ ctypes.byref(self.process_info), # lpProcessInformation
):
raise ctypes.WinError()
@@ -125,7 +132,9 @@ class RunNewConsole(object):
self.hwnd = 0
for _ in range(int(5 / 0.1)):
# Takes time for console window to initialize.
- self.hwnd = ctypes.windll.user32.FindWindowA(None, self.startup_info.lpTitle)
+ self.hwnd = ctypes.windll.user32.FindWindowA(
+ None, self.startup_info.lpTitle
+ )
if self.hwnd:
break
time.sleep(0.1)
@@ -141,7 +150,9 @@ class RunNewConsole(object):
status = ctypes.c_ulong(STILL_ACTIVE)
while status.value == STILL_ACTIVE:
time.sleep(0.1)
- if not self._kernel32.GetExitCodeProcess(self.process_info.hProcess, ctypes.byref(status)):
+ if not self._kernel32.GetExitCodeProcess(
+ self.process_info.hProcess, ctypes.byref(status)
+ ):
raise ctypes.WinError()
assert status.value == 0
finally:
@@ -154,9 +165,11 @@ class RunNewConsole(object):
:return: Yields region the new window is in (left, upper, right, lower).
:rtype: tuple
"""
- rect = ctypes.create_string_buffer(16) # To be written to by GetWindowRect. RECT structure.
+ rect = ctypes.create_string_buffer(
+ 16
+ ) # To be written to by GetWindowRect. RECT structure.
while ctypes.windll.user32.GetWindowRect(self.hwnd, rect):
- left, top, right, bottom = struct.unpack('llll', rect.raw)
+ left, top, right, bottom = struct.unpack("llll", rect.raw)
width, height = right - left, bottom - top
assert width > 1
assert height > 1
@@ -179,8 +192,7 @@ def iter_rows(pil_image):
:rtype: tuple
"""
iterator = izip(*(iter(pil_image.getdata()),) * pil_image.width)
- for row in iterator:
- yield row
+ yield from iterator
def get_most_interesting_row(pil_image):
@@ -224,11 +236,13 @@ def count_subimages(screenshot, subimg):
for x_pos in range(screenshot.width - si_width + 1):
if row[x_pos] != si_pixel:
continue # First pixel does not match.
- if row[x_pos:x_pos + si_width] != si_row:
+ if row[x_pos : x_pos + si_width] != si_row:
continue # Row does not match.
# Found match for interesting row of subimg in screenshot.
y_corrected = y_pos - si_y
- with screenshot.crop((x_pos, y_corrected, x_pos + si_width, y_corrected + si_height)) as cropped:
+ with screenshot.crop(
+ (x_pos, y_corrected, x_pos + si_width, y_corrected + si_height)
+ ) as cropped:
if list(cropped.getdata()) == si_pixels:
occurrences += 1
@@ -248,11 +262,12 @@ def try_candidates(screenshot, subimg_candidates, expected_count):
:rtype: int
"""
from PIL import Image
+
count_found = 0
for subimg_path in subimg_candidates:
with Image.open(subimg_path) as rgba_s:
- with rgba_s.convert(mode='RGB') as subimg:
+ with rgba_s.convert(mode="RGB") as subimg:
# Make sure subimage isn't too large.
assert subimg.width < 256
assert subimg.height < 256
@@ -277,14 +292,17 @@ def screenshot_until_match(save_to, timeout, subimg_candidates, expected_count,
:param iter gen: Generator yielding window position and size to crop screenshot to.
"""
from PIL import ImageGrab
- assert save_to.endswith('.png')
+
+ assert save_to.endswith(".png")
stop_after = time.time() + timeout
# Take screenshots until subimage is found.
while True:
with ImageGrab.grab(next(gen)) as rgba:
- with rgba.convert(mode='RGB') as screenshot:
- count_found = try_candidates(screenshot, subimg_candidates, expected_count)
+ with rgba.convert(mode="RGB") as screenshot:
+ count_found = try_candidates(
+ screenshot, subimg_candidates, expected_count
+ )
if count_found == expected_count or time.time() > stop_after:
screenshot.save(save_to)
assert count_found == expected_count
diff --git a/tests/test_all_tables_e2e/test_ascii_table.py b/tests/test_all_tables_e2e/test_ascii_table.py
index a1a3b9c..ded2bce 100644
--- a/tests/test_all_tables_e2e/test_ascii_table.py
+++ b/tests/test_all_tables_e2e/test_ascii_table.py
@@ -6,8 +6,8 @@ from textwrap import dedent
import py
import pytest
-from terminaltables import AsciiTable
-from terminaltables.terminal_io import IS_WINDOWS
+from terminaltables3 import AsciiTable
+from terminaltables3.terminal_io import IS_WINDOWS
from tests import PROJECT_ROOT
from tests.screenshot import RunNewConsole, screenshot_until_match
@@ -17,31 +17,31 @@ HERE = py.path.local(__file__).dirpath()
def test_single_line():
"""Test single-lined cells."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
- ['Watermelon', 'green'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
+ ["Watermelon", "green"],
[],
]
- table = AsciiTable(table_data, 'Example')
+ table = AsciiTable(table_data, "Example")
table.inner_footing_row_border = True
- table.justify_columns[0] = 'left'
- table.justify_columns[1] = 'center'
- table.justify_columns[2] = 'right'
+ table.justify_columns[0] = "left"
+ table.justify_columns[1] = "center"
+ table.justify_columns[2] = "right"
actual = table.table
expected = (
- '+Example-----+-------+-----------+\n'
- '| Name | Color | Type |\n'
- '+------------+-------+-----------+\n'
- '| Avocado | green | nut |\n'
- '| Tomato | red | fruit |\n'
- '| Lettuce | green | vegetable |\n'
- '| Watermelon | green | |\n'
- '+------------+-------+-----------+\n'
- '| | | |\n'
- '+------------+-------+-----------+'
+ "+Example-----+-------+-----------+\n"
+ "| Name | Color | Type |\n"
+ "+------------+-------+-----------+\n"
+ "| Avocado | green | nut |\n"
+ "| Tomato | red | fruit |\n"
+ "| Lettuce | green | vegetable |\n"
+ "| Watermelon | green | |\n"
+ "+------------+-------+-----------+\n"
+ "| | | |\n"
+ "+------------+-------+-----------+"
)
assert actual == expected
@@ -49,22 +49,25 @@ def test_single_line():
def test_multi_line():
"""Test multi-lined cells."""
table_data = [
- ['Show', 'Characters'],
- ['Rugrats', 'Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles'],
- ['South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick']
+ ["Show", "Characters"],
+ [
+ "Rugrats",
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles",
+ ],
+ ["South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"],
]
table = AsciiTable(table_data)
# Test defaults.
actual = table.table
expected = (
- '+------------+-------------------------------------------------------------------------------------+\n'
- '| Show | Characters |\n'
- '+------------+-------------------------------------------------------------------------------------+\n'
- '| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n'
- '| | Dil Pickles |\n'
- '| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |\n'
- '+------------+-------------------------------------------------------------------------------------+'
+ "+------------+-------------------------------------------------------------------------------------+\n"
+ "| Show | Characters |\n"
+ "+------------+-------------------------------------------------------------------------------------+\n"
+ "| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n"
+ "| | Dil Pickles |\n"
+ "| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |\n"
+ "+------------+-------------------------------------------------------------------------------------+"
)
assert actual == expected
@@ -72,52 +75,53 @@ def test_multi_line():
table.inner_row_border = True
actual = table.table
expected = (
- '+------------+-------------------------------------------------------------------------------------+\n'
- '| Show | Characters |\n'
- '+------------+-------------------------------------------------------------------------------------+\n'
- '| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n'
- '| | Dil Pickles |\n'
- '+------------+-------------------------------------------------------------------------------------+\n'
- '| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |\n'
- '+------------+-------------------------------------------------------------------------------------+'
+ "+------------+-------------------------------------------------------------------------------------+\n"
+ "| Show | Characters |\n"
+ "+------------+-------------------------------------------------------------------------------------+\n"
+ "| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n"
+ "| | Dil Pickles |\n"
+ "+------------+-------------------------------------------------------------------------------------+\n"
+ "| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |\n"
+ "+------------+-------------------------------------------------------------------------------------+"
)
assert actual == expected
# Justify right.
- table.justify_columns = {1: 'right'}
+ table.justify_columns = {1: "right"}
actual = table.table
expected = (
- '+------------+-------------------------------------------------------------------------------------+\n'
- '| Show | Characters |\n'
- '+------------+-------------------------------------------------------------------------------------+\n'
- '| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n'
- '| | Dil Pickles |\n'
- '+------------+-------------------------------------------------------------------------------------+\n'
- '| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |\n'
- '+------------+-------------------------------------------------------------------------------------+'
+ "+------------+-------------------------------------------------------------------------------------+\n"
+ "| Show | Characters |\n"
+ "+------------+-------------------------------------------------------------------------------------+\n"
+ "| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n"
+ "| | Dil Pickles |\n"
+ "+------------+-------------------------------------------------------------------------------------+\n"
+ "| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |\n"
+ "+------------+-------------------------------------------------------------------------------------+"
)
assert actual == expected
@pytest.mark.skipif(str(not IS_WINDOWS))
-@pytest.mark.skip # https://github.com/Robpol86/terminaltables/issues/44
+@pytest.mark.skip # https://github.com/Robpol86/terminaltables3/issues/44
def test_windows_screenshot(tmpdir):
"""Test on Windows in a new console window. Take a screenshot to verify it works.
:param tmpdir: pytest fixture.
"""
- script = tmpdir.join('script.py')
+ script = tmpdir.join("script.py")
command = [sys.executable, str(script)]
- screenshot = PROJECT_ROOT.join('test_ascii_table.png')
+ screenshot = PROJECT_ROOT.join("test_ascii_table.png")
if screenshot.check():
screenshot.remove()
# Generate script.
- script_template = dedent(u"""\
+ script_template = dedent(
+ """\
from __future__ import print_function
import os, time
from colorclass import Color, Windows
- from terminaltables import AsciiTable
+ from terminaltables3 import AsciiTable
Windows.enable(auto_colors=True)
stop_after = time.time() + 20
@@ -132,12 +136,13 @@ def test_windows_screenshot(tmpdir):
print('Waiting for screenshot_until_match()...')
while not os.path.exists(r'%s') and time.time() < stop_after:
time.sleep(0.5)
- """)
+ """
+ )
script_contents = script_template % str(screenshot)
- script.write(script_contents.encode('utf-8'), mode='wb')
+ script.write(script_contents.encode("utf-8"), mode="wb")
# Setup expected.
- sub_images = [str(p) for p in HERE.listdir('sub_ascii_*.bmp')]
+ sub_images = [str(p) for p in HERE.listdir("sub_ascii_*.bmp")]
assert sub_images
# Run.
diff --git a/tests/test_all_tables_e2e/test_double_table.py b/tests/test_all_tables_e2e/test_double_table.py
index beec764..3cd54e6 100644
--- a/tests/test_all_tables_e2e/test_double_table.py
+++ b/tests/test_all_tables_e2e/test_double_table.py
@@ -6,8 +6,8 @@ from textwrap import dedent
import py
import pytest
-from terminaltables import DoubleTable
-from terminaltables.terminal_io import IS_WINDOWS
+from terminaltables3 import DoubleTable
+from terminaltables3.terminal_io import IS_WINDOWS
from tests import PROJECT_ROOT
from tests.screenshot import RunNewConsole, screenshot_until_match
@@ -17,44 +17,35 @@ HERE = py.path.local(__file__).dirpath()
def test_single_line():
"""Test single-lined cells."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
- ['Watermelon', 'green'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
+ ["Watermelon", "green"],
[],
]
- table = DoubleTable(table_data, 'Example')
+ table = DoubleTable(table_data, "Example")
table.inner_footing_row_border = True
- table.justify_columns[0] = 'left'
- table.justify_columns[1] = 'center'
- table.justify_columns[2] = 'right'
+ table.justify_columns[0] = "left"
+ table.justify_columns[1] = "center"
+ table.justify_columns[2] = "right"
actual = table.table
expected = (
- u'\u2554Example\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n'
-
- u'\u2551 Name \u2551 Color \u2551 Type \u2551\n'
-
- u'\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n'
-
- u'\u2551 Avocado \u2551 green \u2551 nut \u2551\n'
-
- u'\u2551 Tomato \u2551 red \u2551 fruit \u2551\n'
-
- u'\u2551 Lettuce \u2551 green \u2551 vegetable \u2551\n'
-
- u'\u2551 Watermelon \u2551 green \u2551 \u2551\n'
-
- u'\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n'
-
- u'\u2551 \u2551 \u2551 \u2551\n'
-
- u'\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d'
+ "\u2554Example\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n"
+ "\u2551 Name \u2551 Color \u2551 Type \u2551\n"
+ "\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n"
+ "\u2551 Avocado \u2551 green \u2551 nut \u2551\n"
+ "\u2551 Tomato \u2551 red \u2551 fruit \u2551\n"
+ "\u2551 Lettuce \u2551 green \u2551 vegetable \u2551\n"
+ "\u2551 Watermelon \u2551 green \u2551 \u2551\n"
+ "\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n"
+ "\u2551 \u2551 \u2551 \u2551\n"
+ "\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d"
)
assert actual == expected
@@ -62,47 +53,44 @@ def test_single_line():
def test_multi_line():
"""Test multi-lined cells."""
table_data = [
- ['Show', 'Characters'],
- ['Rugrats', 'Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles'],
- ['South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick']
+ ["Show", "Characters"],
+ [
+ "Rugrats",
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles",
+ ],
+ ["South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"],
]
table = DoubleTable(table_data)
# Test defaults.
actual = table.table
expected = (
- u'\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n'
-
- u'\u2551 Show \u2551 Characters '
- u'\u2551\n'
-
- u'\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n'
-
- u'\u2551 Rugrats \u2551 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, '
- u'\u2551\n'
-
- u'\u2551 \u2551 Dil Pickles '
- u'\u2551\n'
-
- u'\u2551 South Park \u2551 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
- u'\u2551\n'
-
- u'\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d'
+ "\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n"
+ "\u2551 Show \u2551 Characters "
+ "\u2551\n"
+ "\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n"
+ "\u2551 Rugrats \u2551 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, "
+ "\u2551\n"
+ "\u2551 \u2551 Dil Pickles "
+ "\u2551\n"
+ "\u2551 South Park \u2551 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
+ "\u2551\n"
+ "\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d"
)
assert actual == expected
@@ -110,114 +98,101 @@ def test_multi_line():
table.inner_row_border = True
actual = table.table
expected = (
- u'\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n'
-
- u'\u2551 Show \u2551 Characters '
- u'\u2551\n'
-
- u'\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n'
-
- u'\u2551 Rugrats \u2551 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, '
- u'\u2551\n'
-
- u'\u2551 \u2551 Dil Pickles '
- u'\u2551\n'
-
- u'\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n'
-
- u'\u2551 South Park \u2551 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
- u'\u2551\n'
-
- u'\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d'
+ "\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n"
+ "\u2551 Show \u2551 Characters "
+ "\u2551\n"
+ "\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n"
+ "\u2551 Rugrats \u2551 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, "
+ "\u2551\n"
+ "\u2551 \u2551 Dil Pickles "
+ "\u2551\n"
+ "\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n"
+ "\u2551 South Park \u2551 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
+ "\u2551\n"
+ "\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d"
)
assert actual == expected
# Justify right.
- table.justify_columns = {1: 'right'}
+ table.justify_columns = {1: "right"}
actual = table.table
expected = (
- u'\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n'
-
- u'\u2551 Show \u2551 Characters '
- u'\u2551\n'
-
- u'\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n'
-
- u'\u2551 Rugrats \u2551 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, '
- u'\u2551\n'
-
- u'\u2551 \u2551 Dil Pickles '
- u'\u2551\n'
-
- u'\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n'
-
- u'\u2551 South Park \u2551 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
- u'\u2551\n'
-
- u'\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550'
- u'\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d'
+ "\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n"
+ "\u2551 Show \u2551 Characters "
+ "\u2551\n"
+ "\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n"
+ "\u2551 Rugrats \u2551 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, "
+ "\u2551\n"
+ "\u2551 \u2551 Dil Pickles "
+ "\u2551\n"
+ "\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256c\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563\n"
+ "\u2551 South Park \u2551 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
+ "\u2551\n"
+ "\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d"
)
assert actual == expected
@pytest.mark.skipif(str(not IS_WINDOWS))
-@pytest.mark.skip # https://github.com/Robpol86/terminaltables/issues/44
+@pytest.mark.skip # https://github.com/Robpol86/terminaltables3/issues/44
def test_windows_screenshot(tmpdir):
"""Test on Windows in a new console window. Take a screenshot to verify it works.
:param tmpdir: pytest fixture.
"""
- script = tmpdir.join('script.py')
+ script = tmpdir.join("script.py")
command = [sys.executable, str(script)]
- screenshot = PROJECT_ROOT.join('test_double_table.png')
+ screenshot = PROJECT_ROOT.join("test_double_table.png")
if screenshot.check():
screenshot.remove()
# Generate script.
- script_template = dedent(u"""\
+ script_template = dedent(
+ """\
from __future__ import print_function
import os, time
from colorclass import Color, Windows
- from terminaltables import DoubleTable
+ from terminaltables3 import DoubleTable
Windows.enable(auto_colors=True)
stop_after = time.time() + 20
@@ -232,12 +207,13 @@ def test_windows_screenshot(tmpdir):
print('Waiting for screenshot_until_match()...')
while not os.path.exists(r'%s') and time.time() < stop_after:
time.sleep(0.5)
- """)
+ """
+ )
script_contents = script_template % str(screenshot)
- script.write(script_contents.encode('utf-8'), mode='wb')
+ script.write(script_contents.encode("utf-8"), mode="wb")
# Setup expected.
- sub_images = [str(p) for p in HERE.listdir('sub_double_*.bmp')]
+ sub_images = [str(p) for p in HERE.listdir("sub_double_*.bmp")]
assert sub_images
# Run.
diff --git a/tests/test_all_tables_e2e/test_github_table.py b/tests/test_all_tables_e2e/test_github_table.py
index 6176215..4764d0e 100644
--- a/tests/test_all_tables_e2e/test_github_table.py
+++ b/tests/test_all_tables_e2e/test_github_table.py
@@ -1,33 +1,33 @@
"""GithubFlavoredMarkdownTable end to end testing."""
-from terminaltables import GithubFlavoredMarkdownTable
+from terminaltables3 import GithubFlavoredMarkdownTable
def test_single_line():
"""Test single-lined cells."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
- ['Watermelon', 'green'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
+ ["Watermelon", "green"],
[],
]
table = GithubFlavoredMarkdownTable(table_data)
table.inner_footing_row_border = True
- table.justify_columns[0] = 'left'
- table.justify_columns[1] = 'center'
- table.justify_columns[2] = 'right'
+ table.justify_columns[0] = "left"
+ table.justify_columns[1] = "center"
+ table.justify_columns[2] = "right"
actual = table.table
expected = (
- '| Name | Color | Type |\n'
- '|:-----------|:-----:|----------:|\n'
- '| Avocado | green | nut |\n'
- '| Tomato | red | fruit |\n'
- '| Lettuce | green | vegetable |\n'
- '| Watermelon | green | |\n'
- '| | | |'
+ "| Name | Color | Type |\n"
+ "|:-----------|:-----:|----------:|\n"
+ "| Avocado | green | nut |\n"
+ "| Tomato | red | fruit |\n"
+ "| Lettuce | green | vegetable |\n"
+ "| Watermelon | green | |\n"
+ "| | | |"
)
assert actual == expected
@@ -35,20 +35,23 @@ def test_single_line():
def test_multi_line():
"""Test multi-lined cells."""
table_data = [
- ['Show', 'Characters'],
- ['Rugrats', 'Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles'],
- ['South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick']
+ ["Show", "Characters"],
+ [
+ "Rugrats",
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles",
+ ],
+ ["South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"],
]
table = GithubFlavoredMarkdownTable(table_data)
# Test defaults.
actual = table.table
expected = (
- '| Show | Characters |\n'
- '|------------|-------------------------------------------------------------------------------------|\n'
- '| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n'
- '| | Dil Pickles |\n'
- '| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |'
+ "| Show | Characters |\n"
+ "|------------|-------------------------------------------------------------------------------------|\n"
+ "| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n"
+ "| | Dil Pickles |\n"
+ "| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |"
)
assert actual == expected
@@ -56,22 +59,22 @@ def test_multi_line():
table.inner_row_border = True
actual = table.table
expected = (
- '| Show | Characters |\n'
- '|------------|-------------------------------------------------------------------------------------|\n'
- '| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n'
- '| | Dil Pickles |\n'
- '| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |'
+ "| Show | Characters |\n"
+ "|------------|-------------------------------------------------------------------------------------|\n"
+ "| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n"
+ "| | Dil Pickles |\n"
+ "| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |"
)
assert actual == expected
# Justify right.
- table.justify_columns = {1: 'right'}
+ table.justify_columns = {1: "right"}
actual = table.table
expected = (
- '| Show | Characters |\n'
- '|------------|------------------------------------------------------------------------------------:|\n'
- '| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n'
- '| | Dil Pickles |\n'
- '| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |'
+ "| Show | Characters |\n"
+ "|------------|------------------------------------------------------------------------------------:|\n"
+ "| Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, |\n"
+ "| | Dil Pickles |\n"
+ "| South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick |"
)
assert actual == expected
diff --git a/tests/test_all_tables_e2e/test_porcelain_table.py b/tests/test_all_tables_e2e/test_porcelain_table.py
index 7677188..ced2f9c 100644
--- a/tests/test_all_tables_e2e/test_porcelain_table.py
+++ b/tests/test_all_tables_e2e/test_porcelain_table.py
@@ -1,29 +1,29 @@
"""PorcelainTable end to end testing."""
-from terminaltables import PorcelainTable
+from terminaltables3 import PorcelainTable
def test_single_line():
"""Test single-lined cells."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
- ['Watermelon', 'green']
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
+ ["Watermelon", "green"],
]
table = PorcelainTable(table_data)
- table.justify_columns[0] = 'left'
- table.justify_columns[1] = 'center'
- table.justify_columns[2] = 'right'
+ table.justify_columns[0] = "left"
+ table.justify_columns[1] = "center"
+ table.justify_columns[2] = "right"
actual = table.table
expected = (
- ' Name | Color | Type \n'
- ' Avocado | green | nut \n'
- ' Tomato | red | fruit \n'
- ' Lettuce | green | vegetable \n'
- ' Watermelon | green | '
+ " Name | Color | Type \n"
+ " Avocado | green | nut \n"
+ " Tomato | red | fruit \n"
+ " Lettuce | green | vegetable \n"
+ " Watermelon | green | "
)
assert actual == expected
@@ -31,29 +31,32 @@ def test_single_line():
def test_multi_line():
"""Test multi-lined cells."""
table_data = [
- ['Show', 'Characters'],
- ['Rugrats', 'Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles'],
- ['South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick']
+ ["Show", "Characters"],
+ [
+ "Rugrats",
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles",
+ ],
+ ["South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"],
]
table = PorcelainTable(table_data)
# Test defaults.
actual = table.table
expected = (
- ' Show | Characters \n'
- ' Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, \n'
- ' | Dil Pickles \n'
- ' South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
+ " Show | Characters \n"
+ " Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, \n"
+ " | Dil Pickles \n"
+ " South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
)
assert actual == expected
# Justify right.
- table.justify_columns = {1: 'right'}
+ table.justify_columns = {1: "right"}
actual = table.table
expected = (
- ' Show | Characters \n'
- ' Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, \n'
- ' | Dil Pickles \n'
- ' South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
+ " Show | Characters \n"
+ " Rugrats | Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, \n"
+ " | Dil Pickles \n"
+ " South Park | Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
)
assert actual == expected
diff --git a/tests/test_all_tables_e2e/test_single_table.py b/tests/test_all_tables_e2e/test_single_table.py
index f4fa6b9..7c6b8ff 100644
--- a/tests/test_all_tables_e2e/test_single_table.py
+++ b/tests/test_all_tables_e2e/test_single_table.py
@@ -2,8 +2,8 @@
import pytest
-from terminaltables import SingleTable
-from terminaltables.terminal_io import IS_WINDOWS
+from terminaltables3 import SingleTable
+from terminaltables3.terminal_io import IS_WINDOWS
pytestmark = pytest.mark.skipif(str(IS_WINDOWS))
@@ -11,44 +11,35 @@ pytestmark = pytest.mark.skipif(str(IS_WINDOWS))
def test_single_line():
"""Test single-lined cells."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
- ['Watermelon', 'green'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
+ ["Watermelon", "green"],
[],
]
- table = SingleTable(table_data, 'Example')
+ table = SingleTable(table_data, "Example")
table.inner_footing_row_border = True
- table.justify_columns[0] = 'left'
- table.justify_columns[1] = 'center'
- table.justify_columns[2] = 'right'
+ table.justify_columns[0] = "left"
+ table.justify_columns[1] = "center"
+ table.justify_columns[2] = "right"
actual = table.table
expected = (
- '\033(0\x6c\033(BExample\033(0\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x6b\033(B\n'
-
- '\033(0\x78\033(B Name \033(0\x78\033(B Color \033(0\x78\033(B Type \033(0\x78\033(B\n'
-
- '\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n'
-
- '\033(0\x78\033(B Avocado \033(0\x78\033(B green \033(0\x78\033(B nut \033(0\x78\033(B\n'
-
- '\033(0\x78\033(B Tomato \033(0\x78\033(B red \033(0\x78\033(B fruit \033(0\x78\033(B\n'
-
- '\033(0\x78\033(B Lettuce \033(0\x78\033(B green \033(0\x78\033(B vegetable \033(0\x78\033(B\n'
-
- '\033(0\x78\033(B Watermelon \033(0\x78\033(B green \033(0\x78\033(B \033(0\x78\033(B\n'
-
- '\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n'
-
- '\033(0\x78\033(B \033(0\x78\033(B \033(0\x78\033(B \033(0\x78\033(B\n'
-
- '\033(0\x6d\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x6a\033(B'
+ "\033(0\x6c\033(BExample\033(0\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x6b\033(B\n"
+ "\033(0\x78\033(B Name \033(0\x78\033(B Color \033(0\x78\033(B Type \033(0\x78\033(B\n"
+ "\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n"
+ "\033(0\x78\033(B Avocado \033(0\x78\033(B green \033(0\x78\033(B nut \033(0\x78\033(B\n"
+ "\033(0\x78\033(B Tomato \033(0\x78\033(B red \033(0\x78\033(B fruit \033(0\x78\033(B\n"
+ "\033(0\x78\033(B Lettuce \033(0\x78\033(B green \033(0\x78\033(B vegetable \033(0\x78\033(B\n"
+ "\033(0\x78\033(B Watermelon \033(0\x78\033(B green \033(0\x78\033(B \033(0\x78\033(B\n"
+ "\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n"
+ "\033(0\x78\033(B \033(0\x78\033(B \033(0\x78\033(B \033(0\x78\033(B\n"
+ "\033(0\x6d\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x6a\033(B"
)
assert actual == expected
@@ -56,41 +47,38 @@ def test_single_line():
def test_multi_line():
"""Test multi-lined cells."""
table_data = [
- ['Show', 'Characters'],
- ['Rugrats', 'Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles'],
- ['South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick']
+ ["Show", "Characters"],
+ [
+ "Rugrats",
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles",
+ ],
+ ["South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"],
]
table = SingleTable(table_data)
# Test defaults.
actual = table.table
expected = (
- '\033(0\x6c\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6b\033(B\n'
-
- '\033(0\x78\033(B Show \033(0\x78\033(B Characters '
- ' \033(0\x78\033(B\n'
-
- '\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n'
-
- '\033(0\x78\033(B Rugrats \033(0\x78\033(B Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille,'
- ' Angelica Pickles, \033(0\x78\033(B\n'
-
- '\033(0\x78\033(B \033(0\x78\033(B Dil Pickles '
- ' \033(0\x78\033(B\n'
-
- '\033(0\x78\033(B South Park \033(0\x78\033(B Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
- ' \033(0\x78\033(B\n'
-
- '\033(0\x6d\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6a\033(B'
+ "\033(0\x6c\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6b\033(B\n"
+ "\033(0\x78\033(B Show \033(0\x78\033(B Characters "
+ " \033(0\x78\033(B\n"
+ "\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n"
+ "\033(0\x78\033(B Rugrats \033(0\x78\033(B Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille,"
+ " Angelica Pickles, \033(0\x78\033(B\n"
+ "\033(0\x78\033(B \033(0\x78\033(B Dil Pickles "
+ " \033(0\x78\033(B\n"
+ "\033(0\x78\033(B South Park \033(0\x78\033(B Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
+ " \033(0\x78\033(B\n"
+ "\033(0\x6d\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6a\033(B"
)
assert actual == expected
@@ -98,74 +86,60 @@ def test_multi_line():
table.inner_row_border = True
actual = table.table
expected = (
- '\033(0\x6c\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6b\033(B\n'
-
- '\033(0\x78\033(B Show \033(0\x78\033(B Characters '
- ' \033(0\x78\033(B\n'
-
- '\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n'
-
- '\033(0\x78\033(B Rugrats \033(0\x78\033(B Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille,'
- ' Angelica Pickles, \033(0\x78\033(B\n'
-
- '\033(0\x78\033(B \033(0\x78\033(B Dil Pickles '
- ' \033(0\x78\033(B\n'
-
- '\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n'
-
- '\033(0\x78\033(B South Park \033(0\x78\033(B Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
- ' \033(0\x78\033(B\n'
-
- '\033(0\x6d\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6a\033(B'
+ "\033(0\x6c\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6b\033(B\n"
+ "\033(0\x78\033(B Show \033(0\x78\033(B Characters "
+ " \033(0\x78\033(B\n"
+ "\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n"
+ "\033(0\x78\033(B Rugrats \033(0\x78\033(B Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille,"
+ " Angelica Pickles, \033(0\x78\033(B\n"
+ "\033(0\x78\033(B \033(0\x78\033(B Dil Pickles "
+ " \033(0\x78\033(B\n"
+ "\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n"
+ "\033(0\x78\033(B South Park \033(0\x78\033(B Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
+ " \033(0\x78\033(B\n"
+ "\033(0\x6d\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6a\033(B"
)
assert actual == expected
# Justify right.
- table.justify_columns = {1: 'right'}
+ table.justify_columns = {1: "right"}
actual = table.table
expected = (
- '\033(0\x6c\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6b\033(B\n'
-
- '\033(0\x78\033(B Show \033(0\x78\033(B '
- ' Characters \033(0\x78\033(B\n'
-
- '\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n'
-
- '\033(0\x78\033(B Rugrats \033(0\x78\033(B Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille,'
- ' Angelica Pickles, \033(0\x78\033(B\n'
-
- '\033(0\x78\033(B \033(0\x78\033(B '
- ' Dil Pickles \033(0\x78\033(B\n'
-
- '\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n'
-
- '\033(0\x78\033(B South Park \033(0\x78\033(B Stan Marsh, Kyle Broflovski, '
- 'Eric Cartman, Kenny McCormick \033(0\x78\033(B\n'
-
- '\033(0\x6d\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71'
- '\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6a\033(B'
+ "\033(0\x6c\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x77\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6b\033(B\n"
+ "\033(0\x78\033(B Show \033(0\x78\033(B "
+ " Characters \033(0\x78\033(B\n"
+ "\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n"
+ "\033(0\x78\033(B Rugrats \033(0\x78\033(B Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille,"
+ " Angelica Pickles, \033(0\x78\033(B\n"
+ "\033(0\x78\033(B \033(0\x78\033(B "
+ " Dil Pickles \033(0\x78\033(B\n"
+ "\033(0\x74\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6e\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x75\033(B\n"
+ "\033(0\x78\033(B South Park \033(0\x78\033(B Stan Marsh, Kyle Broflovski, "
+ "Eric Cartman, Kenny McCormick \033(0\x78\033(B\n"
+ "\033(0\x6d\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x76\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71"
+ "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x6a\033(B"
)
assert actual == expected
diff --git a/tests/test_all_tables_e2e/test_single_table_windows.py b/tests/test_all_tables_e2e/test_single_table_windows.py
index bfdfe2e..120cf84 100644
--- a/tests/test_all_tables_e2e/test_single_table_windows.py
+++ b/tests/test_all_tables_e2e/test_single_table_windows.py
@@ -6,8 +6,8 @@ from textwrap import dedent
import py
import pytest
-from terminaltables import SingleTable
-from terminaltables.terminal_io import IS_WINDOWS
+from terminaltables3 import SingleTable
+from terminaltables3.terminal_io import IS_WINDOWS
from tests import PROJECT_ROOT
from tests.screenshot import RunNewConsole, screenshot_until_match
@@ -18,44 +18,35 @@ pytestmark = pytest.mark.skipif(str(not IS_WINDOWS))
def test_single_line():
"""Test single-lined cells."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
- ['Watermelon', 'green'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
+ ["Watermelon", "green"],
[],
]
- table = SingleTable(table_data, 'Example')
+ table = SingleTable(table_data, "Example")
table.inner_footing_row_border = True
- table.justify_columns[0] = 'left'
- table.justify_columns[1] = 'center'
- table.justify_columns[2] = 'right'
+ table.justify_columns[0] = "left"
+ table.justify_columns[1] = "center"
+ table.justify_columns[2] = "right"
actual = table.table
expected = (
- u'\u250cExample\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n'
-
- u'\u2502 Name \u2502 Color \u2502 Type \u2502\n'
-
- u'\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n'
-
- u'\u2502 Avocado \u2502 green \u2502 nut \u2502\n'
-
- u'\u2502 Tomato \u2502 red \u2502 fruit \u2502\n'
-
- u'\u2502 Lettuce \u2502 green \u2502 vegetable \u2502\n'
-
- u'\u2502 Watermelon \u2502 green \u2502 \u2502\n'
-
- u'\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n'
-
- u'\u2502 \u2502 \u2502 \u2502\n'
-
- u'\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518'
+ "\u250cExample\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n"
+ "\u2502 Name \u2502 Color \u2502 Type \u2502\n"
+ "\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n"
+ "\u2502 Avocado \u2502 green \u2502 nut \u2502\n"
+ "\u2502 Tomato \u2502 red \u2502 fruit \u2502\n"
+ "\u2502 Lettuce \u2502 green \u2502 vegetable \u2502\n"
+ "\u2502 Watermelon \u2502 green \u2502 \u2502\n"
+ "\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n"
+ "\u2502 \u2502 \u2502 \u2502\n"
+ "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"
)
assert actual == expected
@@ -63,47 +54,44 @@ def test_single_line():
def test_multi_line():
"""Test multi-lined cells."""
table_data = [
- ['Show', 'Characters'],
- ['Rugrats', 'Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles'],
- ['South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick']
+ ["Show", "Characters"],
+ [
+ "Rugrats",
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles",
+ ],
+ ["South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"],
]
table = SingleTable(table_data)
# Test defaults.
actual = table.table
expected = (
- u'\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n'
-
- u'\u2502 Show \u2502 Characters '
- u'\u2502\n'
-
- u'\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n'
-
- u'\u2502 Rugrats \u2502 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, '
- u'\u2502\n'
-
- u'\u2502 \u2502 Dil Pickles '
- u'\u2502\n'
-
- u'\u2502 South Park \u2502 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
- u'\u2502\n'
-
- u'\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518'
+ "\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n"
+ "\u2502 Show \u2502 Characters "
+ "\u2502\n"
+ "\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n"
+ "\u2502 Rugrats \u2502 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, "
+ "\u2502\n"
+ "\u2502 \u2502 Dil Pickles "
+ "\u2502\n"
+ "\u2502 South Park \u2502 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
+ "\u2502\n"
+ "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"
)
assert actual == expected
@@ -111,114 +99,101 @@ def test_multi_line():
table.inner_row_border = True
actual = table.table
expected = (
- u'\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n'
-
- u'\u2502 Show \u2502 Characters '
- u'\u2502\n'
-
- u'\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n'
-
- u'\u2502 Rugrats \u2502 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, '
- u'\u2502\n'
-
- u'\u2502 \u2502 Dil Pickles '
- u'\u2502\n'
-
- u'\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n'
-
- u'\u2502 South Park \u2502 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
- u'\u2502\n'
-
- u'\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518'
+ "\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n"
+ "\u2502 Show \u2502 Characters "
+ "\u2502\n"
+ "\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n"
+ "\u2502 Rugrats \u2502 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, "
+ "\u2502\n"
+ "\u2502 \u2502 Dil Pickles "
+ "\u2502\n"
+ "\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n"
+ "\u2502 South Park \u2502 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
+ "\u2502\n"
+ "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"
)
assert actual == expected
# Justify right.
- table.justify_columns = {1: 'right'}
+ table.justify_columns = {1: "right"}
actual = table.table
expected = (
- u'\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n'
-
- u'\u2502 Show \u2502 Characters '
- u'\u2502\n'
-
- u'\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n'
-
- u'\u2502 Rugrats \u2502 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, '
- u'\u2502\n'
-
- u'\u2502 \u2502 Dil Pickles '
- u'\u2502\n'
-
- u'\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n'
-
- u'\u2502 South Park \u2502 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick '
- u'\u2502\n'
-
- u'\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'
- u'\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518'
+ "\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n"
+ "\u2502 Show \u2502 Characters "
+ "\u2502\n"
+ "\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n"
+ "\u2502 Rugrats \u2502 Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles, "
+ "\u2502\n"
+ "\u2502 \u2502 Dil Pickles "
+ "\u2502\n"
+ "\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n"
+ "\u2502 South Park \u2502 Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick "
+ "\u2502\n"
+ "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"
)
assert actual == expected
@pytest.mark.skipif(str(not IS_WINDOWS))
-@pytest.mark.skip # https://github.com/Robpol86/terminaltables/issues/44
+@pytest.mark.skip # https://github.com/Robpol86/terminaltables3/issues/44
def test_windows_screenshot(tmpdir):
"""Test on Windows in a new console window. Take a screenshot to verify it works.
:param tmpdir: pytest fixture.
"""
- script = tmpdir.join('script.py')
+ script = tmpdir.join("script.py")
command = [sys.executable, str(script)]
- screenshot = PROJECT_ROOT.join('test_single_table.png')
+ screenshot = PROJECT_ROOT.join("test_single_table.png")
if screenshot.check():
screenshot.remove()
# Generate script.
- script_template = dedent(u"""\
+ script_template = dedent(
+ """\
from __future__ import print_function
import os, time
from colorclass import Color, Windows
- from terminaltables import SingleTable
+ from terminaltables3 import SingleTable
Windows.enable(auto_colors=True)
stop_after = time.time() + 20
@@ -233,12 +208,13 @@ def test_windows_screenshot(tmpdir):
print('Waiting for screenshot_until_match()...')
while not os.path.exists(r'%s') and time.time() < stop_after:
time.sleep(0.5)
- """)
+ """
+ )
script_contents = script_template % str(screenshot)
- script.write(script_contents.encode('utf-8'), mode='wb')
+ script.write(script_contents.encode("utf-8"), mode="wb")
# Setup expected.
- sub_images = [str(p) for p in HERE.listdir('sub_single_*.bmp')]
+ sub_images = [str(p) for p in HERE.listdir("sub_single_*.bmp")]
assert sub_images
# Run.
diff --git a/tests/test_ascii_table.py b/tests/test_ascii_table.py
index 020a443..dd3dc8e 100644
--- a/tests/test_ascii_table.py
+++ b/tests/test_ascii_table.py
@@ -2,19 +2,22 @@
import pytest
-from terminaltables.other_tables import AsciiTable
+from terminaltables3.other_tables import AsciiTable
SINGLE_LINE = (
- ('Name', 'Color', 'Type'),
- ('Avocado', 'green', 'nut'),
- ('Tomato', 'red', 'fruit'),
- ('Lettuce', 'green', 'vegetable'),
+ ("Name", "Color", "Type"),
+ ("Avocado", "green", "nut"),
+ ("Tomato", "red", "fruit"),
+ ("Lettuce", "green", "vegetable"),
)
MULTI_LINE = (
- ('Show', 'Characters'),
- ('Rugrats', 'Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles'),
- ('South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick'),
+ ("Show", "Characters"),
+ (
+ "Rugrats",
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\nDil Pickles",
+ ),
+ ("South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"),
)
@@ -24,20 +27,25 @@ def patch(monkeypatch):
:param monkeypatch: pytest fixture.
"""
- monkeypatch.setattr('terminaltables.ascii_table.terminal_size', lambda: (79, 24))
- monkeypatch.setattr('terminaltables.width_and_alignment.terminal_size', lambda: (79, 24))
-
-
-@pytest.mark.parametrize('table_data,column_number,expected', [
- ([], 0, IndexError),
- ([[]], 0, IndexError),
- ([['']], 1, IndexError),
- (SINGLE_LINE, 0, 55),
- (SINGLE_LINE, 1, 53),
- (SINGLE_LINE, 2, 57),
- (MULTI_LINE, 0, -11),
- (MULTI_LINE, 1, 62),
-])
+ monkeypatch.setattr("terminaltables3.ascii_table.terminal_size", lambda: (79, 24))
+ monkeypatch.setattr(
+ "terminaltables3.width_and_alignment.terminal_size", lambda: (79, 24)
+ )
+
+
+@pytest.mark.parametrize(
+ "table_data,column_number,expected",
+ [
+ ([], 0, IndexError),
+ ([[]], 0, IndexError),
+ ([[""]], 1, IndexError),
+ (SINGLE_LINE, 0, 55),
+ (SINGLE_LINE, 1, 53),
+ (SINGLE_LINE, 2, 57),
+ (MULTI_LINE, 0, -11),
+ (MULTI_LINE, 1, 62),
+ ],
+)
def test_column_max_width(table_data, column_number, expected):
"""Test method in class.
@@ -47,7 +55,7 @@ def test_column_max_width(table_data, column_number, expected):
"""
table = AsciiTable(table_data)
- if expected == IndexError:
+ if expected is IndexError:
with pytest.raises(IndexError):
table.column_max_width(column_number)
return
@@ -58,22 +66,25 @@ def test_column_max_width(table_data, column_number, expected):
def test_column_widths():
"""Test method in class."""
- assert AsciiTable([]).column_widths == list()
+ assert AsciiTable([]).column_widths == []
table = AsciiTable(SINGLE_LINE)
actual = table.column_widths
assert actual == [7, 5, 9]
-@pytest.mark.parametrize('table_data,terminal_width,expected', [
- ([], None, True),
- ([[]], None, True),
- ([['']], None, True),
- (SINGLE_LINE, None, True),
- (SINGLE_LINE, 30, False),
- (MULTI_LINE, None, False),
- (MULTI_LINE, 100, True),
-])
+@pytest.mark.parametrize(
+ "table_data,terminal_width,expected",
+ [
+ ([], None, True),
+ ([[]], None, True),
+ ([[""]], None, True),
+ (SINGLE_LINE, None, True),
+ (SINGLE_LINE, 30, False),
+ (MULTI_LINE, None, False),
+ (MULTI_LINE, 100, True),
+ ],
+)
def test_ok(monkeypatch, table_data, terminal_width, expected):
"""Test method in class.
@@ -83,20 +94,25 @@ def test_ok(monkeypatch, table_data, terminal_width, expected):
:param bool expected: Expected return value.
"""
if terminal_width is not None:
- monkeypatch.setattr('terminaltables.ascii_table.terminal_size', lambda: (terminal_width, 24))
+ monkeypatch.setattr(
+ "terminaltables3.ascii_table.terminal_size", lambda: (terminal_width, 24)
+ )
table = AsciiTable(table_data)
actual = table.ok
assert actual is expected
-@pytest.mark.parametrize('table_data,expected', [
- ([], 2),
- ([[]], 2),
- ([['']], 4),
- ([[' ']], 5),
- (SINGLE_LINE, 31),
- (MULTI_LINE, 100),
-])
+@pytest.mark.parametrize(
+ "table_data,expected",
+ [
+ ([], 2),
+ ([[]], 2),
+ ([[""]], 4),
+ ([[" "]], 5),
+ (SINGLE_LINE, 31),
+ (MULTI_LINE, 100),
+ ],
+)
def test_table_width(table_data, expected):
"""Test method in class.
diff --git a/tests/test_base_table/__init__.py b/tests/test_base_table/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test_base_table/__init__.py
diff --git a/tests/test_base_table/test_gen_row_lines.py b/tests/test_base_table/test_gen_row_lines.py
index 0d0f43c..da47349 100644
--- a/tests/test_base_table/test_gen_row_lines.py
+++ b/tests/test_base_table/test_gen_row_lines.py
@@ -2,47 +2,47 @@
import pytest
-from terminaltables.base_table import BaseTable
+from terminaltables3.base_table import BaseTable
-@pytest.mark.parametrize('style', ['heading', 'footing', 'row'])
+@pytest.mark.parametrize("style", ["heading", "footing", "row"])
def test_single_line(style):
"""Test with single-line row.
:param str style: Passed to method.
"""
- row = ['Row One Column One', 'Two', 'Three']
+ row = ["Row One Column One", "Two", "Three"]
table = BaseTable([row])
actual = [tuple(i) for i in table.gen_row_lines(row, style, [18, 3, 5], 1)]
expected = [
- ('|', ' Row One Column One ', '|', ' Two ', '|', ' Three ', '|'),
+ ("|", " Row One Column One ", "|", " Two ", "|", " Three ", "|"),
]
assert actual == expected
-@pytest.mark.parametrize('style', ['heading', 'footing', 'row'])
+@pytest.mark.parametrize("style", ["heading", "footing", "row"])
def test_multi_line(style):
"""Test with multi-line row.
:param str style: Passed to method.
"""
- row = ['Row One\nColumn One', 'Two', 'Three']
+ row = ["Row One\nColumn One", "Two", "Three"]
table = BaseTable([row])
actual = [tuple(i) for i in table.gen_row_lines(row, style, [10, 3, 5], 2)]
expected = [
- ('|', ' Row One ', '|', ' Two ', '|', ' Three ', '|'),
- ('|', ' Column One ', '|', ' ', '|', ' ', '|'),
+ ("|", " Row One ", "|", " Two ", "|", " Three ", "|"),
+ ("|", " Column One ", "|", " ", "|", " ", "|"),
]
assert actual == expected
-@pytest.mark.parametrize('style', ['heading', 'footing', 'row'])
+@pytest.mark.parametrize("style", ["heading", "footing", "row"])
def test_no_padding_no_borders(style):
"""Test without padding or borders.
:param str style: Passed to method.
"""
- row = ['Row One\nColumn One', 'Two', 'Three']
+ row = ["Row One\nColumn One", "Two", "Three"]
table = BaseTable([row])
table.inner_column_border = False
table.outer_border = False
@@ -50,28 +50,28 @@ def test_no_padding_no_borders(style):
table.padding_right = 0
actual = [tuple(i) for i in table.gen_row_lines(row, style, [10, 3, 5], 2)]
expected = [
- ('Row One ', 'Two', 'Three'),
- ('Column One', ' ', ' '),
+ ("Row One ", "Two", "Three"),
+ ("Column One", " ", " "),
]
assert actual == expected
-@pytest.mark.parametrize('style', ['heading', 'footing', 'row'])
+@pytest.mark.parametrize("style", ["heading", "footing", "row"])
def test_uneven(style):
"""Test with row missing cells.
:param str style: Passed to method.
"""
- row = ['Row One Column One']
+ row = ["Row One Column One"]
table = BaseTable([row])
actual = [tuple(i) for i in table.gen_row_lines(row, style, [18, 3, 5], 1)]
expected = [
- ('|', ' Row One Column One ', '|', ' ', '|', ' ', '|'),
+ ("|", " Row One Column One ", "|", " ", "|", " ", "|"),
]
assert actual == expected
-@pytest.mark.parametrize('style', ['heading', 'footing', 'row'])
+@pytest.mark.parametrize("style", ["heading", "footing", "row"])
def test_empty_table(style):
"""Test empty table.
@@ -81,6 +81,6 @@ def test_empty_table(style):
table = BaseTable([row])
actual = [tuple(i) for i in table.gen_row_lines(row, style, [], 0)]
expected = [
- ('|', '|'),
+ ("|", "|"),
]
assert actual == expected
diff --git a/tests/test_base_table/test_gen_table.py b/tests/test_base_table/test_gen_table.py
index 54d5fe1..d7ee997 100644
--- a/tests/test_base_table/test_gen_table.py
+++ b/tests/test_base_table/test_gen_table.py
@@ -2,15 +2,17 @@
import pytest
-from terminaltables.base_table import BaseTable
-from terminaltables.build import flatten
-from terminaltables.width_and_alignment import max_dimensions
+from terminaltables3.base_table import BaseTable
+from terminaltables3.build import flatten
+from terminaltables3.width_and_alignment import max_dimensions
-@pytest.mark.parametrize('inner_heading_row_border', [True, False])
-@pytest.mark.parametrize('inner_footing_row_border', [True, False])
-@pytest.mark.parametrize('inner_row_border', [True, False])
-def test_inner_row_borders(inner_heading_row_border, inner_footing_row_border, inner_row_border):
+@pytest.mark.parametrize("inner_heading_row_border", [True, False])
+@pytest.mark.parametrize("inner_footing_row_border", [True, False])
+@pytest.mark.parametrize("inner_row_border", [True, False])
+def test_inner_row_borders(
+ inner_heading_row_border, inner_footing_row_border, inner_row_border
+):
"""Test heading/footing/row borders.
:param bool inner_heading_row_border: Passed to table.
@@ -18,142 +20,145 @@ def test_inner_row_borders(inner_heading_row_border, inner_footing_row_border, i
:param bool inner_row_border: Passed to table.
"""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
]
table = BaseTable(table_data)
table.inner_heading_row_border = inner_heading_row_border
table.inner_footing_row_border = inner_footing_row_border
table.inner_row_border = inner_row_border
- inner_widths, inner_heights, outer_widths = max_dimensions(table_data, table.padding_left, table.padding_right)[:3]
+ inner_widths, inner_heights, outer_widths = max_dimensions(
+ table_data, table.padding_left, table.padding_right
+ )[:3]
actual = flatten(table.gen_table(inner_widths, inner_heights, outer_widths))
# Determine expected.
if inner_row_border:
expected = (
- '+---------+-------+-----------+\n'
- '| Name | Color | Type |\n'
- '+---------+-------+-----------+\n'
- '| Avocado | green | nut |\n'
- '+---------+-------+-----------+\n'
- '| Tomato | red | fruit |\n'
- '+---------+-------+-----------+\n'
- '| Lettuce | green | vegetable |\n'
- '+---------+-------+-----------+'
+ "+---------+-------+-----------+\n"
+ "| Name | Color | Type |\n"
+ "+---------+-------+-----------+\n"
+ "| Avocado | green | nut |\n"
+ "+---------+-------+-----------+\n"
+ "| Tomato | red | fruit |\n"
+ "+---------+-------+-----------+\n"
+ "| Lettuce | green | vegetable |\n"
+ "+---------+-------+-----------+"
)
elif inner_heading_row_border and inner_footing_row_border:
expected = (
- '+---------+-------+-----------+\n'
- '| Name | Color | Type |\n'
- '+---------+-------+-----------+\n'
- '| Avocado | green | nut |\n'
- '| Tomato | red | fruit |\n'
- '+---------+-------+-----------+\n'
- '| Lettuce | green | vegetable |\n'
- '+---------+-------+-----------+'
+ "+---------+-------+-----------+\n"
+ "| Name | Color | Type |\n"
+ "+---------+-------+-----------+\n"
+ "| Avocado | green | nut |\n"
+ "| Tomato | red | fruit |\n"
+ "+---------+-------+-----------+\n"
+ "| Lettuce | green | vegetable |\n"
+ "+---------+-------+-----------+"
)
elif inner_heading_row_border:
expected = (
- '+---------+-------+-----------+\n'
- '| Name | Color | Type |\n'
- '+---------+-------+-----------+\n'
- '| Avocado | green | nut |\n'
- '| Tomato | red | fruit |\n'
- '| Lettuce | green | vegetable |\n'
- '+---------+-------+-----------+'
+ "+---------+-------+-----------+\n"
+ "| Name | Color | Type |\n"
+ "+---------+-------+-----------+\n"
+ "| Avocado | green | nut |\n"
+ "| Tomato | red | fruit |\n"
+ "| Lettuce | green | vegetable |\n"
+ "+---------+-------+-----------+"
)
elif inner_footing_row_border:
expected = (
- '+---------+-------+-----------+\n'
- '| Name | Color | Type |\n'
- '| Avocado | green | nut |\n'
- '| Tomato | red | fruit |\n'
- '+---------+-------+-----------+\n'
- '| Lettuce | green | vegetable |\n'
- '+---------+-------+-----------+'
+ "+---------+-------+-----------+\n"
+ "| Name | Color | Type |\n"
+ "| Avocado | green | nut |\n"
+ "| Tomato | red | fruit |\n"
+ "+---------+-------+-----------+\n"
+ "| Lettuce | green | vegetable |\n"
+ "+---------+-------+-----------+"
)
else:
expected = (
- '+---------+-------+-----------+\n'
- '| Name | Color | Type |\n'
- '| Avocado | green | nut |\n'
- '| Tomato | red | fruit |\n'
- '| Lettuce | green | vegetable |\n'
- '+---------+-------+-----------+'
+ "+---------+-------+-----------+\n"
+ "| Name | Color | Type |\n"
+ "| Avocado | green | nut |\n"
+ "| Tomato | red | fruit |\n"
+ "| Lettuce | green | vegetable |\n"
+ "+---------+-------+-----------+"
)
assert actual == expected
-@pytest.mark.parametrize('outer_border', [True, False])
+@pytest.mark.parametrize("outer_border", [True, False])
def test_outer_borders(outer_border):
"""Test left/right/top/bottom table borders.
:param bool outer_border: Passed to table.
"""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
]
- table = BaseTable(table_data, 'Example Table')
+ table = BaseTable(table_data, "Example Table")
table.outer_border = outer_border
- inner_widths, inner_heights, outer_widths = max_dimensions(table_data, table.padding_left, table.padding_right)[:3]
+ inner_widths, inner_heights, outer_widths = max_dimensions(
+ table_data, table.padding_left, table.padding_right
+ )[:3]
actual = flatten(table.gen_table(inner_widths, inner_heights, outer_widths))
# Determine expected.
if outer_border:
expected = (
- '+Example Table----+-----------+\n'
- '| Name | Color | Type |\n'
- '+---------+-------+-----------+\n'
- '| Avocado | green | nut |\n'
- '| Tomato | red | fruit |\n'
- '| Lettuce | green | vegetable |\n'
- '+---------+-------+-----------+'
+ "+Example Table----+-----------+\n"
+ "| Name | Color | Type |\n"
+ "+---------+-------+-----------+\n"
+ "| Avocado | green | nut |\n"
+ "| Tomato | red | fruit |\n"
+ "| Lettuce | green | vegetable |\n"
+ "+---------+-------+-----------+"
)
else:
expected = (
- ' Name | Color | Type \n'
- '---------+-------+-----------\n'
- ' Avocado | green | nut \n'
- ' Tomato | red | fruit \n'
- ' Lettuce | green | vegetable '
+ " Name | Color | Type \n"
+ "---------+-------+-----------\n"
+ " Avocado | green | nut \n"
+ " Tomato | red | fruit \n"
+ " Lettuce | green | vegetable "
)
assert actual == expected
-@pytest.mark.parametrize('mode', ['row', 'one', 'blank', 'empty', 'none'])
-@pytest.mark.parametrize('bare', [False, True])
+@pytest.mark.parametrize("mode", ["row", "one", "blank", "empty", "none"])
+@pytest.mark.parametrize("bare", [False, True])
def test_one_no_rows(mode, bare):
"""Test with one or no rows.
:param str mode: Type of table contents to test.
:param bool bare: Disable padding/borders.
"""
- if mode == 'row':
+ if mode == "row":
table_data = [
- ['Avocado', 'green', 'nut'],
+ ["Avocado", "green", "nut"],
]
- elif mode == 'one':
+ elif mode == "one":
table_data = [
- ['Avocado'],
+ ["Avocado"],
]
- elif mode == 'blank':
+ elif mode == "blank":
table_data = [
- [''],
+ [""],
]
- elif mode == 'empty':
+ elif mode == "empty":
table_data = [
[],
]
else:
- table_data = [
- ]
+ table_data = []
table = BaseTable(table_data)
if bare:
table.inner_column_border = False
@@ -163,63 +168,40 @@ def test_one_no_rows(mode, bare):
table.outer_border = False
table.padding_left = 0
table.padding_right = 0
- inner_widths, inner_heights, outer_widths = max_dimensions(table_data, table.padding_left, table.padding_right)[:3]
+ inner_widths, inner_heights, outer_widths = max_dimensions(
+ table_data, table.padding_left, table.padding_right
+ )[:3]
actual = flatten(table.gen_table(inner_widths, inner_heights, outer_widths))
# Determine expected.
- if mode == 'row':
+ if mode == "row":
if bare:
- expected = (
- 'Avocadogreennut'
- )
+ expected = "Avocadogreennut"
else:
expected = (
- '+---------+-------+-----+\n'
- '| Avocado | green | nut |\n'
- '+---------+-------+-----+'
+ "+---------+-------+-----+\n"
+ "| Avocado | green | nut |\n"
+ "+---------+-------+-----+"
)
- elif mode == 'one':
+ elif mode == "one":
if bare:
- expected = (
- 'Avocado'
- )
+ expected = "Avocado"
else:
- expected = (
- '+---------+\n'
- '| Avocado |\n'
- '+---------+'
- )
- elif mode == 'blank': # Remember there's still padding.
+ expected = "+---------+\n" "| Avocado |\n" "+---------+"
+ elif mode == "blank": # Remember there's still padding.
if bare:
- expected = (
- ''
- )
+ expected = ""
else:
- expected = (
- '+--+\n'
- '| |\n'
- '+--+'
- )
- elif mode == 'empty':
+ expected = "+--+\n" "| |\n" "+--+"
+ elif mode == "empty":
if bare:
- expected = (
- ''
- )
+ expected = ""
else:
- expected = (
- '++\n'
- '||\n'
- '++'
- )
+ expected = "++\n" "||\n" "++"
else:
if bare:
- expected = (
- ''
- )
+ expected = ""
else:
- expected = (
- '++\n'
- '++'
- )
+ expected = "++\n" "++"
assert actual == expected
diff --git a/tests/test_base_table/test_horizontal_border.py b/tests/test_base_table/test_horizontal_border.py
index e162261..59ae29a 100644
--- a/tests/test_base_table/test_horizontal_border.py
+++ b/tests/test_base_table/test_horizontal_border.py
@@ -2,47 +2,49 @@
import pytest
-from terminaltables.base_table import BaseTable
-from terminaltables.width_and_alignment import max_dimensions
+from terminaltables3.base_table import BaseTable
+from terminaltables3.width_and_alignment import max_dimensions
SINGLE_LINE = (
- ('Name', 'Color', 'Type'),
- ('Avocado', 'green', 'nut'),
- ('Tomato', 'red', 'fruit'),
- ('Lettuce', 'green', 'vegetable'),
+ ("Name", "Color", "Type"),
+ ("Avocado", "green", "nut"),
+ ("Tomato", "red", "fruit"),
+ ("Lettuce", "green", "vegetable"),
)
-@pytest.mark.parametrize('inner_column_border', [True, False])
-@pytest.mark.parametrize('style', ['top', 'bottom'])
+@pytest.mark.parametrize("inner_column_border", [True, False])
+@pytest.mark.parametrize("style", ["top", "bottom"])
def test_top_bottom(inner_column_border, style):
"""Test top and bottom borders.
:param bool inner_column_border: Passed to table class.
:param str style: Passed to method.
"""
- table = BaseTable(SINGLE_LINE, 'Example')
+ table = BaseTable(SINGLE_LINE, "Example")
table.inner_column_border = inner_column_border
- outer_widths = max_dimensions(table.table_data, table.padding_left, table.padding_right)[2]
+ outer_widths = max_dimensions(
+ table.table_data, table.padding_left, table.padding_right
+ )[2]
# Determine expected.
- if style == 'top' and inner_column_border:
- expected = '+Example--+-------+-----------+'
- elif style == 'top':
- expected = '+Example--------------------+'
- elif style == 'bottom' and inner_column_border:
- expected = '+---------+-------+-----------+'
+ if style == "top" and inner_column_border:
+ expected = "+Example--+-------+-----------+"
+ elif style == "top":
+ expected = "+Example--------------------+"
+ elif style == "bottom" and inner_column_border:
+ expected = "+---------+-------+-----------+"
else:
- expected = '+---------------------------+'
+ expected = "+---------------------------+"
# Test.
- actual = ''.join(table.horizontal_border(style, outer_widths))
+ actual = "".join(table.horizontal_border(style, outer_widths))
assert actual == expected
-@pytest.mark.parametrize('inner_column_border', [True, False])
-@pytest.mark.parametrize('outer_border', [True, False])
-@pytest.mark.parametrize('style', ['heading', 'footing'])
+@pytest.mark.parametrize("inner_column_border", [True, False])
+@pytest.mark.parametrize("outer_border", [True, False])
+@pytest.mark.parametrize("style", ["heading", "footing"])
def test_heading_footing(inner_column_border, outer_border, style):
"""Test heading and footing borders.
@@ -53,25 +55,43 @@ def test_heading_footing(inner_column_border, outer_border, style):
table = BaseTable(SINGLE_LINE)
table.inner_column_border = inner_column_border
table.outer_border = outer_border
- outer_widths = max_dimensions(table.table_data, table.padding_left, table.padding_right)[2]
+ outer_widths = max_dimensions(
+ table.table_data, table.padding_left, table.padding_right
+ )[2]
# Determine expected.
- if style == 'heading' and outer_border:
- expected = '+---------+-------+-----------+' if inner_column_border else '+---------------------------+'
- elif style == 'heading':
- expected = '---------+-------+-----------' if inner_column_border else '---------------------------'
- elif style == 'footing' and outer_border:
- expected = '+---------+-------+-----------+' if inner_column_border else '+---------------------------+'
+ if style == "heading" and outer_border:
+ expected = (
+ "+---------+-------+-----------+"
+ if inner_column_border
+ else "+---------------------------+"
+ )
+ elif style == "heading":
+ expected = (
+ "---------+-------+-----------"
+ if inner_column_border
+ else "---------------------------"
+ )
+ elif style == "footing" and outer_border:
+ expected = (
+ "+---------+-------+-----------+"
+ if inner_column_border
+ else "+---------------------------+"
+ )
else:
- expected = '---------+-------+-----------' if inner_column_border else '---------------------------'
+ expected = (
+ "---------+-------+-----------"
+ if inner_column_border
+ else "---------------------------"
+ )
# Test.
- actual = ''.join(table.horizontal_border(style, outer_widths))
+ actual = "".join(table.horizontal_border(style, outer_widths))
assert actual == expected
-@pytest.mark.parametrize('inner_column_border', [True, False])
-@pytest.mark.parametrize('outer_border', [True, False])
+@pytest.mark.parametrize("inner_column_border", [True, False])
+@pytest.mark.parametrize("outer_border", [True, False])
def test_row(inner_column_border, outer_border):
"""Test inner borders.
@@ -81,18 +101,20 @@ def test_row(inner_column_border, outer_border):
table = BaseTable(SINGLE_LINE)
table.inner_column_border = inner_column_border
table.outer_border = outer_border
- outer_widths = max_dimensions(table.table_data, table.padding_left, table.padding_right)[2]
+ outer_widths = max_dimensions(
+ table.table_data, table.padding_left, table.padding_right
+ )[2]
# Determine expected.
if inner_column_border and outer_border:
- expected = '+---------+-------+-----------+'
+ expected = "+---------+-------+-----------+"
elif inner_column_border:
- expected = '---------+-------+-----------'
+ expected = "---------+-------+-----------"
elif outer_border:
- expected = '+---------------------------+'
+ expected = "+---------------------------+"
else:
- expected = '---------------------------'
+ expected = "---------------------------"
# Test.
- actual = ''.join(table.horizontal_border('row', outer_widths))
+ actual = "".join(table.horizontal_border("row", outer_widths))
assert actual == expected
diff --git a/tests/test_base_table/test_table.py b/tests/test_base_table/test_table.py
index c5b5a89..7487308 100644
--- a/tests/test_base_table/test_table.py
+++ b/tests/test_base_table/test_table.py
@@ -1,32 +1,31 @@
-# coding: utf-8
"""Test property in BaseTable class."""
from colorama import Fore
from colorclass import Color
from termcolor import colored
-from terminaltables.base_table import BaseTable
+from terminaltables3.base_table import BaseTable
def test_ascii():
"""Test with ASCII characters."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
]
table = BaseTable(table_data)
actual = table.table
expected = (
- '+---------+-------+-----------+\n'
- '| Name | Color | Type |\n'
- '+---------+-------+-----------+\n'
- '| Avocado | green | nut |\n'
- '| Tomato | red | fruit |\n'
- '| Lettuce | green | vegetable |\n'
- '+---------+-------+-----------+'
+ "+---------+-------+-----------+\n"
+ "| Name | Color | Type |\n"
+ "+---------+-------+-----------+\n"
+ "| Avocado | green | nut |\n"
+ "| Tomato | red | fruit |\n"
+ "| Lettuce | green | vegetable |\n"
+ "+---------+-------+-----------+"
)
assert actual == expected
@@ -44,13 +43,13 @@ def test_int():
actual = table.table
expected = (
- '+1234567890+---+\n'
- '| 100 | 10 | 1 |\n'
- '+-----+----+---+\n'
- '| 0 | 3 | 6 |\n'
- '| 1 | 4 | 7 |\n'
- '| 2 | 5 | 8 |\n'
- '+-----+----+---+'
+ "+1234567890+---+\n"
+ "| 100 | 10 | 1 |\n"
+ "+-----+----+---+\n"
+ "| 0 | 3 | 6 |\n"
+ "| 1 | 4 | 7 |\n"
+ "| 2 | 5 | 8 |\n"
+ "+-----+----+---+"
)
assert actual == expected
@@ -68,13 +67,13 @@ def test_float():
actual = table.table
expected = (
- '+0.12345678--+-------+\n'
- '| 1.0 | 22.0 | 333.0 |\n'
- '+-----+------+-------+\n'
- '| 0.1 | 3.1 | 6.1 |\n'
- '| 1.1 | 4.1 | 7.1 |\n'
- '| 2.1 | 5.1 | 8.1 |\n'
- '+-----+------+-------+'
+ "+0.12345678--+-------+\n"
+ "| 1.0 | 22.0 | 333.0 |\n"
+ "+-----+------+-------+\n"
+ "| 0.1 | 3.1 | 6.1 |\n"
+ "| 1.1 | 4.1 | 7.1 |\n"
+ "| 2.1 | 5.1 | 8.1 |\n"
+ "+-----+------+-------+"
)
assert actual == expected
@@ -92,13 +91,13 @@ def test_bool_none():
actual = table.table
expected = (
- '+True---+-------+-------+\n'
- '| True | False | None |\n'
- '+-------+-------+-------+\n'
- '| True | False | None |\n'
- '| False | None | True |\n'
- '| None | True | False |\n'
- '+-------+-------+-------+'
+ "+True---+-------+-------+\n"
+ "| True | False | None |\n"
+ "+-------+-------+-------+\n"
+ "| True | False | None |\n"
+ "| False | None | True |\n"
+ "| None | True | False |\n"
+ "+-------+-------+-------+"
)
assert actual == expected
@@ -107,20 +106,20 @@ def test_bool_none():
def test_cjk():
"""Test with CJK characters."""
table_data = [
- ['CJK'],
- ['蓝色'],
- ['世界你好'],
+ ["CJK"],
+ ["蓝色"],
+ ["世界你好"],
]
table = BaseTable(table_data)
actual = table.table
expected = (
- '+----------+\n'
- '| CJK |\n'
- '+----------+\n'
- '| 蓝色 |\n'
- '| 世界你好 |\n'
- '+----------+'
+ "+----------+\n"
+ "| CJK |\n"
+ "+----------+\n"
+ "| 蓝色 |\n"
+ "| 世界你好 |\n"
+ "+----------+"
)
assert actual == expected
@@ -129,20 +128,15 @@ def test_cjk():
def test_rtl():
"""Test with RTL characters."""
table_data = [
- ['RTL'],
- ['שלום'],
- ['معرب'],
+ ["RTL"],
+ ["שלום"],
+ ["معرب"],
]
table = BaseTable(table_data)
actual = table.table
expected = (
- '+------+\n'
- '| RTL |\n'
- '+------+\n'
- '| שלום |\n'
- '| معرب |\n'
- '+------+'
+ "+------+\n" "| RTL |\n" "+------+\n" "| שלום |\n" "| معرب |\n" "+------+"
)
assert actual == expected
@@ -151,22 +145,22 @@ def test_rtl():
def test_rtl_large():
"""Test large table of RTL characters."""
table_data = [
- ['اكتب', 'اللون', 'اسم'],
- ['البندق', 'أخضر', 'أفوكادو'],
- ['ثمرة', 'أحمر', 'بندورة'],
- ['الخضروات', 'أخضر', 'الخس'],
+ ["اكتب", "اللون", "اسم"],
+ ["البندق", "أخضر", "أفوكادو"],
+ ["ثمرة", "أحمر", "بندورة"],
+ ["الخضروات", "أخضر", "الخس"],
]
- table = BaseTable(table_data, 'جوجل المترجم')
+ table = BaseTable(table_data, "جوجل المترجم")
actual = table.table
expected = (
- '+جوجل المترجم------+---------+\n'
- '| اكتب | اللون | اسم |\n'
- '+----------+-------+---------+\n'
- '| البندق | أخضر | أفوكادو |\n'
- '| ثمرة | أحمر | بندورة |\n'
- '| الخضروات | أخضر | الخس |\n'
- '+----------+-------+---------+'
+ "+جوجل المترجم------+---------+\n"
+ "| اكتب | اللون | اسم |\n"
+ "+----------+-------+---------+\n"
+ "| البندق | أخضر | أفوكادو |\n"
+ "| ثمرة | أحمر | بندورة |\n"
+ "| الخضروات | أخضر | الخس |\n"
+ "+----------+-------+---------+"
)
assert actual == expected
@@ -175,22 +169,42 @@ def test_rtl_large():
def test_color():
"""Test with color characters."""
table_data = [
- ['ansi', '\033[31mRed\033[39m', '\033[32mGreen\033[39m', '\033[34mBlue\033[39m'],
- ['colorclass', Color('{red}Red{/red}'), Color('{green}Green{/green}'), Color('{blue}Blue{/blue}')],
- ['colorama', Fore.RED + 'Red' + Fore.RESET, Fore.GREEN + 'Green' + Fore.RESET, Fore.BLUE + 'Blue' + Fore.RESET],
- ['termcolor', colored('Red', 'red'), colored('Green', 'green'), colored('Blue', 'blue')],
+ [
+ "ansi",
+ "\033[31mRed\033[39m",
+ "\033[32mGreen\033[39m",
+ "\033[34mBlue\033[39m",
+ ],
+ [
+ "colorclass",
+ Color("{red}Red{/red}"),
+ Color("{green}Green{/green}"),
+ Color("{blue}Blue{/blue}"),
+ ],
+ [
+ "colorama",
+ Fore.RED + "Red" + Fore.RESET,
+ Fore.GREEN + "Green" + Fore.RESET,
+ Fore.BLUE + "Blue" + Fore.RESET,
+ ],
+ [
+ "termcolor",
+ colored("Red", "red"),
+ colored("Green", "green"),
+ colored("Blue", "blue"),
+ ],
]
table = BaseTable(table_data)
table.inner_heading_row_border = False
actual = table.table
expected = (
- u'+------------+-----+-------+------+\n'
- u'| ansi | \033[31mRed\033[39m | \033[32mGreen\033[39m | \033[34mBlue\033[39m |\n'
- u'| colorclass | \033[31mRed\033[39m | \033[32mGreen\033[39m | \033[34mBlue\033[39m |\n'
- u'| colorama | \033[31mRed\033[39m | \033[32mGreen\033[39m | \033[34mBlue\033[39m |\n'
- u'| termcolor | \033[31mRed\033[0m | \033[32mGreen\033[0m | \033[34mBlue\033[0m |\n'
- u'+------------+-----+-------+------+'
+ "+------------+-----+-------+------+\n"
+ "| ansi | \033[31mRed\033[39m | \033[32mGreen\033[39m | \033[34mBlue\033[39m |\n"
+ "| colorclass | \033[31mRed\033[39m | \033[32mGreen\033[39m | \033[34mBlue\033[39m |\n"
+ "| colorama | \033[31mRed\033[39m | \033[32mGreen\033[39m | \033[34mBlue\033[39m |\n"
+ "| termcolor | \033[31mRed\033[0m | \033[32mGreen\033[0m | \033[34mBlue\033[0m |\n"
+ "+------------+-----+-------+------+"
)
assert actual == expected
diff --git a/tests/test_build/__init__.py b/tests/test_build/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test_build/__init__.py
diff --git a/tests/test_build/test_build_border.py b/tests/test_build/test_build_border.py
index 9c410fd..1ac2d0a 100644
--- a/tests/test_build/test_build_border.py
+++ b/tests/test_build/test_build_border.py
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Test function in module."""
import pytest
@@ -6,16 +5,19 @@ from colorama import Fore, Style
from colorclass import Color
from termcolor import colored
-from terminaltables.build import build_border
+from terminaltables3.build import build_border
-@pytest.mark.parametrize('outer_widths,horizontal,left,intersect,right,expected', [
- ([5, 6, 7], '-', '<', '+', '>', '<-----+------+------->'),
- ([1, 1, 1], '-', '', '', '', '---'),
- ([1, 1, 1], '', '', '', '', ''),
- ([1], '-', '<', '+', '>', '<->'),
- ([], '-', '<', '+', '>', '<>'),
-])
+@pytest.mark.parametrize(
+ "outer_widths,horizontal,left,intersect,right,expected",
+ [
+ ([5, 6, 7], "-", "<", "+", ">", "<-----+------+------->"),
+ ([1, 1, 1], "-", "", "", "", "---"),
+ ([1, 1, 1], "", "", "", "", ""),
+ ([1], "-", "<", "+", ">", "<->"),
+ ([], "-", "<", "+", ">", "<>"),
+ ],
+)
def test_no_title(outer_widths, horizontal, left, intersect, right, expected):
"""Test without title.
@@ -27,26 +29,25 @@ def test_no_title(outer_widths, horizontal, left, intersect, right, expected):
:param str expected: Expected output.
"""
actual = build_border(outer_widths, horizontal, left, intersect, right)
- assert ''.join(actual) == expected
-
-
-@pytest.mark.parametrize('outer_widths,intersect,expected', [
- ([20], '+', 'Applications--------'),
- ([20], '', 'Applications--------'),
-
- ([15, 5], '+', 'Applications---+-----'),
- ([15, 5], '', 'Applications--------'),
-
- ([12], '+', 'Applications'),
- ([12], '', 'Applications'),
-
- ([12, 1], '+', 'Applications+-'),
- ([12, 1], '', 'Applications-'),
-
- ([12, 0], '+', 'Applications+'),
- ([12, 0], '', 'Applications'),
-])
-@pytest.mark.parametrize('left,right', [('', ''), ('<', '>')])
+ assert "".join(actual) == expected
+
+
+@pytest.mark.parametrize(
+ "outer_widths,intersect,expected",
+ [
+ ([20], "+", "Applications--------"),
+ ([20], "", "Applications--------"),
+ ([15, 5], "+", "Applications---+-----"),
+ ([15, 5], "", "Applications--------"),
+ ([12], "+", "Applications"),
+ ([12], "", "Applications"),
+ ([12, 1], "+", "Applications+-"),
+ ([12, 1], "", "Applications-"),
+ ([12, 0], "+", "Applications+"),
+ ([12, 0], "", "Applications"),
+ ],
+)
+@pytest.mark.parametrize("left,right", [("", ""), ("<", ">")])
def test_first_column_fit(outer_widths, left, intersect, right, expected):
"""Test with title that fits in the first column.
@@ -58,23 +59,28 @@ def test_first_column_fit(outer_widths, left, intersect, right, expected):
"""
if left and right:
expected = left + expected + right
- actual = build_border(outer_widths, '-', left, intersect, right, title='Applications')
- assert ''.join(actual) == expected
-
-
-@pytest.mark.parametrize('outer_widths,expected', [
- ([20], 'Applications--------'),
- ([10, 10], 'Applications--------'),
- ([5, 5, 5, 5], 'Applications--------'),
- ([3, 2, 3, 2, 3, 2, 3, 2], 'Applications--------'),
- ([1] * 20, 'Applications--------'),
- ([10, 5], 'Applications---'),
- ([9, 5], 'Applications--'),
- ([8, 5], 'Applications-'),
- ([7, 5], 'Applications'),
- ([6, 5], '-----------'),
-])
-@pytest.mark.parametrize('left,right', [('', ''), ('<', '>')])
+ actual = build_border(
+ outer_widths, "-", left, intersect, right, title="Applications"
+ )
+ assert "".join(actual) == expected
+
+
+@pytest.mark.parametrize(
+ "outer_widths,expected",
+ [
+ ([20], "Applications--------"),
+ ([10, 10], "Applications--------"),
+ ([5, 5, 5, 5], "Applications--------"),
+ ([3, 2, 3, 2, 3, 2, 3, 2], "Applications--------"),
+ ([1] * 20, "Applications--------"),
+ ([10, 5], "Applications---"),
+ ([9, 5], "Applications--"),
+ ([8, 5], "Applications-"),
+ ([7, 5], "Applications"),
+ ([6, 5], "-----------"),
+ ],
+)
+@pytest.mark.parametrize("left,right", [("", ""), ("<", ">")])
def test_no_intersect(outer_widths, left, right, expected):
"""Test with no column dividers.
@@ -85,37 +91,39 @@ def test_no_intersect(outer_widths, left, right, expected):
"""
if left and right:
expected = left + expected + right
- actual = build_border(outer_widths, '-', left, '', right, title='Applications')
- assert ''.join(actual) == expected
-
-
-@pytest.mark.parametrize('outer_widths,expected', [
- ([20], 'Applications--------'),
- ([0, 20], 'Applications---------'),
- ([20, 0], 'Applications--------+'),
- ([0, 0, 20], 'Applications----------'),
- ([20, 0, 0], 'Applications--------++'),
-
- ([10, 10], 'Applications---------'),
- ([11, 9], 'Applications---------'),
- ([12, 8], 'Applications+--------'),
- ([13, 7], 'Applications-+-------'),
-
- ([5, 5, 5, 5], 'Applications-----+-----'),
- ([4, 4, 6, 6], 'Applications----+------'),
- ([3, 3, 7, 7], 'Applications---+-------'),
- ([2, 2, 7, 9], 'Applications-+---------'),
- ([1, 1, 9, 9], 'Applications-+---------'),
-
- ([2, 2, 2, 2, 2, 2, 2], 'Applications--+--+--'),
- ([1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'Applications-+-+-+-'),
- ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'Applications++++++++'),
-
- ([2, 2, 2, 2], '--+--+--+--'),
- ([1, 1, 1, 1, 1], '-+-+-+-+-'),
- ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], '+++++++++'),
-])
-@pytest.mark.parametrize('left,right', [('', ''), ('<', '>')])
+ actual = build_border(outer_widths, "-", left, "", right, title="Applications")
+ assert "".join(actual) == expected
+
+
+@pytest.mark.parametrize(
+ "outer_widths,expected",
+ [
+ ([20], "Applications--------"),
+ ([0, 20], "Applications---------"),
+ ([20, 0], "Applications--------+"),
+ ([0, 0, 20], "Applications----------"),
+ ([20, 0, 0], "Applications--------++"),
+ ([10, 10], "Applications---------"),
+ ([11, 9], "Applications---------"),
+ ([12, 8], "Applications+--------"),
+ ([13, 7], "Applications-+-------"),
+ ([5, 5, 5, 5], "Applications-----+-----"),
+ ([4, 4, 6, 6], "Applications----+------"),
+ ([3, 3, 7, 7], "Applications---+-------"),
+ ([2, 2, 7, 9], "Applications-+---------"),
+ ([1, 1, 9, 9], "Applications-+---------"),
+ ([2, 2, 2, 2, 2, 2, 2], "Applications--+--+--"),
+ ([1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "Applications-+-+-+-"),
+ (
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "Applications++++++++",
+ ),
+ ([2, 2, 2, 2], "--+--+--+--"),
+ ([1, 1, 1, 1, 1], "-+-+-+-+-"),
+ ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "+++++++++"),
+ ],
+)
+@pytest.mark.parametrize("left,right", [("", ""), ("<", ">")])
def test_intersect(outer_widths, left, right, expected):
"""Test with column dividers.
@@ -126,48 +134,51 @@ def test_intersect(outer_widths, left, right, expected):
"""
if left and right:
expected = left + expected + right
- actual = build_border(outer_widths, '-', left, '+', right, title='Applications')
- assert ''.join(actual) == expected
-
-
-@pytest.mark.parametrize('outer_widths,intersect,expected', [
- ([12], '+', u'蓝色--------'),
- ([12], '', u'蓝色--------'),
- ([7, 5], '+', u'蓝色---+-----'),
- ([7, 5], '', u'蓝色--------'),
- ([4], '+', u'蓝色'),
- ([4], '', u'蓝色'),
- ([4, 1], '+', u'蓝色+-'),
- ([4, 1], '', u'蓝色-'),
- ([4, 0], '+', u'蓝色+'),
- ([4, 0], '', u'蓝色'),
- ([12], '', u'蓝色--------'),
- ([6, 6], '', u'蓝色--------'),
- ([3, 3, 3, 3], '', u'蓝色--------'),
- ([2, 1, 2, 1, 2, 1, 2, 1], '', u'蓝色--------'),
- ([1] * 12, '', u'蓝色--------'),
- ([2, 4], '', u'蓝色--'),
- ([1, 4], '', u'蓝色-'),
- ([1, 3], '', u'蓝色'),
- ([1, 2], '', u'---'),
- ([2], '', u'--'),
- ([12], '+', u'蓝色--------'),
- ([0, 12], '+', u'蓝色---------'),
- ([12, 0], '+', u'蓝色--------+'),
- ([0, 0, 12], '+', u'蓝色----------'),
- ([12, 0, 0], '+', u'蓝色--------++'),
- ([3, 3], '+', u'蓝色---'),
- ([4, 2], '+', u'蓝色+--'),
- ([5, 1], '+', u'蓝色-+-'),
- ([3, 3, 3, 3], '+', u'蓝色---+---+---'),
- ([2, 2, 4, 4], '+', u'蓝色-+----+----'),
- ([1, 1, 5, 5], '+', u'蓝色-----+-----'),
- ([2, 2, 2, 2], '+', u'蓝色-+--+--'),
- ([1, 1, 1, 1, 1], '+', u'蓝色-+-+-'),
- ([0, 0, 0, 0, 0, 0, 0], '+', u'蓝色++'),
- ([1, 1], '+', u'-+-'),
-])
-@pytest.mark.parametrize('left,right', [('', ''), ('<', '>')])
+ actual = build_border(outer_widths, "-", left, "+", right, title="Applications")
+ assert "".join(actual) == expected
+
+
+@pytest.mark.parametrize(
+ "outer_widths,intersect,expected",
+ [
+ ([12], "+", "蓝色--------"),
+ ([12], "", "蓝色--------"),
+ ([7, 5], "+", "蓝色---+-----"),
+ ([7, 5], "", "蓝色--------"),
+ ([4], "+", "蓝色"),
+ ([4], "", "蓝色"),
+ ([4, 1], "+", "蓝色+-"),
+ ([4, 1], "", "蓝色-"),
+ ([4, 0], "+", "蓝色+"),
+ ([4, 0], "", "蓝色"),
+ ([12], "", "蓝色--------"),
+ ([6, 6], "", "蓝色--------"),
+ ([3, 3, 3, 3], "", "蓝色--------"),
+ ([2, 1, 2, 1, 2, 1, 2, 1], "", "蓝色--------"),
+ ([1] * 12, "", "蓝色--------"),
+ ([2, 4], "", "蓝色--"),
+ ([1, 4], "", "蓝色-"),
+ ([1, 3], "", "蓝色"),
+ ([1, 2], "", "---"),
+ ([2], "", "--"),
+ ([12], "+", "蓝色--------"),
+ ([0, 12], "+", "蓝色---------"),
+ ([12, 0], "+", "蓝色--------+"),
+ ([0, 0, 12], "+", "蓝色----------"),
+ ([12, 0, 0], "+", "蓝色--------++"),
+ ([3, 3], "+", "蓝色---"),
+ ([4, 2], "+", "蓝色+--"),
+ ([5, 1], "+", "蓝色-+-"),
+ ([3, 3, 3, 3], "+", "蓝色---+---+---"),
+ ([2, 2, 4, 4], "+", "蓝色-+----+----"),
+ ([1, 1, 5, 5], "+", "蓝色-----+-----"),
+ ([2, 2, 2, 2], "+", "蓝色-+--+--"),
+ ([1, 1, 1, 1, 1], "+", "蓝色-+-+-"),
+ ([0, 0, 0, 0, 0, 0, 0], "+", "蓝色++"),
+ ([1, 1], "+", "-+-"),
+ ],
+)
+@pytest.mark.parametrize("left,right", [("", ""), ("<", ">")])
def test_cjk(outer_widths, left, intersect, right, expected):
"""Test with CJK characters in title.
@@ -179,48 +190,51 @@ def test_cjk(outer_widths, left, intersect, right, expected):
"""
if left and right:
expected = left + expected + right
- actual = build_border(outer_widths, '-', left, intersect, right, title=u'蓝色')
- assert ''.join(actual) == expected
-
-
-@pytest.mark.parametrize('outer_widths,intersect,expected', [
- ([12], '+', u'معرب--------'),
- ([12], '', u'معرب--------'),
- ([7, 5], '+', u'معرب---+-----'),
- ([7, 5], '', u'معرب--------'),
- ([4], '+', u'معرب'),
- ([4], '', u'معرب'),
- ([4, 1], '+', u'معرب+-'),
- ([4, 1], '', u'معرب-'),
- ([4, 0], '+', u'معرب+'),
- ([4, 0], '', u'معرب'),
- ([12], '', u'معرب--------'),
- ([6, 6], '', u'معرب--------'),
- ([3, 3, 3, 3], '', u'معرب--------'),
- ([2, 1, 2, 1, 2, 1, 2, 1], '', u'معرب--------'),
- ([1] * 12, '', u'معرب--------'),
- ([2, 4], '', u'معرب--'),
- ([1, 4], '', u'معرب-'),
- ([1, 3], '', u'معرب'),
- ([1, 2], '', u'---'),
- ([2], '', u'--'),
- ([12], '+', u'معرب--------'),
- ([0, 12], '+', u'معرب---------'),
- ([12, 0], '+', u'معرب--------+'),
- ([0, 0, 12], '+', u'معرب----------'),
- ([12, 0, 0], '+', u'معرب--------++'),
- ([3, 3], '+', u'معرب---'),
- ([4, 2], '+', u'معرب+--'),
- ([5, 1], '+', u'معرب-+-'),
- ([3, 3, 3, 3], '+', u'معرب---+---+---'),
- ([2, 2, 4, 4], '+', u'معرب-+----+----'),
- ([1, 1, 5, 5], '+', u'معرب-----+-----'),
- ([2, 2, 2, 2], '+', u'معرب-+--+--'),
- ([1, 1, 1, 1, 1], '+', u'معرب-+-+-'),
- ([0, 0, 0, 0, 0, 0, 0], '+', u'معرب++'),
- ([1, 1], '+', u'-+-'),
-])
-@pytest.mark.parametrize('left,right', [('', ''), ('<', '>')])
+ actual = build_border(outer_widths, "-", left, intersect, right, title="蓝色")
+ assert "".join(actual) == expected
+
+
+@pytest.mark.parametrize(
+ "outer_widths,intersect,expected",
+ [
+ ([12], "+", "معرب--------"),
+ ([12], "", "معرب--------"),
+ ([7, 5], "+", "معرب---+-----"),
+ ([7, 5], "", "معرب--------"),
+ ([4], "+", "معرب"),
+ ([4], "", "معرب"),
+ ([4, 1], "+", "معرب+-"),
+ ([4, 1], "", "معرب-"),
+ ([4, 0], "+", "معرب+"),
+ ([4, 0], "", "معرب"),
+ ([12], "", "معرب--------"),
+ ([6, 6], "", "معرب--------"),
+ ([3, 3, 3, 3], "", "معرب--------"),
+ ([2, 1, 2, 1, 2, 1, 2, 1], "", "معرب--------"),
+ ([1] * 12, "", "معرب--------"),
+ ([2, 4], "", "معرب--"),
+ ([1, 4], "", "معرب-"),
+ ([1, 3], "", "معرب"),
+ ([1, 2], "", "---"),
+ ([2], "", "--"),
+ ([12], "+", "معرب--------"),
+ ([0, 12], "+", "معرب---------"),
+ ([12, 0], "+", "معرب--------+"),
+ ([0, 0, 12], "+", "معرب----------"),
+ ([12, 0, 0], "+", "معرب--------++"),
+ ([3, 3], "+", "معرب---"),
+ ([4, 2], "+", "معرب+--"),
+ ([5, 1], "+", "معرب-+-"),
+ ([3, 3, 3, 3], "+", "معرب---+---+---"),
+ ([2, 2, 4, 4], "+", "معرب-+----+----"),
+ ([1, 1, 5, 5], "+", "معرب-----+-----"),
+ ([2, 2, 2, 2], "+", "معرب-+--+--"),
+ ([1, 1, 1, 1, 1], "+", "معرب-+-+-"),
+ ([0, 0, 0, 0, 0, 0, 0], "+", "معرب++"),
+ ([1, 1], "+", "-+-"),
+ ],
+)
+@pytest.mark.parametrize("left,right", [("", ""), ("<", ">")])
def test_rtl(outer_widths, left, intersect, right, expected):
"""Test with RTL characters in title.
@@ -232,53 +246,59 @@ def test_rtl(outer_widths, left, intersect, right, expected):
"""
if left and right:
expected = left + expected + right
- actual = build_border(outer_widths, '-', left, intersect, right, title=u'معرب')
- assert ''.join(actual) == expected
-
-
-@pytest.mark.parametrize('outer_widths,intersect,expected', [
- ([12], '+', '\x1b[34mTEST\x1b[0m--------'),
- ([12], '', '\x1b[34mTEST\x1b[0m--------'),
- ([7, 5], '+', '\x1b[34mTEST\x1b[0m---+-----'),
- ([7, 5], '', '\x1b[34mTEST\x1b[0m--------'),
- ([4], '+', '\x1b[34mTEST\x1b[0m'),
- ([4], '', '\x1b[34mTEST\x1b[0m'),
- ([4, 1], '+', '\x1b[34mTEST\x1b[0m+-'),
- ([4, 1], '', '\x1b[34mTEST\x1b[0m-'),
- ([4, 0], '+', '\x1b[34mTEST\x1b[0m+'),
- ([4, 0], '', '\x1b[34mTEST\x1b[0m'),
- ([12], '', '\x1b[34mTEST\x1b[0m--------'),
- ([6, 6], '', '\x1b[34mTEST\x1b[0m--------'),
- ([3, 3, 3, 3], '', '\x1b[34mTEST\x1b[0m--------'),
- ([2, 1, 2, 1, 2, 1, 2, 1], '', '\x1b[34mTEST\x1b[0m--------'),
- ([1] * 12, '', '\x1b[34mTEST\x1b[0m--------'),
- ([2, 4], '', '\x1b[34mTEST\x1b[0m--'),
- ([1, 4], '', '\x1b[34mTEST\x1b[0m-'),
- ([1, 3], '', '\x1b[34mTEST\x1b[0m'),
- ([1, 2], '', '---'),
- ([12], '+', '\x1b[34mTEST\x1b[0m--------'),
- ([0, 12], '+', '\x1b[34mTEST\x1b[0m---------'),
- ([12, 0], '+', '\x1b[34mTEST\x1b[0m--------+'),
- ([0, 0, 12], '+', '\x1b[34mTEST\x1b[0m----------'),
- ([12, 0, 0], '+', '\x1b[34mTEST\x1b[0m--------++'),
- ([3, 3], '+', '\x1b[34mTEST\x1b[0m---'),
- ([4, 2], '+', '\x1b[34mTEST\x1b[0m+--'),
- ([5, 1], '+', '\x1b[34mTEST\x1b[0m-+-'),
- ([3, 3, 3, 3], '+', '\x1b[34mTEST\x1b[0m---+---+---'),
- ([2, 2, 4, 4], '+', '\x1b[34mTEST\x1b[0m-+----+----'),
- ([1, 1, 5, 5], '+', '\x1b[34mTEST\x1b[0m-----+-----'),
- ([2, 2, 2, 2], '+', '\x1b[34mTEST\x1b[0m-+--+--'),
- ([1, 1, 1, 1, 1], '+', '\x1b[34mTEST\x1b[0m-+-+-'),
- ([0, 0, 0, 0, 0, 0, 0], '+', '\x1b[34mTEST\x1b[0m++'),
- ([1, 1], '+', '-+-'),
-])
-@pytest.mark.parametrize('left,right', [('', ''), ('<', '>')])
-@pytest.mark.parametrize('title', [
- '\x1b[34mTEST\x1b[0m',
- Color('{blue}TEST{/all}'),
- Fore.BLUE + 'TEST' + Style.RESET_ALL,
- colored('TEST', 'blue'),
-])
+ actual = build_border(outer_widths, "-", left, intersect, right, title="معرب")
+ assert "".join(actual) == expected
+
+
+@pytest.mark.parametrize(
+ "outer_widths,intersect,expected",
+ [
+ ([12], "+", "\x1b[34mTEST\x1b[0m--------"),
+ ([12], "", "\x1b[34mTEST\x1b[0m--------"),
+ ([7, 5], "+", "\x1b[34mTEST\x1b[0m---+-----"),
+ ([7, 5], "", "\x1b[34mTEST\x1b[0m--------"),
+ ([4], "+", "\x1b[34mTEST\x1b[0m"),
+ ([4], "", "\x1b[34mTEST\x1b[0m"),
+ ([4, 1], "+", "\x1b[34mTEST\x1b[0m+-"),
+ ([4, 1], "", "\x1b[34mTEST\x1b[0m-"),
+ ([4, 0], "+", "\x1b[34mTEST\x1b[0m+"),
+ ([4, 0], "", "\x1b[34mTEST\x1b[0m"),
+ ([12], "", "\x1b[34mTEST\x1b[0m--------"),
+ ([6, 6], "", "\x1b[34mTEST\x1b[0m--------"),
+ ([3, 3, 3, 3], "", "\x1b[34mTEST\x1b[0m--------"),
+ ([2, 1, 2, 1, 2, 1, 2, 1], "", "\x1b[34mTEST\x1b[0m--------"),
+ ([1] * 12, "", "\x1b[34mTEST\x1b[0m--------"),
+ ([2, 4], "", "\x1b[34mTEST\x1b[0m--"),
+ ([1, 4], "", "\x1b[34mTEST\x1b[0m-"),
+ ([1, 3], "", "\x1b[34mTEST\x1b[0m"),
+ ([1, 2], "", "---"),
+ ([12], "+", "\x1b[34mTEST\x1b[0m--------"),
+ ([0, 12], "+", "\x1b[34mTEST\x1b[0m---------"),
+ ([12, 0], "+", "\x1b[34mTEST\x1b[0m--------+"),
+ ([0, 0, 12], "+", "\x1b[34mTEST\x1b[0m----------"),
+ ([12, 0, 0], "+", "\x1b[34mTEST\x1b[0m--------++"),
+ ([3, 3], "+", "\x1b[34mTEST\x1b[0m---"),
+ ([4, 2], "+", "\x1b[34mTEST\x1b[0m+--"),
+ ([5, 1], "+", "\x1b[34mTEST\x1b[0m-+-"),
+ ([3, 3, 3, 3], "+", "\x1b[34mTEST\x1b[0m---+---+---"),
+ ([2, 2, 4, 4], "+", "\x1b[34mTEST\x1b[0m-+----+----"),
+ ([1, 1, 5, 5], "+", "\x1b[34mTEST\x1b[0m-----+-----"),
+ ([2, 2, 2, 2], "+", "\x1b[34mTEST\x1b[0m-+--+--"),
+ ([1, 1, 1, 1, 1], "+", "\x1b[34mTEST\x1b[0m-+-+-"),
+ ([0, 0, 0, 0, 0, 0, 0], "+", "\x1b[34mTEST\x1b[0m++"),
+ ([1, 1], "+", "-+-"),
+ ],
+)
+@pytest.mark.parametrize("left,right", [("", ""), ("<", ">")])
+@pytest.mark.parametrize(
+ "title",
+ [
+ "\x1b[34mTEST\x1b[0m",
+ Color("{blue}TEST{/all}"),
+ Fore.BLUE + "TEST" + Style.RESET_ALL,
+ colored("TEST", "blue"),
+ ],
+)
def test_colors(outer_widths, left, intersect, right, title, expected):
"""Test with color title characters.
@@ -291,16 +311,19 @@ def test_colors(outer_widths, left, intersect, right, title, expected):
"""
if left and right:
expected = left + expected + right
- actual = build_border(outer_widths, '-', left, intersect, right, title=title)
- assert ''.join(actual) == expected
-
-
-@pytest.mark.parametrize('outer_widths,title,expected', [
- ([3, 3, 3], 123, '<123+---+--->'),
- ([3, 3, 3], 0.9, '<0.9+---+--->'),
- ([3, 3, 3], True, '<True---+--->'),
- ([3, 3, 3], False, '<False--+--->'),
-])
+ actual = build_border(outer_widths, "-", left, intersect, right, title=title)
+ assert "".join(actual) == expected
+
+
+@pytest.mark.parametrize(
+ "outer_widths,title,expected",
+ [
+ ([3, 3, 3], 123, "<123+---+--->"),
+ ([3, 3, 3], 0.9, "<0.9+---+--->"),
+ ([3, 3, 3], True, "<True---+--->"),
+ ([3, 3, 3], False, "<False--+--->"),
+ ],
+)
def test_non_string(outer_widths, title, expected):
"""Test with non-string values.
@@ -308,5 +331,5 @@ def test_non_string(outer_widths, title, expected):
:param title: Title in border.
:param str expected: Expected output.
"""
- actual = build_border(outer_widths, '-', '<', '+', '>', title=title)
- assert ''.join(actual) == expected
+ actual = build_border(outer_widths, "-", "<", "+", ">", title=title)
+ assert "".join(actual) == expected
diff --git a/tests/test_build/test_build_row.py b/tests/test_build/test_build_row.py
index ce55944..93aaf37 100644
--- a/tests/test_build/test_build_row.py
+++ b/tests/test_build/test_build_row.py
@@ -1,16 +1,18 @@
"""Test function in module."""
-from terminaltables.build import build_row
+from terminaltables3.build import build_row
def test_one_line():
"""Test with one line cells."""
row = [
- ['Left Cell'], ['Center Cell'], ['Right Cell'],
+ ["Left Cell"],
+ ["Center Cell"],
+ ["Right Cell"],
]
- actual = [tuple(i) for i in build_row(row, '>', '|', '<')]
+ actual = [tuple(i) for i in build_row(row, ">", "|", "<")]
expected = [
- ('>', 'Left Cell', '|', 'Center Cell', '|', 'Right Cell', '<'),
+ (">", "Left Cell", "|", "Center Cell", "|", "Right Cell", "<"),
]
assert actual == expected
@@ -19,24 +21,22 @@ def test_two_line():
"""Test with two line cells."""
row = [
[
- 'Left ',
- 'Cell1',
+ "Left ",
+ "Cell1",
],
-
[
- 'Center',
- 'Cell2 ',
+ "Center",
+ "Cell2 ",
],
-
[
- 'Right',
- 'Cell3',
+ "Right",
+ "Cell3",
],
]
- actual = [tuple(i) for i in build_row(row, '>', '|', '<')]
+ actual = [tuple(i) for i in build_row(row, ">", "|", "<")]
expected = [
- ('>', 'Left ', '|', 'Center', '|', 'Right', '<'),
- ('>', 'Cell1', '|', 'Cell2 ', '|', 'Cell3', '<'),
+ (">", "Left ", "|", "Center", "|", "Right", "<"),
+ (">", "Cell1", "|", "Cell2 ", "|", "Cell3", "<"),
]
assert actual == expected
@@ -45,60 +45,58 @@ def test_three_line():
"""Test with three line cells."""
row = [
[
- 'Left ',
- 'Cell1',
- ' ',
+ "Left ",
+ "Cell1",
+ " ",
],
-
[
- 'Center',
- 'Cell2 ',
- ' ',
+ "Center",
+ "Cell2 ",
+ " ",
],
-
[
- 'Right',
- 'Cell3',
- ' ',
+ "Right",
+ "Cell3",
+ " ",
],
]
- actual = [tuple(i) for i in build_row(row, '>', '|', '<')]
+ actual = [tuple(i) for i in build_row(row, ">", "|", "<")]
expected = [
- ('>', 'Left ', '|', 'Center', '|', 'Right', '<'),
- ('>', 'Cell1', '|', 'Cell2 ', '|', 'Cell3', '<'),
- ('>', ' ', '|', ' ', '|', ' ', '<'),
+ (">", "Left ", "|", "Center", "|", "Right", "<"),
+ (">", "Cell1", "|", "Cell2 ", "|", "Cell3", "<"),
+ (">", " ", "|", " ", "|", " ", "<"),
]
assert actual == expected
def test_single():
"""Test with single cell."""
- actual = [tuple(i) for i in build_row([['Cell']], '>', '|', '<')]
+ actual = [tuple(i) for i in build_row([["Cell"]], ">", "|", "<")]
expected = [
- ('>', 'Cell', '<'),
+ (">", "Cell", "<"),
]
assert actual == expected
def test_empty():
"""Test with empty cell."""
- actual = [tuple(i) for i in build_row([['']], '>', '|', '<')]
+ actual = [tuple(i) for i in build_row([[""]], ">", "|", "<")]
expected = [
- ('>', '', '<'),
+ (">", "", "<"),
]
assert actual == expected
def test_no_cells():
"""Test with no cells."""
- actual = [tuple(i) for i in build_row([[]], '>', '|', '<')]
+ actual = [tuple(i) for i in build_row([[]], ">", "|", "<")]
expected = [
- ('>', '<'),
+ (">", "<"),
]
assert actual == expected
- actual = [tuple(i) for i in build_row([], '>', '|', '<')]
+ actual = [tuple(i) for i in build_row([], ">", "|", "<")]
expected = [
- ('>', '<'),
+ (">", "<"),
]
assert actual == expected
diff --git a/tests/test_build/test_combine.py b/tests/test_build/test_combine.py
index b296ffd..a96d302 100644
--- a/tests/test_build/test_combine.py
+++ b/tests/test_build/test_combine.py
@@ -2,36 +2,36 @@
import pytest
-from terminaltables.build import combine
+from terminaltables3.build import combine
-@pytest.mark.parametrize('generator', [False, True])
+@pytest.mark.parametrize("generator", [False, True])
def test_borders(generator):
"""Test with borders.
:param bool generator: Test with generator instead of list.
"""
- line = ['One', 'Two', 'Three']
- actual = list(combine(iter(line) if generator else line, '>', '|', '<'))
- assert actual == ['>', 'One', '|', 'Two', '|', 'Three', '<']
+ line = ["One", "Two", "Three"]
+ actual = list(combine(iter(line) if generator else line, ">", "|", "<"))
+ assert actual == [">", "One", "|", "Two", "|", "Three", "<"]
-@pytest.mark.parametrize('generator', [False, True])
+@pytest.mark.parametrize("generator", [False, True])
def test_no_border(generator):
"""Test without borders.
:param bool generator: Test with generator instead of list.
"""
- line = ['One', 'Two', 'Three']
- actual = list(combine(iter(line) if generator else line, '', '', ''))
- assert actual == ['One', 'Two', 'Three']
+ line = ["One", "Two", "Three"]
+ actual = list(combine(iter(line) if generator else line, "", "", ""))
+ assert actual == ["One", "Two", "Three"]
-@pytest.mark.parametrize('generator', [False, True])
+@pytest.mark.parametrize("generator", [False, True])
def test_no_items(generator):
"""Test with empty list.
:param bool generator: Test with generator instead of list.
"""
- actual = list(combine(iter([]) if generator else [], '>', '|', '<'))
- assert actual == ['>', '<']
+ actual = list(combine(iter([]) if generator else [], ">", "|", "<"))
+ assert actual == [">", "<"]
diff --git a/tests/test_build/test_flatten.py b/tests/test_build/test_flatten.py
index aacfdbd..44e1e18 100644
--- a/tests/test_build/test_flatten.py
+++ b/tests/test_build/test_flatten.py
@@ -1,25 +1,24 @@
"""Test function in module."""
-from terminaltables.build import flatten
+from terminaltables3.build import flatten
def test_one_line():
"""Test with one line cells."""
table = [
- ['>', 'Left Cell', '|', 'Center Cell', '|', 'Right Cell', '<'],
+ [">", "Left Cell", "|", "Center Cell", "|", "Right Cell", "<"],
]
actual = flatten(table)
- expected = '>Left Cell|Center Cell|Right Cell<'
+ expected = ">Left Cell|Center Cell|Right Cell<"
assert actual == expected
def test_two_line():
"""Test with two line cells."""
table = [
- ['>', 'Left ', '|', 'Center', '|', 'Right', '<'],
- ['>', 'Cell1', '|', 'Cell2 ', '|', 'Cell3', '<'],
+ [">", "Left ", "|", "Center", "|", "Right", "<"],
+ [">", "Cell1", "|", "Cell2 ", "|", "Cell3", "<"],
]
actual = flatten(table)
- expected = ('>Left |Center|Right<\n'
- '>Cell1|Cell2 |Cell3<')
+ expected = ">Left |Center|Right<\n" ">Cell1|Cell2 |Cell3<"
assert actual == expected
diff --git a/tests/test_examples.py b/tests/test_examples.py
index f0799f9..d882890 100644
--- a/tests/test_examples.py
+++ b/tests/test_examples.py
@@ -1,7 +1,5 @@
"""Test example scripts."""
-from __future__ import print_function
-
import os
import subprocess
import sys
@@ -11,17 +9,19 @@ import pytest
from tests import PROJECT_ROOT
-@pytest.mark.parametrize('filename', map('example{0}.py'.format, (1, 2, 3)))
+@pytest.mark.parametrize("filename", map("example{}.py".format, (1, 2, 3)))
def test(filename):
"""Test with subprocess.
:param str filename: Example script filename to run.
"""
command = [sys.executable, str(PROJECT_ROOT.join(filename))]
- env = dict(os.environ, PYTHONIOENCODING='utf-8')
+ env = dict(os.environ, PYTHONIOENCODING="utf-8")
# Run.
- proc = subprocess.Popen(command, env=env, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+ proc = subprocess.Popen(
+ command, env=env, stderr=subprocess.STDOUT, stdout=subprocess.PIPE
+ )
output = proc.communicate()[0]
# Verify.
diff --git a/tests/test_terminal_io/__init__.py b/tests/test_terminal_io/__init__.py
index 93738fc..f8200f0 100644
--- a/tests/test_terminal_io/__init__.py
+++ b/tests/test_terminal_io/__init__.py
@@ -1,17 +1,21 @@
"""Common objects used by tests in directory."""
-from terminaltables import terminal_io
+from terminaltables3 import terminal_io
-class MockKernel32(object):
+class MockKernel32:
"""Mock kernel32."""
- def __init__(self, stderr=terminal_io.INVALID_HANDLE_VALUE, stdout=terminal_io.INVALID_HANDLE_VALUE):
+ def __init__(
+ self,
+ stderr=terminal_io.INVALID_HANDLE_VALUE,
+ stdout=terminal_io.INVALID_HANDLE_VALUE,
+ ):
"""Constructor."""
self.stderr = stderr
self.stdout = stdout
- self.csbi_err = b'x\x00)#\x00\x00\x87\x05\x07\x00\x00\x00j\x05w\x00\x87\x05x\x00J\x00' # 119 x 29
- self.csbi_out = b'L\x00,\x01\x00\x00*\x01\x07\x00\x00\x00\x0e\x01K\x00*\x01L\x00L\x00' # 75 x 28
+ self.csbi_err = b"x\x00)#\x00\x00\x87\x05\x07\x00\x00\x00j\x05w\x00\x87\x05x\x00J\x00" # 119 x 29
+ self.csbi_out = b"L\x00,\x01\x00\x00*\x01\x07\x00\x00\x00\x0e\x01K\x00*\x01L\x00L\x00" # 75 x 28
self.setConsoleTitleA_called = False
self.setConsoleTitleW_called = False
diff --git a/tests/test_terminal_io/test_get_console_info.py b/tests/test_terminal_io/test_get_console_info.py
index 1a9b98f..522613e 100644
--- a/tests/test_terminal_io/test_get_console_info.py
+++ b/tests/test_terminal_io/test_get_console_info.py
@@ -1,11 +1,14 @@
-# coding: utf-8
"""Test function in module."""
import ctypes
import pytest
-from terminaltables.terminal_io import get_console_info, INVALID_HANDLE_VALUE, IS_WINDOWS
+from terminaltables3.terminal_io import (
+ get_console_info,
+ INVALID_HANDLE_VALUE,
+ IS_WINDOWS,
+)
from tests.test_terminal_io import MockKernel32
diff --git a/tests/test_terminal_io/test_set_terminal_title.py b/tests/test_terminal_io/test_set_terminal_title.py
index 38980be..297325b 100644
--- a/tests/test_terminal_io/test_set_terminal_title.py
+++ b/tests/test_terminal_io/test_set_terminal_title.py
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Test function in module."""
import sys
@@ -7,7 +6,7 @@ from textwrap import dedent
import py
import pytest
-from terminaltables.terminal_io import IS_WINDOWS, set_terminal_title
+from terminaltables3.terminal_io import IS_WINDOWS, set_terminal_title
from tests import PROJECT_ROOT
from tests.screenshot import RunNewConsole, screenshot_until_match
@@ -15,9 +14,10 @@ from tests.test_terminal_io import MockKernel32
HERE = py.path.local(__file__).dirpath()
+
@pytest.mark.skip("Fails on windows, I didn't touch it")
-@pytest.mark.parametrize('is_windows', [False, True])
-@pytest.mark.parametrize('mode', ['ascii', 'unicode', 'bytes'])
+@pytest.mark.parametrize("is_windows", [False, True])
+@pytest.mark.parametrize("mode", ["ascii", "unicode", "bytes"])
def test(monkeypatch, is_windows, mode):
"""Test function.
@@ -25,16 +25,16 @@ def test(monkeypatch, is_windows, mode):
:param bool is_windows: Monkeypatch terminal_io.IS_WINDOWS
:param str mode: Scenario to test for.
"""
- monkeypatch.setattr('terminaltables.terminal_io.IS_WINDOWS', is_windows)
+ monkeypatch.setattr("terminaltables3.terminal_io.IS_WINDOWS", is_windows)
kernel32 = MockKernel32()
# Title.
- if mode == 'ascii':
- title = 'Testing terminaltables.'
- elif mode == 'unicode':
- title = u'Testing terminaltables with unicode: 世界你好蓝色'
+ if mode == "ascii":
+ title = "Testing terminaltables3."
+ elif mode == "unicode":
+ title = "Testing terminaltables3 with unicode: 世界你好蓝色"
else:
- title = b'Testing terminaltables with bytes.'
+ title = b"Testing terminaltables3 with bytes."
# Run.
assert set_terminal_title(title, kernel32)
@@ -42,10 +42,10 @@ def test(monkeypatch, is_windows, mode):
return
# Verify.
- if mode == 'ascii':
+ if mode == "ascii":
assert kernel32.setConsoleTitleA_called
assert not kernel32.setConsoleTitleW_called
- elif mode == 'unicode':
+ elif mode == "unicode":
assert not kernel32.setConsoleTitleA_called
assert kernel32.setConsoleTitleW_called
else:
@@ -54,35 +54,36 @@ def test(monkeypatch, is_windows, mode):
@pytest.mark.skipif(str(not IS_WINDOWS))
-@pytest.mark.parametrize('mode', ['ascii', 'unicode', 'bytes'])
-@pytest.mark.skip # https://github.com/Robpol86/terminaltables/issues/44
+@pytest.mark.parametrize("mode", ["ascii", "unicode", "bytes"])
+@pytest.mark.skip # https://github.com/Robpol86/terminaltables3/issues/44
def test_windows_screenshot(tmpdir, mode):
"""Test function on Windows in a new console window. Take a screenshot to verify it works.
:param tmpdir: pytest fixture.
:param str mode: Scenario to test for.
"""
- script = tmpdir.join('script.py')
+ script = tmpdir.join("script.py")
command = [sys.executable, str(script)]
- change_title = tmpdir.join('change_title')
- screenshot = PROJECT_ROOT.join('test_terminal_io_{0}.png'.format(mode))
+ change_title = tmpdir.join("change_title")
+ screenshot = PROJECT_ROOT.join(f"test_terminal_io_{mode}.png")
if screenshot.check():
screenshot.remove()
# Determine title.
- if mode == 'ascii':
+ if mode == "ascii":
title = "'test ASCII test'"
- elif mode == 'unicode':
- title = u"u'test 世界你好蓝色 test'"
+ elif mode == "unicode":
+ title = "u'test 世界你好蓝色 test'"
else:
title = "b'test ASCII test'"
# Generate script.
- script_template = dedent(u"""\
+ script_template = dedent(
+ """\
# coding: utf-8
from __future__ import print_function
import os, time
- from terminaltables.terminal_io import set_terminal_title
+ from terminaltables3.terminal_io import set_terminal_title
stop_after = time.time() + 20
print('Waiting for FindWindowA() in RunNewConsole.__enter__()...')
@@ -93,15 +94,18 @@ def test_windows_screenshot(tmpdir, mode):
print('Waiting for screenshot_until_match()...')
while not os.path.exists(r'{screenshot}') and time.time() < stop_after:
time.sleep(0.5)
- """)
- script_contents = script_template.format(change_title=str(change_title), title=title, screenshot=str(screenshot))
- script.write(script_contents.encode('utf-8'), mode='wb')
+ """
+ )
+ script_contents = script_template.format(
+ change_title=str(change_title), title=title, screenshot=str(screenshot)
+ )
+ script.write(script_contents.encode("utf-8"), mode="wb")
# Setup expected.
- if mode == 'unicode':
- sub_images = [str(p) for p in HERE.listdir('sub_title_cjk_*.bmp')]
+ if mode == "unicode":
+ sub_images = [str(p) for p in HERE.listdir("sub_title_cjk_*.bmp")]
else:
- sub_images = [str(p) for p in HERE.listdir('sub_title_ascii_*.bmp')]
+ sub_images = [str(p) for p in HERE.listdir("sub_title_ascii_*.bmp")]
assert sub_images
# Run.
diff --git a/tests/test_terminal_io/test_terminal_size.py b/tests/test_terminal_io/test_terminal_size.py
index ba14d18..69945a3 100644
--- a/tests/test_terminal_io/test_terminal_size.py
+++ b/tests/test_terminal_io/test_terminal_size.py
@@ -1,15 +1,20 @@
-# coding: utf-8
"""Test function in module."""
import pytest
-from terminaltables.terminal_io import DEFAULT_HEIGHT, DEFAULT_WIDTH, INVALID_HANDLE_VALUE, IS_WINDOWS, terminal_size
+from terminaltables3.terminal_io import (
+ DEFAULT_HEIGHT,
+ DEFAULT_WIDTH,
+ INVALID_HANDLE_VALUE,
+ IS_WINDOWS,
+ terminal_size,
+)
from tests.test_terminal_io import MockKernel32
-@pytest.mark.parametrize('stderr', [1, INVALID_HANDLE_VALUE])
-@pytest.mark.parametrize('stdout', [2, INVALID_HANDLE_VALUE])
+@pytest.mark.parametrize("stderr", [1, INVALID_HANDLE_VALUE])
+@pytest.mark.parametrize("stdout", [2, INVALID_HANDLE_VALUE])
def test_windows(monkeypatch, stderr, stdout):
"""Test function with IS_WINDOWS=True.
@@ -17,7 +22,7 @@ def test_windows(monkeypatch, stderr, stdout):
:param int stderr: Mock handle value.
:param int stdout: Mock handle value.
"""
- monkeypatch.setattr('terminaltables.terminal_io.IS_WINDOWS', True)
+ monkeypatch.setattr("terminaltables3.terminal_io.IS_WINDOWS", True)
kernel32 = MockKernel32(stderr=stderr, stdout=stdout)
width, height = terminal_size(kernel32)
@@ -48,7 +53,7 @@ def test_nix(monkeypatch):
assert height == DEFAULT_HEIGHT
# Test mocked.
- monkeypatch.setattr('fcntl.ioctl', lambda *_: b'\x1d\x00w\x00\xca\x02\x96\x01')
+ monkeypatch.setattr("fcntl.ioctl", lambda *_: b"\x1d\x00w\x00\xca\x02\x96\x01")
width, height = terminal_size()
assert width == 119
assert height == 29
diff --git a/tests/test_width_and_alignment/__init__.py b/tests/test_width_and_alignment/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test_width_and_alignment/__init__.py
diff --git a/tests/test_width_and_alignment/test_align_and_pad_cell.py b/tests/test_width_and_alignment/test_align_and_pad_cell.py
index e0a928e..b0c441b 100644
--- a/tests/test_width_and_alignment/test_align_and_pad_cell.py
+++ b/tests/test_width_and_alignment/test_align_and_pad_cell.py
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Test function in module."""
import pytest
@@ -6,75 +5,74 @@ from colorama import Fore
from colorclass import Color
from termcolor import colored
-from terminaltables.width_and_alignment import align_and_pad_cell
-
-
-@pytest.mark.parametrize('string,align,width,expected', [
- ('test', '', 4, ['test']),
- (123, '', 3, ['123']),
- (0.9, '', 3, ['0.9']),
- (None, '', 4, ['None']),
- (True, '', 4, ['True']),
- (False, '', 5, ['False']),
- (Color('{blue}Test{/blue}'), '', 4, ['\x1b[34mTest\x1b[39m']),
- (Fore.BLUE + 'Test' + Fore.RESET, '', 4, ['\x1b[34mTest\x1b[39m']),
- (colored('Test', 'blue'), '', 4, ['\x1b[34mTest\x1b[0m']),
- ('蓝色', '', 4, ['蓝色']),
- (u'שלום', '', 4, [u'\u05e9\u05dc\u05d5\u05dd']),
- (u'معرب', '', 4, [u'\u0645\u0639\u0631\u0628']),
-
- ('test', '', 5, ['test ']),
- (123, '', 4, ['123 ']),
- (0.9, '', 4, ['0.9 ']),
- (None, '', 5, ['None ']),
- (True, '', 5, ['True ']),
- (False, '', 6, ['False ']),
- (Color('{blue}Test{/blue}'), '', 5, ['\x1b[34mTest\x1b[39m ']),
- (Fore.BLUE + 'Test' + Fore.RESET, '', 5, ['\x1b[34mTest\x1b[39m ']),
- (colored('Test', 'blue'), '', 5, ['\x1b[34mTest\x1b[0m ']),
- ('蓝色', '', 5, ['蓝色 ']),
- (u'שלום', '', 5, [u'\u05e9\u05dc\u05d5\u05dd ']),
- (u'معرب', '', 5, [u'\u0645\u0639\u0631\u0628 ']),
-
- ('test', 'left', 5, ['test ']),
- (123, 'left', 4, ['123 ']),
- (0.9, 'left', 4, ['0.9 ']),
- (None, 'left', 5, ['None ']),
- (True, 'left', 5, ['True ']),
- (False, 'left', 6, ['False ']),
- (Color('{blue}Test{/blue}'), 'left', 5, ['\x1b[34mTest\x1b[39m ']),
- (Fore.BLUE + 'Test' + Fore.RESET, 'left', 5, ['\x1b[34mTest\x1b[39m ']),
- (colored('Test', 'blue'), 'left', 5, ['\x1b[34mTest\x1b[0m ']),
- ('蓝色', 'left', 5, ['蓝色 ']),
- (u'שלום', 'left', 5, [u'\u05e9\u05dc\u05d5\u05dd ']),
- (u'معرب', 'left', 5, [u'\u0645\u0639\u0631\u0628 ']),
-
- ('test', 'right', 5, [' test']),
- (123, 'right', 4, [' 123']),
- (0.9, 'right', 4, [' 0.9']),
- (None, 'right', 5, [' None']),
- (True, 'right', 5, [' True']),
- (False, 'right', 6, [' False']),
- (Color('{blue}Test{/blue}'), 'right', 5, [' \x1b[34mTest\x1b[39m']),
- (Fore.BLUE + 'Test' + Fore.RESET, 'right', 5, [' \x1b[34mTest\x1b[39m']),
- (colored('Test', 'blue'), 'right', 5, [' \x1b[34mTest\x1b[0m']),
- ('蓝色', 'right', 5, [' 蓝色']),
- (u'שלום', 'right', 5, [u' \u05e9\u05dc\u05d5\u05dd']),
- (u'معرب', 'right', 5, [u' \u0645\u0639\u0631\u0628']),
-
- ('test', 'center', 6, [' test ']),
- (123, 'center', 5, [' 123 ']),
- (0.9, 'center', 5, [' 0.9 ']),
- (None, 'center', 6, [' None ']),
- (True, 'center', 6, [' True ']),
- (False, 'center', 7, [' False ']),
- (Color('{blue}Test{/blue}'), 'center', 6, [' \x1b[34mTest\x1b[39m ']),
- (Fore.BLUE + 'Test' + Fore.RESET, 'center', 6, [' \x1b[34mTest\x1b[39m ']),
- (colored('Test', 'blue'), 'center', 6, [' \x1b[34mTest\x1b[0m ']),
- ('蓝色', 'center', 6, [' 蓝色 ']),
- (u'שלום', 'center', 6, [u' \u05e9\u05dc\u05d5\u05dd ']),
- (u'معرب', 'center', 6, [u' \u0645\u0639\u0631\u0628 ']),
-])
+from terminaltables3.width_and_alignment import align_and_pad_cell
+
+
+@pytest.mark.parametrize(
+ "string,align,width,expected",
+ [
+ ("test", "", 4, ["test"]),
+ (123, "", 3, ["123"]),
+ (0.9, "", 3, ["0.9"]),
+ (None, "", 4, ["None"]),
+ (True, "", 4, ["True"]),
+ (False, "", 5, ["False"]),
+ (Color("{blue}Test{/blue}"), "", 4, ["\x1b[34mTest\x1b[39m"]),
+ (Fore.BLUE + "Test" + Fore.RESET, "", 4, ["\x1b[34mTest\x1b[39m"]),
+ (colored("Test", "blue"), "", 4, ["\x1b[34mTest\x1b[0m"]),
+ ("蓝色", "", 4, ["蓝色"]),
+ ("שלום", "", 4, ["\u05e9\u05dc\u05d5\u05dd"]),
+ ("معرب", "", 4, ["\u0645\u0639\u0631\u0628"]),
+ ("test", "", 5, ["test "]),
+ (123, "", 4, ["123 "]),
+ (0.9, "", 4, ["0.9 "]),
+ (None, "", 5, ["None "]),
+ (True, "", 5, ["True "]),
+ (False, "", 6, ["False "]),
+ (Color("{blue}Test{/blue}"), "", 5, ["\x1b[34mTest\x1b[39m "]),
+ (Fore.BLUE + "Test" + Fore.RESET, "", 5, ["\x1b[34mTest\x1b[39m "]),
+ (colored("Test", "blue"), "", 5, ["\x1b[34mTest\x1b[0m "]),
+ ("蓝色", "", 5, ["蓝色 "]),
+ ("שלום", "", 5, ["\u05e9\u05dc\u05d5\u05dd "]),
+ ("معرب", "", 5, ["\u0645\u0639\u0631\u0628 "]),
+ ("test", "left", 5, ["test "]),
+ (123, "left", 4, ["123 "]),
+ (0.9, "left", 4, ["0.9 "]),
+ (None, "left", 5, ["None "]),
+ (True, "left", 5, ["True "]),
+ (False, "left", 6, ["False "]),
+ (Color("{blue}Test{/blue}"), "left", 5, ["\x1b[34mTest\x1b[39m "]),
+ (Fore.BLUE + "Test" + Fore.RESET, "left", 5, ["\x1b[34mTest\x1b[39m "]),
+ (colored("Test", "blue"), "left", 5, ["\x1b[34mTest\x1b[0m "]),
+ ("蓝色", "left", 5, ["蓝色 "]),
+ ("שלום", "left", 5, ["\u05e9\u05dc\u05d5\u05dd "]),
+ ("معرب", "left", 5, ["\u0645\u0639\u0631\u0628 "]),
+ ("test", "right", 5, [" test"]),
+ (123, "right", 4, [" 123"]),
+ (0.9, "right", 4, [" 0.9"]),
+ (None, "right", 5, [" None"]),
+ (True, "right", 5, [" True"]),
+ (False, "right", 6, [" False"]),
+ (Color("{blue}Test{/blue}"), "right", 5, [" \x1b[34mTest\x1b[39m"]),
+ (Fore.BLUE + "Test" + Fore.RESET, "right", 5, [" \x1b[34mTest\x1b[39m"]),
+ (colored("Test", "blue"), "right", 5, [" \x1b[34mTest\x1b[0m"]),
+ ("蓝色", "right", 5, [" 蓝色"]),
+ ("שלום", "right", 5, [" \u05e9\u05dc\u05d5\u05dd"]),
+ ("معرب", "right", 5, [" \u0645\u0639\u0631\u0628"]),
+ ("test", "center", 6, [" test "]),
+ (123, "center", 5, [" 123 "]),
+ (0.9, "center", 5, [" 0.9 "]),
+ (None, "center", 6, [" None "]),
+ (True, "center", 6, [" True "]),
+ (False, "center", 7, [" False "]),
+ (Color("{blue}Test{/blue}"), "center", 6, [" \x1b[34mTest\x1b[39m "]),
+ (Fore.BLUE + "Test" + Fore.RESET, "center", 6, [" \x1b[34mTest\x1b[39m "]),
+ (colored("Test", "blue"), "center", 6, [" \x1b[34mTest\x1b[0m "]),
+ ("蓝色", "center", 6, [" 蓝色 "]),
+ ("שלום", "center", 6, [" \u05e9\u05dc\u05d5\u05dd "]),
+ ("معرب", "center", 6, [" \u0645\u0639\u0631\u0628 "]),
+ ],
+)
def test_width(string, align, width, expected):
"""Test width and horizontal alignment.
@@ -87,47 +85,61 @@ def test_width(string, align, width, expected):
assert actual == expected
-@pytest.mark.parametrize('string,align,height,expected', [
- ('test', '', 1, ['test']),
- (Color('{blue}Test{/blue}'), '', 1, ['\x1b[34mTest\x1b[39m']),
- (Fore.BLUE + 'Test' + Fore.RESET, '', 1, ['\x1b[34mTest\x1b[39m']),
- (colored('Test', 'blue'), '', 1, ['\x1b[34mTest\x1b[0m']),
- ('蓝色', '', 1, ['蓝色']),
- (u'שלום', '', 1, [u'\u05e9\u05dc\u05d5\u05dd']),
- (u'معرب', '', 1, [u'\u0645\u0639\u0631\u0628']),
-
- ('test', '', 2, ['test', ' ']),
- (Color('{blue}Test{/blue}'), '', 2, ['\x1b[34mTest\x1b[39m', ' ']),
- (Fore.BLUE + 'Test' + Fore.RESET, '', 2, ['\x1b[34mTest\x1b[39m', ' ']),
- (colored('Test', 'blue'), '', 2, ['\x1b[34mTest\x1b[0m', ' ']),
- ('蓝色', '', 2, ['蓝色', ' ']),
- (u'שלום', '', 2, [u'\u05e9\u05dc\u05d5\u05dd', ' ']),
- (u'معرب', '', 2, [u'\u0645\u0639\u0631\u0628', ' ']),
-
- ('test', 'top', 2, ['test', ' ']),
- (Color('{blue}Test{/blue}'), 'top', 2, ['\x1b[34mTest\x1b[39m', ' ']),
- (Fore.BLUE + 'Test' + Fore.RESET, 'top', 2, ['\x1b[34mTest\x1b[39m', ' ']),
- (colored('Test', 'blue'), 'top', 2, ['\x1b[34mTest\x1b[0m', ' ']),
- ('蓝色', 'top', 2, ['蓝色', ' ']),
- (u'שלום', 'top', 2, [u'\u05e9\u05dc\u05d5\u05dd', ' ']),
- (u'معرب', 'top', 2, [u'\u0645\u0639\u0631\u0628', ' ']),
-
- ('test', 'bottom', 2, [' ', 'test']),
- (Color('{blue}Test{/blue}'), 'bottom', 2, [' ', '\x1b[34mTest\x1b[39m']),
- (Fore.BLUE + 'Test' + Fore.RESET, 'bottom', 2, [' ', '\x1b[34mTest\x1b[39m']),
- (colored('Test', 'blue'), 'bottom', 2, [' ', '\x1b[34mTest\x1b[0m']),
- ('蓝色', 'bottom', 2, [' ', '蓝色']),
- (u'שלום', 'bottom', 2, [' ', u'\u05e9\u05dc\u05d5\u05dd']),
- (u'معرب', 'bottom', 2, [' ', u'\u0645\u0639\u0631\u0628']),
-
- ('test', 'middle', 3, [' ', 'test', ' ']),
- (Color('{blue}Test{/blue}'), 'middle', 3, [' ', '\x1b[34mTest\x1b[39m', ' ']),
- (Fore.BLUE + 'Test' + Fore.RESET, 'middle', 3, [' ', '\x1b[34mTest\x1b[39m', ' ']),
- (colored('Test', 'blue'), 'middle', 3, [' ', '\x1b[34mTest\x1b[0m', ' ']),
- ('蓝色', 'middle', 3, [' ', '蓝色', ' ']),
- (u'שלום', 'middle', 3, [' ', u'\u05e9\u05dc\u05d5\u05dd', ' ']),
- (u'معرب', 'middle', 3, [' ', u'\u0645\u0639\u0631\u0628', ' ']),
-])
+@pytest.mark.parametrize(
+ "string,align,height,expected",
+ [
+ ("test", "", 1, ["test"]),
+ (Color("{blue}Test{/blue}"), "", 1, ["\x1b[34mTest\x1b[39m"]),
+ (Fore.BLUE + "Test" + Fore.RESET, "", 1, ["\x1b[34mTest\x1b[39m"]),
+ (colored("Test", "blue"), "", 1, ["\x1b[34mTest\x1b[0m"]),
+ ("蓝色", "", 1, ["蓝色"]),
+ ("שלום", "", 1, ["\u05e9\u05dc\u05d5\u05dd"]),
+ ("معرب", "", 1, ["\u0645\u0639\u0631\u0628"]),
+ ("test", "", 2, ["test", " "]),
+ (Color("{blue}Test{/blue}"), "", 2, ["\x1b[34mTest\x1b[39m", " "]),
+ (Fore.BLUE + "Test" + Fore.RESET, "", 2, ["\x1b[34mTest\x1b[39m", " "]),
+ (colored("Test", "blue"), "", 2, ["\x1b[34mTest\x1b[0m", " "]),
+ ("蓝色", "", 2, ["蓝色", " "]),
+ ("שלום", "", 2, ["\u05e9\u05dc\u05d5\u05dd", " "]),
+ ("معرب", "", 2, ["\u0645\u0639\u0631\u0628", " "]),
+ ("test", "top", 2, ["test", " "]),
+ (Color("{blue}Test{/blue}"), "top", 2, ["\x1b[34mTest\x1b[39m", " "]),
+ (Fore.BLUE + "Test" + Fore.RESET, "top", 2, ["\x1b[34mTest\x1b[39m", " "]),
+ (colored("Test", "blue"), "top", 2, ["\x1b[34mTest\x1b[0m", " "]),
+ ("蓝色", "top", 2, ["蓝色", " "]),
+ ("שלום", "top", 2, ["\u05e9\u05dc\u05d5\u05dd", " "]),
+ ("معرب", "top", 2, ["\u0645\u0639\u0631\u0628", " "]),
+ ("test", "bottom", 2, [" ", "test"]),
+ (Color("{blue}Test{/blue}"), "bottom", 2, [" ", "\x1b[34mTest\x1b[39m"]),
+ (
+ Fore.BLUE + "Test" + Fore.RESET,
+ "bottom",
+ 2,
+ [" ", "\x1b[34mTest\x1b[39m"],
+ ),
+ (colored("Test", "blue"), "bottom", 2, [" ", "\x1b[34mTest\x1b[0m"]),
+ ("蓝色", "bottom", 2, [" ", "蓝色"]),
+ ("שלום", "bottom", 2, [" ", "\u05e9\u05dc\u05d5\u05dd"]),
+ ("معرب", "bottom", 2, [" ", "\u0645\u0639\u0631\u0628"]),
+ ("test", "middle", 3, [" ", "test", " "]),
+ (
+ Color("{blue}Test{/blue}"),
+ "middle",
+ 3,
+ [" ", "\x1b[34mTest\x1b[39m", " "],
+ ),
+ (
+ Fore.BLUE + "Test" + Fore.RESET,
+ "middle",
+ 3,
+ [" ", "\x1b[34mTest\x1b[39m", " "],
+ ),
+ (colored("Test", "blue"), "middle", 3, [" ", "\x1b[34mTest\x1b[0m", " "]),
+ ("蓝色", "middle", 3, [" ", "蓝色", " "]),
+ ("שלום", "middle", 3, [" ", "\u05e9\u05dc\u05d5\u05dd", " "]),
+ ("معرب", "middle", 3, [" ", "\u0645\u0639\u0631\u0628", " "]),
+ ],
+)
def test_height(string, align, height, expected):
"""Test height and vertical alignment.
@@ -140,57 +152,68 @@ def test_height(string, align, height, expected):
assert actual == expected
-@pytest.mark.parametrize('string,align,expected', [
- ('', '', ['.......', '.......', '.......', '.......', '.......']),
- ('\n', '', ['.......', '.......', '.......', '.......', '.......']),
- ('a\nb\nc', '', ['.......', '.a.....', '.b.....', '.c.....', '.......']),
- ('test', '', ['.......', '.test..', '.......', '.......', '.......']),
-
- ('', 'left', ['.......', '.......', '.......', '.......', '.......']),
- ('\n', 'left', ['.......', '.......', '.......', '.......', '.......']),
- ('a\nb\nc', 'left', ['.......', '.a.....', '.b.....', '.c.....', '.......']),
- ('test', 'left', ['.......', '.test..', '.......', '.......', '.......']),
-
- ('', 'right', ['.......', '.......', '.......', '.......', '.......']),
- ('\n', 'right', ['.......', '.......', '.......', '.......', '.......']),
- ('a\nb\nc', 'right', ['.......', '.....a.', '.....b.', '.....c.', '.......']),
- ('test', 'right', ['.......', '..test.', '.......', '.......', '.......']),
-
- ('', 'center', ['.......', '.......', '.......', '.......', '.......']),
- ('\n', 'center', ['.......', '.......', '.......', '.......', '.......']),
- ('a\nb\nc', 'center', ['.......', '...a...', '...b...', '...c...', '.......']),
- ('test', 'center', ['.......', '..test.', '.......', '.......', '.......']),
-
- ('', 'top', ['.......', '.......', '.......', '.......', '.......']),
- ('\n', 'top', ['.......', '.......', '.......', '.......', '.......']),
- ('a\nb\nc', 'top', ['.......', '.a.....', '.b.....', '.c.....', '.......']),
- ('test', 'top', ['.......', '.test..', '.......', '.......', '.......']),
-
- ('', 'bottom', ['.......', '.......', '.......', '.......', '.......']),
- ('\n', 'bottom', ['.......', '.......', '.......', '.......', '.......']),
- ('a\nb\nc', 'bottom', ['.......', '.a.....', '.b.....', '.c.....', '.......']),
- ('test', 'bottom', ['.......', '.......', '.......', '.test..', '.......']),
-
- ('', 'middle', ['.......', '.......', '.......', '.......', '.......']),
- ('\n', 'middle', ['.......', '.......', '.......', '.......', '.......']),
- ('a\nb\nc', 'middle', ['.......', '.a.....', '.b.....', '.c.....', '.......']),
- ('test', 'middle', ['.......', '.......', '.test..', '.......', '.......']),
-
- (
- u'蓝色\nשלום\nمعرب',
- '',
- ['.......', u'.蓝色..', u'.\u05e9\u05dc\u05d5\u05dd..', u'.\u0645\u0639\u0631\u0628..', '.......']
- ),
-
- (
- '\n'.join((Color('{blue}Test{/blue}'), Fore.BLUE + 'Test' + Fore.RESET, colored('Test', 'blue'))),
- '',
- ['.......', '.\x1b[34mTest\x1b[39m..', '.\x1b[34mTest\x1b[39m..', '.\x1b[34mTest\x1b[0m..', '.......']
- ),
-
- # (Color('{blue}A\nB{/blue}'), '', '.......\n.\x1b[34mA\x1b[39m.....\n.\x1b[34mB\x1b[39m.....\n.......\n.......'),
-
-])
+@pytest.mark.parametrize(
+ "string,align,expected",
+ [
+ ("", "", [".......", ".......", ".......", ".......", "......."]),
+ ("\n", "", [".......", ".......", ".......", ".......", "......."]),
+ ("a\nb\nc", "", [".......", ".a.....", ".b.....", ".c.....", "......."]),
+ ("test", "", [".......", ".test..", ".......", ".......", "......."]),
+ ("", "left", [".......", ".......", ".......", ".......", "......."]),
+ ("\n", "left", [".......", ".......", ".......", ".......", "......."]),
+ ("a\nb\nc", "left", [".......", ".a.....", ".b.....", ".c.....", "......."]),
+ ("test", "left", [".......", ".test..", ".......", ".......", "......."]),
+ ("", "right", [".......", ".......", ".......", ".......", "......."]),
+ ("\n", "right", [".......", ".......", ".......", ".......", "......."]),
+ ("a\nb\nc", "right", [".......", ".....a.", ".....b.", ".....c.", "......."]),
+ ("test", "right", [".......", "..test.", ".......", ".......", "......."]),
+ ("", "center", [".......", ".......", ".......", ".......", "......."]),
+ ("\n", "center", [".......", ".......", ".......", ".......", "......."]),
+ ("a\nb\nc", "center", [".......", "...a...", "...b...", "...c...", "......."]),
+ ("test", "center", [".......", "..test.", ".......", ".......", "......."]),
+ ("", "top", [".......", ".......", ".......", ".......", "......."]),
+ ("\n", "top", [".......", ".......", ".......", ".......", "......."]),
+ ("a\nb\nc", "top", [".......", ".a.....", ".b.....", ".c.....", "......."]),
+ ("test", "top", [".......", ".test..", ".......", ".......", "......."]),
+ ("", "bottom", [".......", ".......", ".......", ".......", "......."]),
+ ("\n", "bottom", [".......", ".......", ".......", ".......", "......."]),
+ ("a\nb\nc", "bottom", [".......", ".a.....", ".b.....", ".c.....", "......."]),
+ ("test", "bottom", [".......", ".......", ".......", ".test..", "......."]),
+ ("", "middle", [".......", ".......", ".......", ".......", "......."]),
+ ("\n", "middle", [".......", ".......", ".......", ".......", "......."]),
+ ("a\nb\nc", "middle", [".......", ".a.....", ".b.....", ".c.....", "......."]),
+ ("test", "middle", [".......", ".......", ".test..", ".......", "......."]),
+ (
+ "蓝色\nשלום\nمعرب",
+ "",
+ [
+ ".......",
+ ".蓝色..",
+ ".\u05e9\u05dc\u05d5\u05dd..",
+ ".\u0645\u0639\u0631\u0628..",
+ ".......",
+ ],
+ ),
+ (
+ "\n".join(
+ (
+ Color("{blue}Test{/blue}"),
+ Fore.BLUE + "Test" + Fore.RESET,
+ colored("Test", "blue"),
+ )
+ ),
+ "",
+ [
+ ".......",
+ ".\x1b[34mTest\x1b[39m..",
+ ".\x1b[34mTest\x1b[39m..",
+ ".\x1b[34mTest\x1b[0m..",
+ ".......",
+ ],
+ ),
+ # (Color('{blue}A\nB{/blue}'), '', '.......\n.\x1b[34mA\x1b[39m.....\n.\x1b[34mB\x1b[39m.....\n.......\n.......'),
+ ],
+)
def test_odd_width_height_pad_space(string, align, expected):
"""Test odd number width, height, padding, and dots for whitespaces.
@@ -198,5 +221,5 @@ def test_odd_width_height_pad_space(string, align, expected):
:param str align: Alignment in any dimension but one at a time.
:param list expected: Expected output string.
"""
- actual = align_and_pad_cell(string, (align,), (5, 3), (1, 1, 1, 1), '.')
+ actual = align_and_pad_cell(string, (align,), (5, 3), (1, 1, 1, 1), ".")
assert actual == expected
diff --git a/tests/test_width_and_alignment/test_column_max_width.py b/tests/test_width_and_alignment/test_column_max_width.py
index 696c9bf..47a9c30 100644
--- a/tests/test_width_and_alignment/test_column_max_width.py
+++ b/tests/test_width_and_alignment/test_column_max_width.py
@@ -2,7 +2,7 @@
import pytest
-from terminaltables.width_and_alignment import column_max_width, max_dimensions
+from terminaltables3.width_and_alignment import column_max_width, max_dimensions
@pytest.fixture(autouse=True)
@@ -11,27 +11,35 @@ def patch(monkeypatch):
:param monkeypatch: pytest fixture.
"""
- monkeypatch.setattr('terminaltables.width_and_alignment.terminal_size', lambda: (79, 24))
+ monkeypatch.setattr(
+ "terminaltables3.width_and_alignment.terminal_size", lambda: (79, 24)
+ )
def test_empty():
"""Test with zero-length cells."""
- assert column_max_width(max_dimensions([['']])[0], 0, 0, 0, 0) == 79
- assert column_max_width(max_dimensions([['', '', '']])[0], 0, 0, 0, 0) == 79
- assert column_max_width(max_dimensions([['', '', ''], ['', '', '']])[0], 0, 0, 0, 0) == 79
+ assert column_max_width(max_dimensions([[""]])[0], 0, 0, 0, 0) == 79
+ assert column_max_width(max_dimensions([["", "", ""]])[0], 0, 0, 0, 0) == 79
+ assert (
+ column_max_width(max_dimensions([["", "", ""], ["", "", ""]])[0], 0, 0, 0, 0)
+ == 79
+ )
- assert column_max_width(max_dimensions([['']])[0], 0, 2, 1, 2) == 75
- assert column_max_width(max_dimensions([['', '', '']])[0], 0, 2, 1, 2) == 69
- assert column_max_width(max_dimensions([['', '', ''], ['', '', '']])[0], 0, 2, 1, 2) == 69
+ assert column_max_width(max_dimensions([[""]])[0], 0, 2, 1, 2) == 75
+ assert column_max_width(max_dimensions([["", "", ""]])[0], 0, 2, 1, 2) == 69
+ assert (
+ column_max_width(max_dimensions([["", "", ""], ["", "", ""]])[0], 0, 2, 1, 2)
+ == 69
+ )
def test_single_line():
"""Test with single-line cells."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
]
inner_widths = max_dimensions(table_data)[0]
@@ -72,11 +80,11 @@ def test_single_line():
assert column_max_width(inner_widths, 2, outer, inner, padding) == 48
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
- ['Watermelon', 'green', 'fruit'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
+ ["Watermelon", "green", "fruit"],
]
inner_widths = max_dimensions(table_data)[0]
outer, inner, padding = 2, 1, 2
@@ -91,10 +99,15 @@ def test_multi_line(monkeypatch):
:param monkeypatch: pytest fixture.
"""
table_data = [
- ['Show', 'Characters'],
- ['Rugrats', ('Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\n'
- 'Susie Carmichael, Dil Pickles, Kimi Finster, Spike')],
- ['South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick']
+ ["Show", "Characters"],
+ [
+ "Rugrats",
+ (
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\n"
+ "Susie Carmichael, Dil Pickles, Kimi Finster, Spike"
+ ),
+ ],
+ ["South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"],
]
inner_widths = max_dimensions(table_data)[0]
outer, inner, padding = 2, 1, 2
@@ -102,6 +115,8 @@ def test_multi_line(monkeypatch):
assert column_max_width(inner_widths, 0, outer, inner, padding) == -11
assert column_max_width(inner_widths, 1, outer, inner, padding) == 62
- monkeypatch.setattr('terminaltables.width_and_alignment.terminal_size', lambda: (100, 24))
+ monkeypatch.setattr(
+ "terminaltables3.width_and_alignment.terminal_size", lambda: (100, 24)
+ )
assert column_max_width(inner_widths, 0, outer, inner, padding) == 10
assert column_max_width(inner_widths, 1, outer, inner, padding) == 83
diff --git a/tests/test_width_and_alignment/test_max_dimensions.py b/tests/test_width_and_alignment/test_max_dimensions.py
index fc97883..5dd2629 100644
--- a/tests/test_width_and_alignment/test_max_dimensions.py
+++ b/tests/test_width_and_alignment/test_max_dimensions.py
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Test function in module."""
import pytest
@@ -6,18 +5,20 @@ from colorama import Fore
from colorclass import Color
from termcolor import colored
-from terminaltables.width_and_alignment import max_dimensions
+from terminaltables3.width_and_alignment import max_dimensions
-@pytest.mark.parametrize('table_data,expected_w,expected_h', [
- ([[]], [], [0]),
- ([['']], [0], [0]),
- ([['', '']], [0, 0], [0]),
-
- ([[], []], [], [0, 0]),
- ([[''], ['']], [0], [0, 0]),
- ([['', ''], ['', '']], [0, 0], [0, 0]),
-])
+@pytest.mark.parametrize(
+ "table_data,expected_w,expected_h",
+ [
+ ([[]], [], [0]),
+ ([[""]], [0], [0]),
+ ([["", ""]], [0, 0], [0]),
+ ([[], []], [], [0, 0]),
+ ([[""], [""]], [0], [0, 0]),
+ ([["", ""], ["", ""]], [0, 0], [0, 0]),
+ ],
+)
def test_zero_length(table_data, expected_w, expected_h):
"""Test zero-length or empty tables.
@@ -32,40 +33,60 @@ def test_zero_length(table_data, expected_w, expected_h):
def test_single_line():
"""Test widths."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
]
- assert max_dimensions(table_data, 1, 1) == ([7, 5, 9], [1, 1, 1, 1], [9, 7, 11], [1, 1, 1, 1])
-
- table_data.append(['Watermelon', 'green', 'fruit'])
- assert max_dimensions(table_data, 2, 2) == ([10, 5, 9], [1, 1, 1, 1, 1], [14, 9, 13], [1, 1, 1, 1, 1])
+ assert max_dimensions(table_data, 1, 1) == (
+ [7, 5, 9],
+ [1, 1, 1, 1],
+ [9, 7, 11],
+ [1, 1, 1, 1],
+ )
+
+ table_data.append(["Watermelon", "green", "fruit"])
+ assert max_dimensions(table_data, 2, 2) == (
+ [10, 5, 9],
+ [1, 1, 1, 1, 1],
+ [14, 9, 13],
+ [1, 1, 1, 1, 1],
+ )
def test_multi_line():
"""Test heights."""
table_data = [
- ['One\nTwo', 'Buckle\nMy\nShoe'],
+ ["One\nTwo", "Buckle\nMy\nShoe"],
]
assert max_dimensions(table_data, 0, 0, 1, 1) == ([3, 6], [3], [3, 6], [5])
table_data = [
- ['Show', 'Characters'],
- ['Rugrats', ('Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\n'
- 'Susie Carmichael, Dil Pickles, Kimi Finster, Spike')],
- ['South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick']
+ ["Show", "Characters"],
+ [
+ "Rugrats",
+ (
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\n"
+ "Susie Carmichael, Dil Pickles, Kimi Finster, Spike"
+ ),
+ ],
+ ["South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"],
]
- assert max_dimensions(table_data, 0, 0, 2, 2) == ([10, 83], [1, 2, 1], [10, 83], [5, 6, 5])
+ assert max_dimensions(table_data, 0, 0, 2, 2) == (
+ [10, 83],
+ [1, 2, 1],
+ [10, 83],
+ [5, 6, 5],
+ )
def test_trailing_newline():
r"""Test with trailing \n."""
table_data = [
- ['Row One\n<blank>'],
- ['<blank>\nRow Two'],
- ['Row Three\n'],
- ['\nRow Four'],
+ ["Row One\n<blank>"],
+ ["<blank>\nRow Two"],
+ ["Row Three\n"],
+ ["\nRow Four"],
]
assert max_dimensions(table_data) == ([9], [2, 2, 2, 2], [9], [2, 2, 2, 2])
@@ -73,21 +94,21 @@ def test_trailing_newline():
def test_colors_cjk_rtl():
"""Test color text, CJK characters, and RTL characters."""
table_data = [
- [Color('{blue}Test{/blue}')],
- [Fore.BLUE + 'Test' + Fore.RESET],
- [colored('Test', 'blue')],
+ [Color("{blue}Test{/blue}")],
+ [Fore.BLUE + "Test" + Fore.RESET],
+ [colored("Test", "blue")],
]
assert max_dimensions(table_data) == ([4], [1, 1, 1], [4], [1, 1, 1])
table_data = [
- ['蓝色'],
- ['世界你好'],
+ ["蓝色"],
+ ["世界你好"],
]
assert max_dimensions(table_data) == ([8], [1, 1], [8], [1, 1])
table_data = [
- ['שלום'],
- ['معرب'],
+ ["שלום"],
+ ["معرب"],
]
assert max_dimensions(table_data) == ([4], [1, 1], [4], [1, 1])
diff --git a/tests/test_width_and_alignment/test_table_width.py b/tests/test_width_and_alignment/test_table_width.py
index 5818789..15bf73d 100644
--- a/tests/test_width_and_alignment/test_table_width.py
+++ b/tests/test_width_and_alignment/test_table_width.py
@@ -1,26 +1,28 @@
"""Test function in module."""
-from terminaltables.width_and_alignment import max_dimensions, table_width
+from terminaltables3.width_and_alignment import max_dimensions, table_width
def test_empty():
"""Test with zero-length cells."""
- assert table_width(max_dimensions([['']])[2], 0, 0) == 0
- assert table_width(max_dimensions([['', '', '']])[2], 0, 0) == 0
- assert table_width(max_dimensions([['', '', ''], ['', '', '']])[2], 0, 0) == 0
+ assert table_width(max_dimensions([[""]])[2], 0, 0) == 0
+ assert table_width(max_dimensions([["", "", ""]])[2], 0, 0) == 0
+ assert table_width(max_dimensions([["", "", ""], ["", "", ""]])[2], 0, 0) == 0
- assert table_width(max_dimensions([['']], 1, 1)[2], 2, 1) == 4
- assert table_width(max_dimensions([['', '', '']], 1, 1)[2], 2, 1) == 10
- assert table_width(max_dimensions([['', '', ''], ['', '', '']], 1, 1)[2], 2, 1) == 10
+ assert table_width(max_dimensions([[""]], 1, 1)[2], 2, 1) == 4
+ assert table_width(max_dimensions([["", "", ""]], 1, 1)[2], 2, 1) == 10
+ assert (
+ table_width(max_dimensions([["", "", ""], ["", "", ""]], 1, 1)[2], 2, 1) == 10
+ )
def test_single_line():
"""Test with single-line cells."""
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
]
# '| Lettuce | green | vegetable |'
@@ -48,11 +50,11 @@ def test_single_line():
assert table_width(outer_widths, outer, inner) == 40
table_data = [
- ['Name', 'Color', 'Type'],
- ['Avocado', 'green', 'nut'],
- ['Tomato', 'red', 'fruit'],
- ['Lettuce', 'green', 'vegetable'],
- ['Watermelon', 'green', 'fruit'],
+ ["Name", "Color", "Type"],
+ ["Avocado", "green", "nut"],
+ ["Tomato", "red", "fruit"],
+ ["Lettuce", "green", "vegetable"],
+ ["Watermelon", "green", "fruit"],
]
outer, inner, outer_widths = 2, 1, max_dimensions(table_data, 1, 1)[2]
assert table_width(outer_widths, outer, inner) == 34
@@ -61,10 +63,15 @@ def test_single_line():
def test_multi_line():
"""Test with multi-line cells."""
table_data = [
- ['Show', 'Characters'],
- ['Rugrats', ('Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\n'
- 'Susie Carmichael, Dil Pickles, Kimi Finster, Spike')],
- ['South Park', 'Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick']
+ ["Show", "Characters"],
+ [
+ "Rugrats",
+ (
+ "Tommy Pickles, Chuckie Finster, Phillip DeVille, Lillian DeVille, Angelica Pickles,\n"
+ "Susie Carmichael, Dil Pickles, Kimi Finster, Spike"
+ ),
+ ],
+ ["South Park", "Stan Marsh, Kyle Broflovski, Eric Cartman, Kenny McCormick"],
]
outer, inner, outer_widths = 2, 1, max_dimensions(table_data, 1, 1)[2]
assert table_width(outer_widths, outer, inner) == 100
diff --git a/tests/test_width_and_alignment/test_visible_width.py b/tests/test_width_and_alignment/test_visible_width.py
index 79cebcb..53e9116 100644
--- a/tests/test_width_and_alignment/test_visible_width.py
+++ b/tests/test_width_and_alignment/test_visible_width.py
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Test function in module."""
import pytest
@@ -6,50 +5,49 @@ from colorama import Fore
from colorclass import Color
from termcolor import colored
-from terminaltables.width_and_alignment import visible_width
-
-
-@pytest.mark.parametrize('string,expected', [
- # str
- ('hello, world', 12),
- ('世界你好', 8),
- ('蓝色', 4),
- ('שלום', 4),
- ('معرب', 4),
- ('hello 世界', 10),
-
- # str+ansi
- ('\x1b[34mhello, world\x1b[39m', 12),
- ('\x1b[34m世界你好\x1b[39m', 8),
- ('\x1b[34m蓝色\x1b[39m', 4),
- ('\x1b[34mשלום\x1b[39m', 4),
- ('\x1b[34mمعرب\x1b[39m', 4),
- ('\x1b[34mhello 世界\x1b[39m', 10),
-
- # colorclass
- (Color(u'{blue}hello, world{/blue}'), 12),
- (Color(u'{blue}世界你好{/blue}'), 8),
- (Color(u'{blue}蓝色{/blue}'), 4),
- (Color(u'{blue}שלום{/blue}'), 4),
- (Color(u'{blue}معرب{/blue}'), 4),
- (Color(u'{blue}hello 世界{/blue}'), 10),
-
- # colorama
- (Fore.BLUE + 'hello, world' + Fore.RESET, 12),
- (Fore.BLUE + '世界你好' + Fore.RESET, 8),
- (Fore.BLUE + '蓝色' + Fore.RESET, 4),
- (Fore.BLUE + 'שלום' + Fore.RESET, 4),
- (Fore.BLUE + 'معرب' + Fore.RESET, 4),
- (Fore.BLUE + 'hello 世界' + Fore.RESET, 10),
-
- # termcolor
- (colored('hello, world', 'blue'), 12),
- (colored('世界你好', 'blue'), 8),
- (colored('蓝色', 'blue'), 4),
- (colored('שלום', 'blue'), 4),
- (colored('معرب', 'blue'), 4),
- (colored('hello 世界', 'blue'), 10),
-])
+from terminaltables3.width_and_alignment import visible_width
+
+
+@pytest.mark.parametrize(
+ "string,expected",
+ [
+ # str
+ ("hello, world", 12),
+ ("世界你好", 8),
+ ("蓝色", 4),
+ ("שלום", 4),
+ ("معرب", 4),
+ ("hello 世界", 10),
+ # str+ansi
+ ("\x1b[34mhello, world\x1b[39m", 12),
+ ("\x1b[34m世界你好\x1b[39m", 8),
+ ("\x1b[34m蓝色\x1b[39m", 4),
+ ("\x1b[34mשלום\x1b[39m", 4),
+ ("\x1b[34mمعرب\x1b[39m", 4),
+ ("\x1b[34mhello 世界\x1b[39m", 10),
+ # colorclass
+ (Color("{blue}hello, world{/blue}"), 12),
+ (Color("{blue}世界你好{/blue}"), 8),
+ (Color("{blue}蓝色{/blue}"), 4),
+ (Color("{blue}שלום{/blue}"), 4),
+ (Color("{blue}معرب{/blue}"), 4),
+ (Color("{blue}hello 世界{/blue}"), 10),
+ # colorama
+ (Fore.BLUE + "hello, world" + Fore.RESET, 12),
+ (Fore.BLUE + "世界你好" + Fore.RESET, 8),
+ (Fore.BLUE + "蓝色" + Fore.RESET, 4),
+ (Fore.BLUE + "שלום" + Fore.RESET, 4),
+ (Fore.BLUE + "معرب" + Fore.RESET, 4),
+ (Fore.BLUE + "hello 世界" + Fore.RESET, 10),
+ # termcolor
+ (colored("hello, world", "blue"), 12),
+ (colored("世界你好", "blue"), 8),
+ (colored("蓝色", "blue"), 4),
+ (colored("שלום", "blue"), 4),
+ (colored("معرب", "blue"), 4),
+ (colored("hello 世界", "blue"), 10),
+ ],
+)
def test(string, expected):
"""Test function with different color libraries.
diff --git a/tox.ini b/tox.ini
index ffb40c5..e50fe20 100644
--- a/tox.ini
+++ b/tox.ini
@@ -2,39 +2,23 @@
name = terminaltables
[tox]
-envlist = lint,py{34,27,26}
+envlist = py{38,39,310,311,312,313}
[testenv]
commands =
- python -c "import os, sys; sys.platform == 'win32' and os.system('easy_install pillow')"
- py.test --cov-report term-missing --cov-report xml --cov {[general]name} --cov-config tox.ini {posargs:tests}
+ python -c "import os, sys; sys.version_info[:3] <= (3, 12, 0) and os.system('pip install pillow')"
+ py.test --cov-report term-missing --cov-report xml --cov {[general]name} {posargs:tests}
deps =
- colorama==0.3.7
- colorclass==2.2.0
- pytest-cov==2.4.0
- termcolor==1.1.0
+ colorama>=0.3.7
+ colorclass>=2.2.0
+ pytest-cov>=2.4.0
+ termcolor>=1.1.0
passenv =
WINDIR
setenv =
PYTHON_EGG_CACHE = {envtmpdir}
usedevelop = True
-[testenv:lint]
-commands =
- python setup.py check --strict
- python setup.py check --strict -m
- python setup.py check --strict -s
- python setup.py check_version
- flake8 --application-import-names={[general]name},tests
- pylint --rcfile=tox.ini setup.py {[general]name}
-deps =
- flake8-docstrings==1.0.3
- flake8-import-order==0.12
- flake8==3.3.0
- pep8-naming==0.4.1
- pydocstyle==1.1.1
- pylint==1.6.5
-
[testenv:docs]
changedir = {toxinidir}/docs
commands =
@@ -55,25 +39,24 @@ passenv =
HOME
HOSTNAME
SSH_AUTH_SOCK
- TRAVIS*
USER
usedevelop = False
-
-[flake8]
-exclude = .tox/*,build/*,docs/*,env/*,get-pip.py
-import-order-style = smarkets
-max-line-length = 120
-statistics = True
-
-[pylint]
-disable =
- locally-disabled,
- too-few-public-methods,
- too-many-instance-attributes,
-ignore = .tox/*,build/*,docs/*,env/*,get-pip.py
-max-args = 6
-max-line-length = 120
-reports = no
-
-[run]
-branch = True
+;
+;[flake8]
+;exclude = .tox/*,build/*,docs/*,env/*,get-pip.py
+;import-order-style = smarkets
+;max-line-length = 120
+;statistics = True
+
+;[pylint]
+;disable =
+; locally-disabled,
+; too-few-public-methods,
+; too-many-instance-attributes,
+;ignore = .tox/*,build/*,docs/*,env/*,get-pip.py
+;max-args = 6
+;max-line-length = 120
+;reports = no
+
+;[run]
+;branch = True