Skip to content

Commit

Permalink
Merge pull request #100 from AnonymouX47/typing
Browse files Browse the repository at this point in the history
Static Typing & Type Checking Support
  • Loading branch information
AnonymouX47 authored Dec 28, 2023
2 parents af3da1c + 6f7db15 commit 52fa555
Show file tree
Hide file tree
Showing 24 changed files with 807 additions and 509 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/type_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This workflow will install Python dependencies and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: type check

on:
push:
branches: [ main ]
pull_request:

jobs:
build:

runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: make install-req

- name: Type-check with mypy
run: make type
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `term_image.padding` submodule ([#97]).
- `Padding`, `AlignedPadding`, `ExactPadding`, etc.
- Support for Pillow 10. ([8cfebe2])
- Static Typing & Type Checking Support ([#100]).

### Changed
- `term_image.utils.get_cell_size()` now returns `term_image.geometry.Size` instances in place of tuples ([#96]).

### Removed
- Support for Python 3.7. ([594d451])
- Runtime argument type validation ([b790f0e] in [#100]).


[#96]: https://github.com/AnonymouX47/term-image/pull/96
[#97]: https://github.com/AnonymouX47/term-image/pull/97
[#100]: https://github.com/AnonymouX47/term-image/pull/100
[497d9b7]: https://github.com/AnonymouX47/term-image/commit/497d9b70dd74605e6589b81bea2fcac22efc684b
[d296a31]: https://github.com/AnonymouX47/term-image/commit/d296a3110882449f6717959400abbc5fa1bd0891
[5537037]: https://github.com/AnonymouX47/term-image/commit/5537037a10b1da7ae8467cefaf99dc7959ceb7bc
[594d451]: https://github.com/AnonymouX47/term-image/commit/594d451d124a47c73a9dce61a4496a2a218261b1
[8cfebe2]: https://github.com/AnonymouX47/term-image/commit/8cfebe27b63dcdd987fc9d0c71616e76777779a9
[b790f0e]: https://github.com/AnonymouX47/term-image/commit/b790f0e7c5cd2afd7dafa7c14797136719b9dafb


## [0.7.0] - 2023-06-05
Expand Down
20 changes: 18 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,31 @@ For a more detailed explanation with examples see the guide at https://cbea.ms/g

- **NAMES tell WHAT... CODE tells HOW... COMMENTS tell WHY, when necessary (and WHAT, when impossible/unreasonable to make it obvious with NAMES)**.
- Maximum line length is 88 characters.
- All functions (including methods) should be adequately annotated.
- **Note:** Currently, annotations are only for documentation purposes and better/quicker comprehension of the defined interfaces by the users and developers.
- Try to keep things (definitions, names, dictionary keys, list items, etc)

- **grouped** (preferably by the most dominant criterium e.g object/definition type)
- **sorted** (preferably lexicographically, with the exception of depended-upon definitions e.g decorators, metaclasses, baseclasses, etc)

wherever **reasonably** possible. Makes things organized and quicker and easier to find 😃.

- All functions (including methods), variables and attributes should be duely type-annotated.

- Class and instance attributes (public and private) should be explicitly annotated, immediately within the class body.
- Module-scope and local variables should be explicitly annotated **only when neccessary**, such as

- exported/documented module-scope variables,
- when the type cannot be [correctly] inferred from the initial value,
- it's not initialized immediately, or
- the type is too complex or nested to be inferred from the initializer by a human reader at a glance.

- Any typing construct that incurs a runtime cost (no matter how "little"), such as `typing.cast()`, must not be used anywhere it may be executed more than once.
- **Note:**

- Type annotations are primarily for documentation purposes and better/quicker comprehension of defined interfaces by users and contributors, though they're also required to pass static type checking.
- This project doesn't depend primarily on static type checking for correctness. Hence, it is not an alternative to tests.

- Finally, please do not submit any pull request with code mindlessly written to satisfy a static type checker e.g at an unjustifiable cost of conciseness, readability and/or performance.

- For any matter of style not directly/indirectly addressed here, please try as much as possible to follow formats or styles already established in the project.
- Any questions or suggestions about the above can be asked or given in [this discussion](https://github.com/AnonymouX47/term-image/discussions/7).
- See also: [Documentation Style](#documentation-style).
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include src/term_image/py.typed
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,14 @@ py_files := *.py src/ docs/source/conf.py tests/

## Code Checks

check-code: lint check-format check-imports
check-code: lint type check-format check-imports

lint:
flake8 $(py_files) && echo

type:
mypy src/term_image && echo

check-format:
black --check --diff --color $(py_files) && echo

Expand Down
8 changes: 8 additions & 0 deletions docs/source/api/renderable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ Exceptions

|
Type Variables and Aliases
--------------------------

.. autotypevar:: OptionalPaddingT
:no-type:

|
Extension API
-------------

Expand Down
1 change: 1 addition & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"sphinx_toolbox.sidebar_links",
"sphinx_toolbox.more_autosummary",
"sphinx_toolbox.collapse",
"sphinx_toolbox.more_autodoc.typevars",
"sphinxcontrib.prettyspecialmethods",
]

Expand Down
21 changes: 21 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[tool.mypy]
strict = true
show_column_numbers = true
implicit_reexport = false

[[tool.mypy.overrides]]
module = [
'term_image.renderable.*',
'term_image.render.*',
'term_image.image.*',
]
disable_error_code = ["type-abstract"]

# These modules will go through massive changes real soon
[[tool.mypy.overrides]]
module = [
'term_image.image.*',
'term_image.widget.*',
]
ignore_errors = true

[tool.isort]
profile = "black"
combine_as_imports = true
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ black==23.9.1
flake8==6.1.0;python_version>="3.8.1"
flake8==5.0.4;python_version<"3.8.1"
isort[colors]==5.12.0
mypy==1.8.0
pillow==10.0.1
pytest==7.4.2
requests==2.31.0
typing_extensions==4.9.0
urwid==2.2.2
7 changes: 6 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@
license="MIT",
classifiers=classifiers,
python_requires=">=3.8",
install_requires=["pillow>=9.1,<11", "requests>=2.23,<3"],
install_requires=[
"pillow>=9.1,<11",
"requests>=2.23,<3",
"typing_extensions>=4.8,<5",
],
include_package_data=True,
project_urls={
"Changelog": "https://github.com/AnonymouX47/term-image/blob/main/CHANGELOG.md",
"Documentation": "https://term-image.readthedocs.io/",
Expand Down
39 changes: 17 additions & 22 deletions src/term_image/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@

from enum import Enum, auto
from operator import truediv
from typing import ClassVar, Union

from typing_extensions import ClassVar, Final

from . import utils
from .exceptions import TermImageError
from .utils import arg_value_error_range, get_cell_size

version_info = (0, 8, 0, "dev")

Expand All @@ -35,7 +37,7 @@
if version_info[3:]:
__version__ += "-" + ".".join(map(str, version_info[3:]))

DEFAULT_QUERY_TIMEOUT: float = utils._query_timeout # Final[float]
DEFAULT_QUERY_TIMEOUT: Final[float] = utils._query_timeout
"""Default timeout for :ref:`terminal-queries`
.. seealso:: :py:func:`set_query_timeout`.
Expand Down Expand Up @@ -91,7 +93,7 @@ def disable_queries() -> None:
utils._queries_enabled = False


def disable_win_size_swap():
def disable_win_size_swap() -> None:
"""Disables a workaround for terminal emulators that wrongly report window
dimensions swapped.
Expand All @@ -118,13 +120,13 @@ def enable_queries() -> None:
"""
if not utils._queries_enabled:
utils._queries_enabled = True
utils.get_fg_bg_colors._invalidate_cache()
utils.get_terminal_name_version._invalidate_cache()
getattr(utils.get_fg_bg_colors, "_invalidate_cache")()
getattr(utils.get_terminal_name_version, "_invalidate_cache")()
with utils._cell_size_lock:
utils._cell_size_cache[:] = (0,) * 4


def enable_win_size_swap():
def enable_win_size_swap() -> None:
"""Enables a workaround for terminal emulators that wrongly report window
dimensions swapped.
Expand All @@ -147,10 +149,10 @@ def get_cell_ratio() -> float:
.. seealso:: :py:func:`set_cell_ratio`.
"""
# `(1, 2)` is a fallback in case the terminal doesn't respond in time
return _cell_ratio or truediv(*(utils.get_cell_size() or (1, 2)))
return _cell_ratio or truediv(*(get_cell_size() or (1, 2)))


def set_cell_ratio(ratio: Union[float, AutoCellRatio]) -> None:
def set_cell_ratio(ratio: float | AutoCellRatio) -> None:
"""Sets the global :term:`cell ratio`.
Args:
Expand All @@ -165,9 +167,7 @@ def set_cell_ratio(ratio: Union[float, AutoCellRatio]) -> None:
only if the terminal size changes.
Raises:
TypeError: An argument is of an inappropriate type.
ValueError: An argument is of an appropriate type but has an
unexpected/invalid value.
ValueError: *ratio* is a non-positive :py:class:`float`.
term_image.exceptions.TermImageError: Auto cell ratio is not supported
in the :term:`active terminal` or on the current platform.
Expand All @@ -187,7 +187,7 @@ def set_cell_ratio(ratio: Union[float, AutoCellRatio]) -> None:

if isinstance(ratio, AutoCellRatio):
if AutoCellRatio.is_supported is None:
AutoCellRatio.is_supported = utils.get_cell_size() is not None
AutoCellRatio.is_supported = get_cell_size() is not None

if not AutoCellRatio.is_supported:
raise TermImageError(
Expand All @@ -196,15 +196,13 @@ def set_cell_ratio(ratio: Union[float, AutoCellRatio]) -> None:
)
elif ratio is AutoCellRatio.FIXED:
# `(1, 2)` is a fallback in case the terminal doesn't respond in time
_cell_ratio = truediv(*(utils.get_cell_size() or (1, 2)))
_cell_ratio = truediv(*(get_cell_size() or (1, 2)))
else:
_cell_ratio = None
elif isinstance(ratio, float):
else:
if ratio <= 0.0:
raise utils.arg_value_error_range("ratio", ratio)
raise arg_value_error_range("ratio", ratio)
_cell_ratio = ratio
else:
raise utils.arg_type_error("ratio", ratio)


def set_query_timeout(timeout: float) -> None:
Expand All @@ -214,16 +212,13 @@ def set_query_timeout(timeout: float) -> None:
timeout: Time limit for awaiting a response from the terminal, in seconds.
Raises:
TypeError: *timeout* is not a float.
ValueError: *timeout* is less than or equal to zero.
"""
if not isinstance(timeout, float):
raise utils.arg_type_error("timeout", timeout)
if timeout <= 0.0:
raise utils.arg_value_error_range("timeout", timeout)
raise arg_value_error_range("timeout", timeout)

utils._query_timeout = timeout


_cell_ratio = 0.5
_cell_ratio: float | None = 0.5
AutoCellRatio.is_supported = None
Loading

0 comments on commit 52fa555

Please sign in to comment.