diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000..fd0ec73
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,2 @@
+# Initial application of pre-commit (including Black)
+77f65d1a2ebbb8593e6968ce1af212693b074c93
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 85fbbd4..be916cd 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -7,41 +7,21 @@ on:
workflow_call:
jobs:
- beefore:
- name: Pre-test checks
- runs-on: ubuntu-latest
- strategy:
- max-parallel: 4
- matrix:
- task:
- - 'flake8'
- - 'towncrier-check'
- - 'package'
- steps:
- # Fetch main branch for comparison, then check out current branch.
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0
- ref: main
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0
- - name: Set up Python
- uses: actions/setup-python@v4.5.0
- with:
- python-version: 3.X
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- python -m pip install --upgrade setuptools
- python -m pip install tox
- - name: Run pre-test check
- run: |
- tox -e ${{ matrix.task }}
+ pre-commit:
+ name: Pre-commit checks
+ uses: beeware/.github/.github/workflows/pre-commit-run.yml@main
+
+ towncrier:
+ name: Check towncrier
+ uses: beeware/.github/.github/workflows/towncrier-run.yml@main
+
+ package:
+ name: Python Package
+ uses: beeware/.github/.github/workflows/python-package-create.yml@main
- python-versions:
+ unit-tests:
name: Python compatibility test
- needs: beefore
+ needs: [pre-commit, towncrier, package]
runs-on: ubuntu-latest
strategy:
matrix:
@@ -53,16 +33,28 @@ jobs:
experimental: true
steps:
- - uses: actions/checkout@v3
+ - name: Checkout
+ uses: actions/checkout@v3.3.0
+ with:
+ fetch-depth: 0
+
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ matrix.python-version }}
- - name: Install dependencies
+
+ - name: Get packages
+ uses: actions/download-artifact@v3.0.2
+ with:
+ name: ${{ needs.package.outputs.artifact-name }}
+ path: dist
+
+ - name: Install dev dependencies
run: |
- python -m pip install --upgrade pip
- python -m pip install --upgrade setuptools
- python -m pip install tox
+ # We don't actually want to install travertino;
+ # we just want the dev extras so we have a known version of tox.
+ python -m pip install $(ls dist/travertino-*.whl)[dev]
+
- name: Test
run: |
- tox -e py
+ tox -e py --installpkg dist/travertino-*.whl
diff --git a/.github/workflows/pre-commit-update.yml b/.github/workflows/pre-commit-update.yml
new file mode 100644
index 0000000..2bc6a36
--- /dev/null
+++ b/.github/workflows/pre-commit-update.yml
@@ -0,0 +1,12 @@
+name: Update pre-commit
+
+on:
+ schedule:
+ - cron: "0 20 * * SUN" # Sunday @ 2000 UTC
+ workflow_dispatch:
+
+jobs:
+ pre-commit-update:
+ name: Update pre-commit
+ uses: beeware/.github/.github/workflows/pre-commit-update.yml@main
+ secrets: inherit
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 793af38..ac8a2a6 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -5,25 +5,18 @@ on:
types: published
jobs:
- publish:
+ deploy:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
- - name: Set up Python
- uses: actions/setup-python@v1
- with:
- python-version: '3.x'
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- python -m pip install --upgrade setuptools
- python -m pip install tox
- - name: Build release artefacts
- run: |
- tox -e package
- - name: Publish release
- env:
- TWINE_USERNAME: __token__
- TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
- run: |
- tox -e publish
+ - uses: dsaltares/fetch-gh-release-asset@1.1.0
+ with:
+ version: tags/${{ github.event.release.tag_name }}
+ # This next line is *not* a bash filename expansion - it's a regex.
+ file: travertino.*
+ regex: true
+ target: dist/
+
+ - name: Publish release to production PyPI
+ uses: pypa/gh-action-pypi-publish@release/v1
+ with:
+ password: ${{ secrets.PYPI_PASSWORD }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 2e4d332..d1107a2 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,22 +3,66 @@ name: Create Release
on:
push:
tags:
- - 'v*'
+ - "v*"
jobs:
+ ci:
+ uses: ./.github/workflows/ci.yml
+
release:
name: Create Release
- runs-on: ubuntu-latest
+ needs: ci
+ permissions:
+ contents: write
steps:
- - name: Checkout code
- uses: actions/checkout@master
+ - name: Set build variables
+ run: |
+ echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV
+
+ - name: Set up Python
+ uses: actions/setup-python@v4.5.0
+ with:
+ python-version: "3.X"
+
+ - name: Get packages
+ uses: actions/download-artifact@v3.0.2
+ with:
+ name: packages
+ path: dist
+
+ - name: Install packages
+ run: pip install dist/travertino-*.whl
+
+ - name: Check version number
+ # Check that the setuptools_scm-generated version number is still the same when
+ # installed from a wheel with setuptools_scm not present.
+ run: |
+ set -x
+ test $(python -c "from travertino import __version__; print(__version__)") = $VERSION
+
- name: Create Release
- id: create_release
- uses: actions/create-release@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ uses: ncipollo/release-action@v1.12.0
with:
- tag_name: ${{ github.ref }}
- release_name: ${{ github.ref }}
+ name: ${{ env.VERSION }}
draft: true
- prerelease: false
+ artifacts: dist/*
+ artifactErrorsFailBuild: true
+
+ test-publish:
+ name: Publish test package
+ needs: [release]
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ steps:
+ - name: Get packages
+ uses: actions/download-artifact@v3.0.2
+ with:
+ name: packages
+ path: dist
+
+ - name: Publish release to Test PyPI
+ uses: pypa/gh-action-pypi-publish@release/v1
+ with:
+ repository_url: https://test.pypi.org/legacy/
+ password: ${{ secrets.TEST_PYPI_PASSWORD }}
diff --git a/.gitignore b/.gitignore
index f77f0b5..0b5784b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,3 @@ distribute-*
venv
.idea
pip-wheel-metadata
-
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..afcf057
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,28 @@
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.4.0
+ hooks:
+ - id: check-toml
+ - id: check-yaml
+ - id: check-case-conflict
+ - id: check-docstring-first
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+ - repo: https://github.com/PyCQA/isort
+ rev: 5.12.0
+ hooks:
+ - id: isort
+ additional_dependencies: [toml]
+ - repo: https://github.com/asottile/pyupgrade
+ rev: v3.3.1
+ hooks:
+ - id: pyupgrade
+ args: [--py37-plus]
+ - repo: https://github.com/psf/black
+ rev: 23.1.0
+ hooks:
+ - id: black
+ - repo: https://github.com/PyCQA/flake8
+ rev: 6.0.0
+ hooks:
+ - id: flake8
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 09e2781..ec4f1c0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,8 +1,7 @@
# Contributing
-PyBee <3's contributions!
+BeeWare <3's contributions!
-Please be aware, PyBee operates under a Code of Conduct.
-
-See [CONTRIBUTING to PyBee](http://pybee.org/contributing) for details.
+Please be aware, BeeWare operates under a Code of Conduct.
+See [CONTRIBUTING to BeeWare](https://beeware.org/contributing) for details.
diff --git a/MANIFEST.in b/MANIFEST.in
index 2f83e76..77a1dc0 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,9 +3,8 @@ include CONTRIBUTING.md
include README.rst
include AUTHORS
include LICENSE
-include beekeeper.yml
include tox.ini
+include .git-blame-ignore-revs
+include .pre-commit-config.yaml
recursive-include changes *.rst
-recursive-include travertino *.py
recursive-include tests *.py
-recursive-include tests *.json
diff --git a/README.rst b/README.rst
index 5b07825..6a856ea 100644
--- a/README.rst
+++ b/README.rst
@@ -24,7 +24,7 @@ Travertino
.. image:: https://img.shields.io/discord/836455665257021440?label=Discord%20Chat&logo=discord&style=plastic
:target: https://beeware.org/bee/chat/
:alt: Discord server
-
+
Travertino is a set of constants and utilities for describing user
interfaces, including:
@@ -74,6 +74,14 @@ Contributing
If you experience problems with Travertino, `log them on GitHub`_. If you
want to contribute code, please `fork the code`_ and `submit a pull request`_.
+Travertino uses `Pre-commit `__ and `TownCrier
+`__ to help maintain code quality. For
+details on how to use these tools as part of your development environment, see
+the `Briefcase code contribution guide
+`__.
+Although that document is for a different project, the details about setting up
+your development environment are the same.
+
.. _BeeWare suite: http://beeware.org
.. _Read The Docs: https://travertino.readthedocs.io
.. _@pybeeware on Twitter: https://twitter.com/pybeeware
diff --git a/changes/18.doc.rst b/changes/18.doc.rst
new file mode 100644
index 0000000..93e004d
--- /dev/null
+++ b/changes/18.doc.rst
@@ -0,0 +1 @@
+Details on towncrier and pre-commit ussage were added to the README.
diff --git a/changes/22.misc.rst b/changes/22.misc.rst
index 9afbc42..ee0ef39 100644
--- a/changes/22.misc.rst
+++ b/changes/22.misc.rst
@@ -1 +1 @@
-Corrected some spelling errors.
\ No newline at end of file
+Corrected some spelling errors.
diff --git a/changes/23.feature.rst b/changes/23.feature.rst
index 8dc6d78..a22e951 100644
--- a/changes/23.feature.rst
+++ b/changes/23.feature.rst
@@ -1 +1 @@
-Node now supports the `clear` method in order to clear all children.
\ No newline at end of file
+Node now supports the ``clear`` method in order to clear all children.
diff --git a/changes/24.misc.rst b/changes/24.misc.rst
index df20f9a..bf80e14 100644
--- a/changes/24.misc.rst
+++ b/changes/24.misc.rst
@@ -1 +1 @@
-Flake8 should ignore the venv directory when running.
\ No newline at end of file
+Flake8 should ignore the venv directory when running.
diff --git a/changes/25.misc.rst b/changes/25.misc.rst
index 2765652..8a84664 100644
--- a/changes/25.misc.rst
+++ b/changes/25.misc.rst
@@ -1 +1 @@
-Drop python 3.5 support!
\ No newline at end of file
+Drop python 3.5 support!
diff --git a/changes/26.misc.rst b/changes/26.misc.rst
index 48b128a..61bdffa 100644
--- a/changes/26.misc.rst
+++ b/changes/26.misc.rst
@@ -1 +1 @@
-Upgrade all codebase to use format-strings
\ No newline at end of file
+Upgrade all codebase to use format-strings
diff --git a/changes/34.misc.rst b/changes/34.misc.rst
new file mode 100644
index 0000000..890adf3
--- /dev/null
+++ b/changes/34.misc.rst
@@ -0,0 +1 @@
+Pre-commit was added to the codebase. This introduces black as a coding style.
diff --git a/pyproject.toml b/pyproject.toml
index 8c96d1c..3829c7c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,15 @@
[build-system]
-requires = [
- "setuptools >= 43.0.0",
- "wheel >= 0.32.0",
-]
+requires = ["setuptools==66.1.1", "setuptools_scm[toml]==7.0.5"]
build-backend = "setuptools.build_meta"
+[tool.isort]
+profile = "black"
+split_on_trailing_comma = true
+combine_as_imports = true
+
+[tool.setuptools_scm]
+# To enable SCM versioning, we need an empty tool configuration for setuptools_scm
+
[tool.towncrier]
directory = "changes"
package = "travertino"
@@ -12,4 +17,3 @@ filename = "CHANGELOG.rst"
title_format = "{version} ({project_date})"
issue_format = "`#{issue} `_"
template = "changes/template.rst"
-underlines = ["-", "^", "\""]
diff --git a/setup.cfg b/setup.cfg
index 64da470..02d30c3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,5 @@
[metadata]
name = travertino
-version = attr: travertino.__version__
project_urls =
Funding = https://beeware.org/contributing/membership/
Tracker = https://github.com/beeware/travertino/issues
@@ -35,6 +34,16 @@ packages = find:
package_dir =
= src
+[options.extras_require]
+dev =
+ # Pre-commit 3.0 dropped support for Python 3.7
+ pre-commit == 2.21.0; python_version < "3.8"
+ pre-commit == 3.0.4; python_version >= "3.8"
+ pytest == 7.2.1
+ pytest-tldr == 0.2.5
+ setuptools_scm[toml] == 7.1.0
+ tox == 4.4.4
+
[options.packages.find]
where = src
@@ -53,12 +62,3 @@ max-line-length = 119
# E226: missing whitespace around arithmetic operator
# W503: line break occurred before a binary operator
ignore = E133,E226,W503
-
-# ignore = E121,E123,E126,E226,E24,E704,W503,W504,C901
-
-[isort]
-combine_as_imports = true
-include_trailing_comma = true
-line_length = 79
-multi_line_output = 3
-not_skip = __init__.py
diff --git a/setup.py b/setup.py
deleted file mode 100644
index c823345..0000000
--- a/setup.py
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env python
-from setuptools import setup
-
-setup()
diff --git a/src/travertino/__init__.py b/src/travertino/__init__.py
index 8379c6f..cafea81 100644
--- a/src/travertino/__init__.py
+++ b/src/travertino/__init__.py
@@ -1,9 +1,21 @@
-# Examples of valid version strings
-# __version__ = '1.2.3.dev1' # Development release 1
-# __version__ = '1.2.3a1' # Alpha Release 1
-# __version__ = '1.2.3b1' # Beta Release 1
-# __version__ = '1.2.3rc1' # RC Release 1
-# __version__ = '1.2.3' # Final Release
-# __version__ = '1.2.3.post1' # Post Release 1
+try:
+ # Read version from SCM metadata
+ # This will only exist in a development environment
+ from setuptools_scm import get_version
-__version__ = '0.1.3'
+ # Excluded from coverage because a pure test environment (such as the one
+ # used by tox in CI) won't have setuptools_scm
+ __version__ = get_version("../..", relative_to=__file__) # pragma: no cover
+except (ModuleNotFoundError, LookupError):
+ # If setuptools_scm isn't in the environment, the call to import will fail.
+ # If it *is* in the environment, but the code isn't a git checkout (e.g.,
+ # it's been pip installed non-editable) the call to get_version() will fail.
+ # If either of these occurs, read version from the installer metadata.
+
+ # importlib.metadata.versoin was added in Python 3.8
+ try:
+ from importlib.metadata import version
+ except ModuleNotFoundError:
+ from importlib_metadata import version
+
+ __version__ = version("travertino")
diff --git a/src/travertino/colors.py b/src/travertino/colors.py
index 8ef9c6c..a6b91ee 100644
--- a/src/travertino/colors.py
+++ b/src/travertino/colors.py
@@ -11,12 +11,7 @@ def __eq__(self, other):
c1 = self.rgba
c2 = other.rgba
- return (
- c1.r == c2.r
- and c1.g == c2.g
- and c1.b == c2.b
- and c1.a == c2.a
- )
+ return c1.r == c2.r and c1.g == c2.g and c1.b == c2.b and c1.a == c2.a
except AttributeError:
return False
@@ -40,6 +35,7 @@ def _validate_alpha(cls, value):
class rgba(Color):
"A representation of an RGBA color"
+
def __init__(self, r, g, b, a):
self._validate_rgb("red", r)
self._validate_rgb("green", g)
@@ -51,7 +47,7 @@ def __init__(self, r, g, b, a):
self.a = a
def __hash__(self):
- return hash(('RGBA-color', self.r, self.g, self.b, self.a))
+ return hash(("RGBA-color", self.r, self.g, self.b, self.a))
def __repr__(self):
return f"rgba({self.r}, {self.g}, {self.b}, {self.a})"
@@ -67,6 +63,7 @@ def rgba(self):
class rgb(rgba):
"A representation of an RGB color"
+
def __init__(self, r, g, b):
super().__init__(r, g, b, 1.0)
@@ -76,6 +73,7 @@ def __repr__(self):
class hsla(Color):
"A representation of an HSLA color"
+
def __init__(self, h, s, l, a=1.0):
self._validate_between("hue", h, 0, 360)
self._validate_partial("saturation", s)
@@ -87,7 +85,7 @@ def __init__(self, h, s, l, a=1.0):
self.a = a
def __hash__(self):
- return hash(('HSLA-color', self.h, self.s, self.l, self.a))
+ return hash(("HSLA-color", self.h, self.s, self.l, self.a))
def __repr__(self):
return f"hsla({self.h}, {self.s}, {self.l}, {self.a})"
@@ -113,15 +111,16 @@ def rgba(self):
r, g, b = c + m, m, x + m
return rgba(
- round(r * 0xff),
- round(g * 0xff),
- round(b * 0xff),
- self.a
+ round(r * 0xFF),
+ round(g * 0xFF),
+ round(b * 0xFF),
+ self.a,
)
class hsl(hsla):
"A representation of an HSL color"
+
def __init__(self, h, s, l):
super().__init__(h, s, l, 1.0)
@@ -154,7 +153,7 @@ def color(value):
return value
elif isinstance(value, str):
- if value[0] == '#':
+ if value[0] == "#":
if len(value) == 4:
return rgb(
r=int(value[1] + value[1], 16),
@@ -166,7 +165,7 @@ def color(value):
r=int(value[1] + value[1], 16),
g=int(value[2] + value[2], 16),
b=int(value[3] + value[3], 16),
- a=int(value[4] + value[4], 16) / 0xff,
+ a=int(value[4] + value[4], 16) / 0xFF,
)
elif len(value) == 7:
return rgb(
@@ -179,44 +178,55 @@ def color(value):
r=int(value[1:3], 16),
g=int(value[3:5], 16),
b=int(value[5:7], 16),
- a=int(value[7:9], 16) / 0xff,
+ a=int(value[7:9], 16) / 0xFF,
)
- elif value.startswith('rgba'):
+ elif value.startswith("rgba"):
try:
- values = value[5:-1].split(',')
+ values = value[5:-1].split(",")
if len(values) == 4:
- return rgba(int(values[0]), int(values[1]), int(values[2]), float(values[3]))
+ return rgba(
+ int(values[0]),
+ int(values[1]),
+ int(values[2]),
+ float(
+ values[3],
+ ),
+ )
except ValueError:
pass
- elif value.startswith('rgb'):
+ elif value.startswith("rgb"):
try:
- values = value[4:-1].split(',')
+ values = value[4:-1].split(",")
if len(values) == 3:
- return rgb(int(values[0]), int(values[1]), int(values[2]))
+ return rgb(
+ int(values[0]),
+ int(values[1]),
+ int(values[2]),
+ )
except ValueError:
pass
- elif value.startswith('hsla'):
+ elif value.startswith("hsla"):
try:
- values = value[5:-1].split(',')
+ values = value[5:-1].split(",")
if len(values) == 4:
return hsla(
int(values[0]),
- int(values[1].strip().rstrip('%')) / 100.0,
- int(values[2].strip().rstrip('%')) / 100.0,
- float(values[3])
+ int(values[1].strip().rstrip("%")) / 100.0,
+ int(values[2].strip().rstrip("%")) / 100.0,
+ float(values[3]),
)
except ValueError:
pass
- elif value.startswith('hsl'):
+ elif value.startswith("hsl"):
try:
- values = value[4:-1].split(',')
+ values = value[4:-1].split(",")
if len(values) == 3:
return hsl(
int(values[0]),
- int(values[1].strip().rstrip('%')) / 100.0,
- int(values[2].strip().rstrip('%')) / 100.0,
+ int(values[1].strip().rstrip("%")) / 100.0,
+ int(values[2].strip().rstrip("%")) / 100.0,
)
except ValueError:
pass
@@ -226,7 +236,7 @@ def color(value):
except KeyError:
pass
- raise ValueError('Unknown color %s' % value)
+ raise ValueError("Unknown color %s" % value)
NAMED_COLOR = {
@@ -382,5 +392,12 @@ def color(value):
__all__ = [
- 'Color', 'rgba', 'rgb', 'hsla', 'hsl', 'color', 'NAMED_COLOR', 'TRANSPARENT'
+ "Color",
+ "rgba",
+ "rgb",
+ "hsla",
+ "hsl",
+ "color",
+ "NAMED_COLOR",
+ "TRANSPARENT",
] + [name.upper() for name in NAMED_COLOR.keys()]
diff --git a/src/travertino/constants.py b/src/travertino/constants.py
index 93ba53e..24f1bf4 100644
--- a/src/travertino/constants.py
+++ b/src/travertino/constants.py
@@ -2,60 +2,60 @@
# Common constants
######################################################################
-NORMAL = 'normal'
-LEFT = 'left'
-RIGHT = 'right'
-TOP = 'top'
-BOTTOM = 'bottom'
-CENTER = 'center'
+NORMAL = "normal"
+LEFT = "left"
+RIGHT = "right"
+TOP = "top"
+BOTTOM = "bottom"
+CENTER = "center"
######################################################################
# Direction
######################################################################
-ROW = 'row'
-COLUMN = 'column'
+ROW = "row"
+COLUMN = "column"
######################################################################
# Visibility
######################################################################
-VISIBLE = 'visible'
-HIDDEN = 'hidden'
-NONE = 'none'
+VISIBLE = "visible"
+HIDDEN = "hidden"
+NONE = "none"
######################################################################
# Text Justification
######################################################################
-JUSTIFY = 'justify'
+JUSTIFY = "justify"
######################################################################
# Text Direction
######################################################################
-RTL = 'rtl'
-LTR = 'ltr'
+RTL = "rtl"
+LTR = "ltr"
######################################################################
# Font family
######################################################################
-SYSTEM = 'system'
-MESSAGE = 'message'
+SYSTEM = "system"
+MESSAGE = "message"
-SERIF = 'serif'
-SANS_SERIF = 'sans-serif'
-CURSIVE = 'cursive'
-FANTASY = 'fantasy'
-MONOSPACE = 'monospace'
+SERIF = "serif"
+SANS_SERIF = "sans-serif"
+CURSIVE = "cursive"
+FANTASY = "fantasy"
+MONOSPACE = "monospace"
######################################################################
# Font Styling
######################################################################
-ITALIC = 'italic'
-OBLIQUE = 'oblique'
+ITALIC = "italic"
+OBLIQUE = "oblique"
FONT_STYLES = {ITALIC, OBLIQUE}
@@ -63,7 +63,7 @@
# Font Variant
######################################################################
-SMALL_CAPS = 'small-caps'
+SMALL_CAPS = "small-caps"
FONT_VARIANTS = {SMALL_CAPS}
@@ -71,7 +71,7 @@
# Font boldness
######################################################################
-BOLD = 'bold'
+BOLD = "bold"
FONT_WEIGHTS = {BOLD}
@@ -85,153 +85,153 @@
# Colors
######################################################################
-TRANSPARENT = 'transparent'
-
-ALICEBLUE = 'aliceblue'
-ANTIQUEWHITE = 'antiquewhite'
-AQUA = 'aqua'
-AQUAMARINE = 'aquamarine'
-AZURE = 'azure'
-BEIGE = 'beige'
-BISQUE = 'bisque'
-BLACK = 'black'
-BLANCHEDALMOND = 'blanchedalmond'
-BLUE = 'blue'
-BLUEVIOLET = 'blueviolet'
-BROWN = 'brown'
-BURLYWOOD = 'burlywood'
-CADETBLUE = 'cadetblue'
-CHARTREUSE = 'chartreuse'
-CHOCOLATE = 'chocolate'
-CORAL = 'coral'
-CORNFLOWERBLUE = 'cornflowerblue'
-CORNSILK = 'cornsilk'
-CRIMSON = 'crimson'
-CYAN = 'cyan'
-DARKBLUE = 'darkblue'
-DARKCYAN = 'darkcyan'
-DARKGOLDENROD = 'darkgoldenrod'
-DARKGRAY = 'darkgray'
-DARKGREY = 'darkgrey'
-DARKGREEN = 'darkgreen'
-DARKKHAKI = 'darkkhaki'
-DARKMAGENTA = 'darkmagenta'
-DARKOLIVEGREEN = 'darkolivegreen'
-DARKORANGE = 'darkorange'
-DARKORCHID = 'darkorchid'
-DARKRED = 'darkred'
-DARKSALMON = 'darksalmon'
-DARKSEAGREEN = 'darkseagreen'
-DARKSLATEBLUE = 'darkslateblue'
-DARKSLATEGRAY = 'darkslategray'
-DARKSLATEGREY = 'darkslategrey'
-DARKTURQUOISE = 'darkturquoise'
-DARKVIOLET = 'darkviolet'
-DEEPPINK = 'deeppink'
-DEEPSKYBLUE = 'deepskyblue'
-DIMGRAY = 'dimgray'
-DIMGREY = 'dimgrey'
-DODGERBLUE = 'dodgerblue'
-FIREBRICK = 'firebrick'
-FLORALWHITE = 'floralwhite'
-FORESTGREEN = 'forestgreen'
-FUCHSIA = 'fuchsia'
-GAINSBORO = 'gainsboro'
-GHOSTWHITE = 'ghostwhite'
-GOLD = 'gold'
-GOLDENROD = 'goldenrod'
-GRAY = 'gray'
-GREY = 'grey'
-GREEN = 'green'
-GREENYELLOW = 'greenyellow'
-HONEYDEW = 'honeydew'
-HOTPINK = 'hotpink'
-INDIANRED = 'indianred'
-INDIGO = 'indigo'
-IVORY = 'ivory'
-KHAKI = 'khaki'
-LAVENDER = 'lavender'
-LAVENDERBLUSH = 'lavenderblush'
-LAWNGREEN = 'lawngreen'
-LEMONCHIFFON = 'lemonchiffon'
-LIGHTBLUE = 'lightblue'
-LIGHTCORAL = 'lightcoral'
-LIGHTCYAN = 'lightcyan'
-LIGHTGOLDENRODYELLOW = 'lightgoldenrodyellow'
-LIGHTGRAY = 'lightgray'
-LIGHTGREY = 'lightgrey'
-LIGHTGREEN = 'lightgreen'
-LIGHTPINK = 'lightpink'
-LIGHTSALMON = 'lightsalmon'
-LIGHTSEAGREEN = 'lightseagreen'
-LIGHTSKYBLUE = 'lightskyblue'
-LIGHTSLATEGRAY = 'lightslategray'
-LIGHTSLATEGREY = 'lightslategrey'
-LIGHTSTEELBLUE = 'lightsteelblue'
-LIGHTYELLOW = 'lightyellow'
-LIME = 'lime'
-LIMEGREEN = 'limegreen'
-LINEN = 'linen'
-MAGENTA = 'magenta'
-MAROON = 'maroon'
-MEDIUMAQUAMARINE = 'mediumaquamarine'
-MEDIUMBLUE = 'mediumblue'
-MEDIUMORCHID = 'mediumorchid'
-MEDIUMPURPLE = 'mediumpurple'
-MEDIUMSEAGREEN = 'mediumseagreen'
-MEDIUMSLATEBLUE = 'mediumslateblue'
-MEDIUMSPRINGGREEN = 'mediumspringgreen'
-MEDIUMTURQUOISE = 'mediumturquoise'
-MEDIUMVIOLETRED = 'mediumvioletred'
-MIDNIGHTBLUE = 'midnightblue'
-MINTCREAM = 'mintcream'
-MISTYROSE = 'mistyrose'
-MOCCASIN = 'moccasin'
-NAVAJOWHITE = 'navajowhite'
-NAVY = 'navy'
-OLDLACE = 'oldlace'
-OLIVE = 'olive'
-OLIVEDRAB = 'olivedrab'
-ORANGE = 'orange'
-ORANGERED = 'orangered'
-ORCHID = 'orchid'
-PALEGOLDENROD = 'palegoldenrod'
-PALEGREEN = 'palegreen'
-PALETURQUOISE = 'paleturquoise'
-PALEVIOLETRED = 'palevioletred'
-PAPAYAWHIP = 'papayawhip'
-PEACHPUFF = 'peachpuff'
-PERU = 'peru'
-PINK = 'pink'
-PLUM = 'plum'
-POWDERBLUE = 'powderblue'
-PURPLE = 'purple'
-REBECCAPURPLE = 'rebeccapurple'
-RED = 'red'
-ROSYBROWN = 'rosybrown'
-ROYALBLUE = 'royalblue'
-SADDLEBROWN = 'saddlebrown'
-SALMON = 'salmon'
-SANDYBROWN = 'sandybrown'
-SEAGREEN = 'seagreen'
-SEASHELL = 'seashell'
-SIENNA = 'sienna'
-SILVER = 'silver'
-SKYBLUE = 'skyblue'
-SLATEBLUE = 'slateblue'
-SLATEGRAY = 'slategray'
-SLATEGREY = 'slategrey'
-SNOW = 'snow'
-SPRINGGREEN = 'springgreen'
-STEELBLUE = 'steelblue'
-TAN = 'tan'
-TEAL = 'teal'
-THISTLE = 'thistle'
-TOMATO = 'tomato'
-TURQUOISE = 'turquoise'
-VIOLET = 'violet'
-WHEAT = 'wheat'
-WHITE = 'white'
-WHITESMOKE = 'whitesmoke'
-YELLOW = 'yellow'
-YELLOWGREEN = 'yellowgreen'
+TRANSPARENT = "transparent"
+
+ALICEBLUE = "aliceblue"
+ANTIQUEWHITE = "antiquewhite"
+AQUA = "aqua"
+AQUAMARINE = "aquamarine"
+AZURE = "azure"
+BEIGE = "beige"
+BISQUE = "bisque"
+BLACK = "black"
+BLANCHEDALMOND = "blanchedalmond"
+BLUE = "blue"
+BLUEVIOLET = "blueviolet"
+BROWN = "brown"
+BURLYWOOD = "burlywood"
+CADETBLUE = "cadetblue"
+CHARTREUSE = "chartreuse"
+CHOCOLATE = "chocolate"
+CORAL = "coral"
+CORNFLOWERBLUE = "cornflowerblue"
+CORNSILK = "cornsilk"
+CRIMSON = "crimson"
+CYAN = "cyan"
+DARKBLUE = "darkblue"
+DARKCYAN = "darkcyan"
+DARKGOLDENROD = "darkgoldenrod"
+DARKGRAY = "darkgray"
+DARKGREY = "darkgrey"
+DARKGREEN = "darkgreen"
+DARKKHAKI = "darkkhaki"
+DARKMAGENTA = "darkmagenta"
+DARKOLIVEGREEN = "darkolivegreen"
+DARKORANGE = "darkorange"
+DARKORCHID = "darkorchid"
+DARKRED = "darkred"
+DARKSALMON = "darksalmon"
+DARKSEAGREEN = "darkseagreen"
+DARKSLATEBLUE = "darkslateblue"
+DARKSLATEGRAY = "darkslategray"
+DARKSLATEGREY = "darkslategrey"
+DARKTURQUOISE = "darkturquoise"
+DARKVIOLET = "darkviolet"
+DEEPPINK = "deeppink"
+DEEPSKYBLUE = "deepskyblue"
+DIMGRAY = "dimgray"
+DIMGREY = "dimgrey"
+DODGERBLUE = "dodgerblue"
+FIREBRICK = "firebrick"
+FLORALWHITE = "floralwhite"
+FORESTGREEN = "forestgreen"
+FUCHSIA = "fuchsia"
+GAINSBORO = "gainsboro"
+GHOSTWHITE = "ghostwhite"
+GOLD = "gold"
+GOLDENROD = "goldenrod"
+GRAY = "gray"
+GREY = "grey"
+GREEN = "green"
+GREENYELLOW = "greenyellow"
+HONEYDEW = "honeydew"
+HOTPINK = "hotpink"
+INDIANRED = "indianred"
+INDIGO = "indigo"
+IVORY = "ivory"
+KHAKI = "khaki"
+LAVENDER = "lavender"
+LAVENDERBLUSH = "lavenderblush"
+LAWNGREEN = "lawngreen"
+LEMONCHIFFON = "lemonchiffon"
+LIGHTBLUE = "lightblue"
+LIGHTCORAL = "lightcoral"
+LIGHTCYAN = "lightcyan"
+LIGHTGOLDENRODYELLOW = "lightgoldenrodyellow"
+LIGHTGRAY = "lightgray"
+LIGHTGREY = "lightgrey"
+LIGHTGREEN = "lightgreen"
+LIGHTPINK = "lightpink"
+LIGHTSALMON = "lightsalmon"
+LIGHTSEAGREEN = "lightseagreen"
+LIGHTSKYBLUE = "lightskyblue"
+LIGHTSLATEGRAY = "lightslategray"
+LIGHTSLATEGREY = "lightslategrey"
+LIGHTSTEELBLUE = "lightsteelblue"
+LIGHTYELLOW = "lightyellow"
+LIME = "lime"
+LIMEGREEN = "limegreen"
+LINEN = "linen"
+MAGENTA = "magenta"
+MAROON = "maroon"
+MEDIUMAQUAMARINE = "mediumaquamarine"
+MEDIUMBLUE = "mediumblue"
+MEDIUMORCHID = "mediumorchid"
+MEDIUMPURPLE = "mediumpurple"
+MEDIUMSEAGREEN = "mediumseagreen"
+MEDIUMSLATEBLUE = "mediumslateblue"
+MEDIUMSPRINGGREEN = "mediumspringgreen"
+MEDIUMTURQUOISE = "mediumturquoise"
+MEDIUMVIOLETRED = "mediumvioletred"
+MIDNIGHTBLUE = "midnightblue"
+MINTCREAM = "mintcream"
+MISTYROSE = "mistyrose"
+MOCCASIN = "moccasin"
+NAVAJOWHITE = "navajowhite"
+NAVY = "navy"
+OLDLACE = "oldlace"
+OLIVE = "olive"
+OLIVEDRAB = "olivedrab"
+ORANGE = "orange"
+ORANGERED = "orangered"
+ORCHID = "orchid"
+PALEGOLDENROD = "palegoldenrod"
+PALEGREEN = "palegreen"
+PALETURQUOISE = "paleturquoise"
+PALEVIOLETRED = "palevioletred"
+PAPAYAWHIP = "papayawhip"
+PEACHPUFF = "peachpuff"
+PERU = "peru"
+PINK = "pink"
+PLUM = "plum"
+POWDERBLUE = "powderblue"
+PURPLE = "purple"
+REBECCAPURPLE = "rebeccapurple"
+RED = "red"
+ROSYBROWN = "rosybrown"
+ROYALBLUE = "royalblue"
+SADDLEBROWN = "saddlebrown"
+SALMON = "salmon"
+SANDYBROWN = "sandybrown"
+SEAGREEN = "seagreen"
+SEASHELL = "seashell"
+SIENNA = "sienna"
+SILVER = "silver"
+SKYBLUE = "skyblue"
+SLATEBLUE = "slateblue"
+SLATEGRAY = "slategray"
+SLATEGREY = "slategrey"
+SNOW = "snow"
+SPRINGGREEN = "springgreen"
+STEELBLUE = "steelblue"
+TAN = "tan"
+TEAL = "teal"
+THISTLE = "thistle"
+TOMATO = "tomato"
+TURQUOISE = "turquoise"
+VIOLET = "violet"
+WHEAT = "wheat"
+WHITE = "white"
+WHITESMOKE = "whitesmoke"
+YELLOW = "yellow"
+YELLOWGREEN = "yellowgreen"
diff --git a/src/travertino/declaration.py b/src/travertino/declaration.py
index 5476ae1..5a45641 100644
--- a/src/travertino/declaration.py
+++ b/src/travertino/declaration.py
@@ -3,9 +3,16 @@
class Choices:
"A class to define allowable data types for a property"
+
def __init__(
- self, *constants, default=False,
- string=False, integer=False, number=False, color=False):
+ self,
+ *constants,
+ default=False,
+ string=False,
+ integer=False,
+ number=False,
+ color=False,
+ ):
self.constants = set(constants)
self.default = default
@@ -14,7 +21,7 @@ def __init__(
self.number = number
self.color = color
- self._options = sorted(str(c).lower().replace('_', '-') for c in self.constants)
+ self._options = sorted(str(c).lower().replace("_", "-") for c in self.constants)
if self.string:
self._options.append("")
if self.integer:
@@ -48,7 +55,7 @@ def validate(self, value):
return color(value)
except ValueError:
pass
- if value == 'none':
+ if value == "none":
value = None
for const in self.constants:
if value == const:
@@ -65,6 +72,7 @@ class BaseStyle:
Exposes a dict-like interface.
"""
+
_PROPERTIES = {}
_ALL_PROPERTIES = {}
@@ -77,7 +85,9 @@ def __init__(self, **style):
######################################################################
def apply(self, property, value):
- raise NotImplementedError('Style must define an apply method') # pragma: no cover
+ raise NotImplementedError(
+ "Style must define an apply method"
+ ) # pragma: no cover
######################################################################
# Provide a dict-like interface
@@ -90,7 +100,7 @@ def reapply(self):
def update(self, **styles):
"Set multiple styles on the style definition."
for name, value in styles.items():
- name = name.replace('-', '_')
+ name = name.replace("-", "_")
if name not in self._ALL_PROPERTIES.get(self.__class__, set()):
raise NameError("Unknown style '%s'" % name)
@@ -102,26 +112,26 @@ def copy(self, applicator=None):
dup._applicator = applicator
for style in self._PROPERTIES.get(self.__class__, set()):
try:
- setattr(dup, style, getattr(self, '_%s' % style))
+ setattr(dup, style, getattr(self, "_%s" % style))
except AttributeError:
pass
return dup
def __getitem__(self, name):
- name = name.replace('-', '_')
+ name = name.replace("-", "_")
if name in self._PROPERTIES.get(self.__class__, set()):
return getattr(self, name)
raise KeyError(name)
def __setitem__(self, name, value):
- name = name.replace('-', '_')
+ name = name.replace("-", "_")
if name in self._PROPERTIES.get(self.__class__, set()):
setattr(self, name, value)
else:
raise KeyError(name)
def __delitem__(self, name):
- name = name.replace('-', '_')
+ name = name.replace("-", "_")
if name in self._PROPERTIES.get(self.__class__, set()):
delattr(self, name)
else:
@@ -131,7 +141,7 @@ def items(self):
result = []
for name in self._PROPERTIES.get(self.__class__, set()):
try:
- result.append((name, getattr(self, '_%s' % name)))
+ result.append((name, getattr(self, "_%s" % name)))
except AttributeError:
pass
return result
@@ -139,7 +149,7 @@ def items(self):
def keys(self):
result = set()
for name in self._PROPERTIES.get(self.__class__, set()):
- if hasattr(self, '_%s' % name):
+ if hasattr(self, "_%s" % name):
result.add(name)
return result
@@ -150,17 +160,13 @@ def __str__(self):
non_default = []
for name in self._PROPERTIES.get(self.__class__, set()):
try:
- non_default.append((
- name.replace('_', '-'),
- getattr(self, '_%s' % name)
- ))
+ non_default.append(
+ (name.replace("_", "-"), getattr(self, "_%s" % name))
+ )
except AttributeError:
pass
- return "; ".join(
- f"{name}: {value}"
- for name, value in sorted(non_default)
- )
+ return "; ".join(f"{name}: {value}" for name, value in sorted(non_default))
@classmethod
def validated_property(cls, name, choices, initial=None):
@@ -171,24 +177,26 @@ def validated_property(cls, name, choices, initial=None):
raise ValueError(f"Invalid initial value '{initial}' for property '{name}'")
def getter(self):
- return getattr(self, '_%s' % name, initial)
+ return getattr(self, "_%s" % name, initial)
def setter(self, value):
try:
value = choices.validate(value)
except ValueError:
- raise ValueError("Invalid value '{}' for property '{}'; Valid values are: {}".format(
- value, name, choices
- ))
+ raise ValueError(
+ "Invalid value '{}' for property '{}'; Valid values are: {}".format(
+ value, name, choices
+ )
+ )
- if value != getattr(self, '_%s' % name, initial):
- setattr(self, '_%s' % name, value)
+ if value != getattr(self, "_%s" % name, initial):
+ setattr(self, "_%s" % name, value)
self.apply(name, value)
def deleter(self):
try:
- value = getattr(self, '_%s' % name, initial)
- delattr(self, '_%s' % name)
+ value = getattr(self, "_%s" % name, initial)
+ delattr(self, "_%s" % name)
if value != initial:
self.apply(name, initial)
except AttributeError:
@@ -202,56 +210,57 @@ def deleter(self):
@classmethod
def directional_property(cls, name):
"Define a property attribute that proxies for top/right/bottom/left alternatives."
+
def getter(self):
return (
- getattr(self, name % '_top'),
- getattr(self, name % '_right'),
- getattr(self, name % '_bottom'),
- getattr(self, name % '_left'),
+ getattr(self, name % "_top"),
+ getattr(self, name % "_right"),
+ getattr(self, name % "_bottom"),
+ getattr(self, name % "_left"),
)
def setter(self, value):
if isinstance(value, tuple):
if len(value) == 4:
- setattr(self, name % '_top', value[0])
- setattr(self, name % '_right', value[1])
- setattr(self, name % '_bottom', value[2])
- setattr(self, name % '_left', value[3])
+ setattr(self, name % "_top", value[0])
+ setattr(self, name % "_right", value[1])
+ setattr(self, name % "_bottom", value[2])
+ setattr(self, name % "_left", value[3])
elif len(value) == 3:
- setattr(self, name % '_top', value[0])
- setattr(self, name % '_right', value[1])
- setattr(self, name % '_bottom', value[2])
- setattr(self, name % '_left', value[1])
+ setattr(self, name % "_top", value[0])
+ setattr(self, name % "_right", value[1])
+ setattr(self, name % "_bottom", value[2])
+ setattr(self, name % "_left", value[1])
elif len(value) == 2:
- setattr(self, name % '_top', value[0])
- setattr(self, name % '_right', value[1])
- setattr(self, name % '_bottom', value[0])
- setattr(self, name % '_left', value[1])
+ setattr(self, name % "_top", value[0])
+ setattr(self, name % "_right", value[1])
+ setattr(self, name % "_bottom", value[0])
+ setattr(self, name % "_left", value[1])
elif len(value) == 1:
- setattr(self, name % '_top', value[0])
- setattr(self, name % '_right', value[0])
- setattr(self, name % '_bottom', value[0])
- setattr(self, name % '_left', value[0])
+ setattr(self, name % "_top", value[0])
+ setattr(self, name % "_right", value[0])
+ setattr(self, name % "_bottom", value[0])
+ setattr(self, name % "_left", value[0])
else:
raise ValueError(
"Invalid value for '{}'; value must be an number, or a 1-4 tuple.".format(
- name % ''
+ name % ""
)
)
else:
- setattr(self, name % '_top', value)
- setattr(self, name % '_right', value)
- setattr(self, name % '_bottom', value)
- setattr(self, name % '_left', value)
+ setattr(self, name % "_top", value)
+ setattr(self, name % "_right", value)
+ setattr(self, name % "_bottom", value)
+ setattr(self, name % "_left", value)
def deleter(self):
- delattr(self, name % '_top')
- delattr(self, name % '_right')
- delattr(self, name % '_bottom')
- delattr(self, name % '_left')
+ delattr(self, name % "_top")
+ delattr(self, name % "_right")
+ delattr(self, name % "_bottom")
+ delattr(self, name % "_left")
- cls._ALL_PROPERTIES.setdefault(cls, set()).add(name % '')
- setattr(cls, name % '', property(getter, setter, deleter))
+ cls._ALL_PROPERTIES.setdefault(cls, set()).add(name % "")
+ setattr(cls, name % "", property(getter, setter, deleter))
# def list_property(name, choices, initial=None):
# "Define a property attribute that accepts a list of independently validated values."
diff --git a/src/travertino/fonts.py b/src/travertino/fonts.py
index df396ed..1fdfc9d 100644
--- a/src/travertino/fonts.py
+++ b/src/travertino/fonts.py
@@ -13,7 +13,9 @@
class Font:
def __init__(self, family, size, style=NORMAL, variant=NORMAL, weight=NORMAL):
- if (family[0] == "'" and family[-1] == "'") or (family[0] == '"' and family[-1] == '"'):
+ if (family[0] == "'" and family[-1] == "'") or (
+ family[0] == '"' and family[-1] == '"'
+ ):
self.family = family[1:-1]
else:
self.family = family
@@ -22,7 +24,7 @@ def __init__(self, family, size, style=NORMAL, variant=NORMAL, weight=NORMAL):
self.size = int(size)
except ValueError:
try:
- if size.strip().endswith('pt'):
+ if size.strip().endswith("pt"):
self.size = int(size[:-2])
else:
raise ValueError(f"Invalid font size {size!r}")
@@ -33,15 +35,19 @@ def __init__(self, family, size, style=NORMAL, variant=NORMAL, weight=NORMAL):
self.weight = weight if weight in FONT_WEIGHTS else NORMAL
def __hash__(self):
- return hash(('FONT', self.family, self.size, self.style, self.variant, self.weight))
+ return hash(
+ ("FONT", self.family, self.size, self.style, self.variant, self.weight)
+ )
def __repr__(self):
- return ''.format(
- '' if self.style is NORMAL else (self.style + ' '),
- '' if self.variant is NORMAL else (self.variant + ' '),
- '' if self.weight is NORMAL else (self.weight + ' '),
- 'system default size' if self.size == SYSTEM_DEFAULT_FONT_SIZE else f'{self.size}pt',
- self.family
+ return "".format(
+ "" if self.style is NORMAL else (self.style + " "),
+ "" if self.variant is NORMAL else (self.variant + " "),
+ "" if self.weight is NORMAL else (self.weight + " "),
+ "system default size"
+ if self.size == SYSTEM_DEFAULT_FONT_SIZE
+ else f"{self.size}pt",
+ self.family,
)
def __eq__(self, other):
@@ -55,31 +61,65 @@ def __eq__(self, other):
def normal_style(self):
"Generate a normal style version of this font"
- return Font(self.family, self.size, style=NORMAL, variant=self.variant, weight=self.weight)
+ return Font(
+ self.family,
+ self.size,
+ style=NORMAL,
+ variant=self.variant,
+ weight=self.weight,
+ )
def italic(self):
"Generate an italic version of this font"
- return Font(self.family, self.size, style=ITALIC, variant=self.variant, weight=self.weight)
+ return Font(
+ self.family,
+ self.size,
+ style=ITALIC,
+ variant=self.variant,
+ weight=self.weight,
+ )
def oblique(self):
"Generate an oblique version of this font"
- return Font(self.family, self.size, style=OBLIQUE, variant=self.variant, weight=self.weight)
+ return Font(
+ self.family,
+ self.size,
+ style=OBLIQUE,
+ variant=self.variant,
+ weight=self.weight,
+ )
def normal_variant(self):
"Generate a normal variant of this font"
- return Font(self.family, self.size, style=self.style, variant=NORMAL, weight=self.weight)
+ return Font(
+ self.family, self.size, style=self.style, variant=NORMAL, weight=self.weight
+ )
def small_caps(self):
"Generate a small-caps variant of this font"
- return Font(self.family, self.size, style=self.style, variant=SMALL_CAPS, weight=self.weight)
+ return Font(
+ self.family,
+ self.size,
+ style=self.style,
+ variant=SMALL_CAPS,
+ weight=self.weight,
+ )
def normal_weight(self):
"Generate a normal weight version of this font"
- return Font(self.family, self.size, style=self.style, variant=self.variant, weight=NORMAL)
+ return Font(
+ self.family,
+ self.size,
+ style=self.style,
+ variant=self.variant,
+ weight=NORMAL,
+ )
def bold(self):
"Generate a bold version of this font"
- return Font(self.family, self.size, style=self.style, variant=self.variant, weight=BOLD)
+ return Font(
+ self.family, self.size, style=self.style, variant=self.variant, weight=BOLD
+ )
def font(value):
@@ -102,7 +142,7 @@ def font(value):
return value
elif isinstance(value, str):
- parts = value.split(' ')
+ parts = value.split(" ")
style = None
variant = None
@@ -138,17 +178,17 @@ def font(value):
weight = part
else:
try:
- if part.endswith('pt'):
+ if part.endswith("pt"):
size = int(part[:-2])
else:
size = int(part)
except ValueError:
raise ValueError(f"Invalid size in font declaration '{value}'")
- if parts[0] == 'pt':
+ if parts[0] == "pt":
parts.pop(0)
- family = ' '.join(parts)
+ family = " ".join(parts)
return Font(family, size, style=style, variant=variant, weight=weight)
raise ValueError("Unknown font '%s'" % value)
diff --git a/src/travertino/layout.py b/src/travertino/layout.py
index b8e3af7..b8f656c 100644
--- a/src/travertino/layout.py
+++ b/src/travertino/layout.py
@@ -4,6 +4,7 @@ class Viewport:
rendered. It stores the size of the surface(in pixels), plus the
pixel density of the viewport.
"""
+
def __init__(self, width=0, height=0, dpi=None):
self.width = width
self.height = height
@@ -45,10 +46,12 @@ def __init__(self, node):
self._reset()
def __repr__(self):
- return '<{} ({}x{} @ {},{})>'.format(
+ return "<{} ({}x{} @ {},{})>".format(
self.__class__.__name__,
- self.content_width, self.content_height,
- self.absolute_content_left, self.absolute_content_top,
+ self.content_width,
+ self.content_height,
+ self.absolute_content_left,
+ self.absolute_content_top,
)
def _reset(self):
diff --git a/src/travertino/node.py b/src/travertino/node.py
index 84dd162..73ab0c9 100644
--- a/src/travertino/node.py
+++ b/src/travertino/node.py
@@ -1,4 +1,3 @@
-
class Node:
def __init__(self, style, applicator=None, children=None):
self.applicator = applicator
@@ -26,7 +25,7 @@ def root(self):
@property
def parent(self):
- """ The parent of this node.
+ """The parent of this node.
Returns:
The parent of this node. Returns None if this node is the root node.
@@ -35,7 +34,7 @@ def parent(self):
@property
def children(self):
- """ The children of this node.
+ """The children of this node.
This *always* returns a list, even if the node is a leaf
and cannot have children.
@@ -65,7 +64,7 @@ def add(self, child):
ValueError: If this node is a leaf, and cannot have children.
"""
if self._children is None:
- raise ValueError('Cannot add children')
+ raise ValueError("Cannot add children")
self._children.append(child)
child._parent = self
@@ -81,7 +80,7 @@ def insert(self, index, child):
ValueError: If this node is a leaf, and cannot have children.
"""
if self._children is None:
- raise ValueError('Cannot insert child')
+ raise ValueError("Cannot insert child")
self._children.insert(index, child)
child._parent = self
@@ -96,7 +95,7 @@ def remove(self, child):
ValueError: If this node is a leaf, and cannot have children.
"""
if self._children is None:
- raise ValueError('Cannot remove children')
+ raise ValueError("Cannot remove children")
self._children.remove(child)
child._parent = None
diff --git a/src/travertino/size.py b/src/travertino/size.py
index 726ee14..1104386 100644
--- a/src/travertino/size.py
+++ b/src/travertino/size.py
@@ -1,10 +1,11 @@
class at_least:
"An annotation to wrap around a value to describe that it is a minimum bound"
+
def __init__(self, value):
self.value = value
def __repr__(self):
- return f'at least {self.value}'
+ return f"at least {self.value}"
def __eq__(self, other):
try:
@@ -20,6 +21,7 @@ class BaseIntrinsicSize:
height: The height of the node.
ratio: The height between height and width. width = height * ratio
"""
+
def __init__(self, width=None, height=None, ratio=None, layout=None):
self._layout = layout
self._width = width
@@ -28,7 +30,7 @@ def __init__(self, width=None, height=None, ratio=None, layout=None):
self._ratio = None
def __repr__(self):
- return f'({self.width}, {self.height})'
+ return f"({self.width}, {self.height})"
@property
def width(self):
diff --git a/tests/colors/test_color_constructor.py b/tests/colors/test_color_constructor.py
index 99d4903..e07548a 100644
--- a/tests/colors/test_color_constructor.py
+++ b/tests/colors/test_color_constructor.py
@@ -38,7 +38,9 @@ def test_hsl_hash(self):
def test_hsla_hash(self):
self.assertEqual(hash(hsla(10, 0.2, 0.3, 0.5)), hash(hsla(10, 0.2, 0.3, 0.5)))
self.assertEqual(hash(hsla(10, 0.2, 0.3, 1.0)), hash(hsl(10, 0.2, 0.3)))
- self.assertNotEqual(hash(hsla(10, 0.3, 0.2, 0.5)), hash(hsla(10, 0.2, 0.3, 0.5)))
+ self.assertNotEqual(
+ hash(hsla(10, 0.3, 0.2, 0.5)), hash(hsla(10, 0.2, 0.3, 0.5))
+ )
self.assertNotEqual(hash(hsla(10, 0, 0, 0.5)), hash(rgba(10, 0, 0, 0.5)))
@@ -50,27 +52,27 @@ def test_hsl_blacks(self):
self.assertEqualColor(hsl(360, 0.0, 0.0), rgb(0x00, 0x00, 0x00))
def test_hsl_whites(self):
- self.assertEqualColor(hsl(0, 0.0, 1.0), rgb(0xff, 0xff, 0xff))
- self.assertEqualColor(hsl(60, 0.0, 1.0), rgb(0xff, 0xff, 0xff))
- self.assertEqualColor(hsl(180, 0.0, 1.0), rgb(0xff, 0xff, 0xff))
- self.assertEqualColor(hsl(240, 0.0, 1.0), rgb(0xff, 0xff, 0xff))
- self.assertEqualColor(hsl(360, 0.0, 1.0), rgb(0xff, 0xff, 0xff))
+ self.assertEqualColor(hsl(0, 0.0, 1.0), rgb(0xFF, 0xFF, 0xFF))
+ self.assertEqualColor(hsl(60, 0.0, 1.0), rgb(0xFF, 0xFF, 0xFF))
+ self.assertEqualColor(hsl(180, 0.0, 1.0), rgb(0xFF, 0xFF, 0xFF))
+ self.assertEqualColor(hsl(240, 0.0, 1.0), rgb(0xFF, 0xFF, 0xFF))
+ self.assertEqualColor(hsl(360, 0.0, 1.0), rgb(0xFF, 0xFF, 0xFF))
def test_hsl_grays(self):
self.assertEqualColor(hsl(0, 0.0, 0.2), rgb(0x33, 0x33, 0x33))
self.assertEqualColor(hsl(0, 0.0, 0.4), rgb(0x66, 0x66, 0x66))
self.assertEqualColor(hsl(0, 0.0, 0.5), rgb(0x80, 0x80, 0x80))
self.assertEqualColor(hsl(0, 0.0, 0.6), rgb(0x99, 0x99, 0x99))
- self.assertEqualColor(hsl(0, 0.0, 0.8), rgb(0xcc, 0xcc, 0xcc))
+ self.assertEqualColor(hsl(0, 0.0, 0.8), rgb(0xCC, 0xCC, 0xCC))
def test_hsl_primaries(self):
- self.assertEqualColor(hsl(0, 1.0, 0.5), rgb(0xff, 0x00, 0x00))
- self.assertEqualColor(hsl(60, 1.0, 0.5), rgb(0xff, 0xff, 0x00))
- self.assertEqualColor(hsl(120, 1.0, 0.5), rgb(0x00, 0xff, 0x00))
- self.assertEqualColor(hsl(180, 1.0, 0.5), rgb(0x00, 0xff, 0xff))
- self.assertEqualColor(hsl(240, 1.0, 0.5), rgb(0x00, 0x00, 0xff))
- self.assertEqualColor(hsl(300, 1.0, 0.5), rgb(0xff, 0x00, 0xff))
- self.assertEqualColor(hsl(360, 1.0, 0.5), rgb(0xff, 0x00, 0x00))
+ self.assertEqualColor(hsl(0, 1.0, 0.5), rgb(0xFF, 0x00, 0x00))
+ self.assertEqualColor(hsl(60, 1.0, 0.5), rgb(0xFF, 0xFF, 0x00))
+ self.assertEqualColor(hsl(120, 1.0, 0.5), rgb(0x00, 0xFF, 0x00))
+ self.assertEqualColor(hsl(180, 1.0, 0.5), rgb(0x00, 0xFF, 0xFF))
+ self.assertEqualColor(hsl(240, 1.0, 0.5), rgb(0x00, 0x00, 0xFF))
+ self.assertEqualColor(hsl(300, 1.0, 0.5), rgb(0xFF, 0x00, 0xFF))
+ self.assertEqualColor(hsl(360, 1.0, 0.5), rgb(0xFF, 0x00, 0x00))
def test_hsl_muted(self):
self.assertEqualColor(hsl(0, 0.25, 0.25), rgb(0x50, 0x30, 0x30))
@@ -81,21 +83,21 @@ def test_hsl_muted(self):
self.assertEqualColor(hsl(300, 0.25, 0.25), rgb(0x50, 0x30, 0x50))
self.assertEqualColor(hsl(360, 0.25, 0.25), rgb(0x50, 0x30, 0x30))
- self.assertEqualColor(hsl(0, 0.25, 0.75), rgb(0xcf, 0xaf, 0xaf))
- self.assertEqualColor(hsl(60, 0.25, 0.75), rgb(0xcf, 0xcf, 0xaf))
- self.assertEqualColor(hsl(120, 0.25, 0.75), rgb(0xaf, 0xcf, 0xaf))
- self.assertEqualColor(hsl(180, 0.25, 0.75), rgb(0xaf, 0xcf, 0xcf))
- self.assertEqualColor(hsl(240, 0.25, 0.75), rgb(0xaf, 0xaf, 0xcf))
- self.assertEqualColor(hsl(300, 0.25, 0.75), rgb(0xcf, 0xaf, 0xcf))
- self.assertEqualColor(hsl(360, 0.25, 0.75), rgb(0xcf, 0xaf, 0xaf))
-
- self.assertEqualColor(hsl(0, 0.75, 0.75), rgb(0xef, 0x8f, 0x8f))
- self.assertEqualColor(hsl(60, 0.75, 0.75), rgb(0xef, 0xef, 0x8f))
- self.assertEqualColor(hsl(120, 0.75, 0.75), rgb(0x8f, 0xef, 0x8f))
- self.assertEqualColor(hsl(180, 0.75, 0.75), rgb(0x8f, 0xef, 0xef))
- self.assertEqualColor(hsl(240, 0.75, 0.75), rgb(0x8f, 0x8f, 0xef))
- self.assertEqualColor(hsl(300, 0.75, 0.75), rgb(0xef, 0x8f, 0xef))
- self.assertEqualColor(hsl(360, 0.75, 0.75), rgb(0xef, 0x8f, 0x8f))
+ self.assertEqualColor(hsl(0, 0.25, 0.75), rgb(0xCF, 0xAF, 0xAF))
+ self.assertEqualColor(hsl(60, 0.25, 0.75), rgb(0xCF, 0xCF, 0xAF))
+ self.assertEqualColor(hsl(120, 0.25, 0.75), rgb(0xAF, 0xCF, 0xAF))
+ self.assertEqualColor(hsl(180, 0.25, 0.75), rgb(0xAF, 0xCF, 0xCF))
+ self.assertEqualColor(hsl(240, 0.25, 0.75), rgb(0xAF, 0xAF, 0xCF))
+ self.assertEqualColor(hsl(300, 0.25, 0.75), rgb(0xCF, 0xAF, 0xCF))
+ self.assertEqualColor(hsl(360, 0.25, 0.75), rgb(0xCF, 0xAF, 0xAF))
+
+ self.assertEqualColor(hsl(0, 0.75, 0.75), rgb(0xEF, 0x8F, 0x8F))
+ self.assertEqualColor(hsl(60, 0.75, 0.75), rgb(0xEF, 0xEF, 0x8F))
+ self.assertEqualColor(hsl(120, 0.75, 0.75), rgb(0x8F, 0xEF, 0x8F))
+ self.assertEqualColor(hsl(180, 0.75, 0.75), rgb(0x8F, 0xEF, 0xEF))
+ self.assertEqualColor(hsl(240, 0.75, 0.75), rgb(0x8F, 0x8F, 0xEF))
+ self.assertEqualColor(hsl(300, 0.75, 0.75), rgb(0xEF, 0x8F, 0xEF))
+ self.assertEqualColor(hsl(360, 0.75, 0.75), rgb(0xEF, 0x8F, 0x8F))
self.assertEqualColor(hsl(0, 0.75, 0.25), rgb(0x70, 0x10, 0x10))
self.assertEqualColor(hsl(60, 0.75, 0.25), rgb(0x70, 0x70, 0x10))
@@ -107,11 +109,11 @@ def test_hsl_muted(self):
def test_hsl_alpha(self):
self.assertEqualColor(hsla(60, 0.0, 0.0, 0.3), rgba(0x00, 0x00, 0x00, 0.3))
- self.assertEqualColor(hsla(60, 0.0, 1.0, 0.3), rgba(0xff, 0xff, 0xff, 0.3))
- self.assertEqualColor(hsla(60, 1.0, 0.5, 0.3), rgba(0xff, 0xff, 0x00, 0.3))
+ self.assertEqualColor(hsla(60, 0.0, 1.0, 0.3), rgba(0xFF, 0xFF, 0xFF, 0.3))
+ self.assertEqualColor(hsla(60, 1.0, 0.5, 0.3), rgba(0xFF, 0xFF, 0x00, 0.3))
self.assertEqualColor(hsla(60, 0.25, 0.25, 0.3), rgba(0x50, 0x50, 0x30, 0.3))
- self.assertEqualColor(hsla(60, 0.25, 0.75, 0.3), rgba(0xcf, 0xcf, 0xaf, 0.3))
- self.assertEqualColor(hsla(60, 0.75, 0.75, 0.3), rgba(0xef, 0xef, 0x8f, 0.3))
+ self.assertEqualColor(hsla(60, 0.25, 0.75, 0.3), rgba(0xCF, 0xCF, 0xAF, 0.3))
+ self.assertEqualColor(hsla(60, 0.75, 0.75, 0.3), rgba(0xEF, 0xEF, 0x8F, 0.3))
self.assertEqualColor(hsla(60, 0.75, 0.25, 0.3), rgba(0x70, 0x70, 0x10, 0.3))
@@ -137,116 +139,116 @@ def test_noop(self):
self.assertEqualHSL(hsl(1, 0.2, 0.3), hsl(1, 0.2, 0.3))
def test_rgb(self):
- self.assertEqualColor('rgb(1,2,3)', rgb(1, 2, 3))
- self.assertEqualColor('rgb(1, 2, 3)', rgb(1, 2, 3))
- self.assertEqualColor('rgb( 1 , 2 , 3)', rgb(1, 2, 3))
+ self.assertEqualColor("rgb(1,2,3)", rgb(1, 2, 3))
+ self.assertEqualColor("rgb(1, 2, 3)", rgb(1, 2, 3))
+ self.assertEqualColor("rgb( 1 , 2 , 3)", rgb(1, 2, 3))
- self.assertEqualColor('#123', rgb(0x11, 0x22, 0x33))
- self.assertEqualColor('#112233', rgb(0x11, 0x22, 0x33))
- self.assertEqualColor('#abc', rgb(0xaa, 0xbb, 0xcc))
- self.assertEqualColor('#ABC', rgb(0xaa, 0xbb, 0xcc))
- self.assertEqualColor('#abcdef', rgb(0xab, 0xcd, 0xef))
- self.assertEqualColor('#ABCDEF', rgb(0xab, 0xcd, 0xef))
+ self.assertEqualColor("#123", rgb(0x11, 0x22, 0x33))
+ self.assertEqualColor("#112233", rgb(0x11, 0x22, 0x33))
+ self.assertEqualColor("#abc", rgb(0xAA, 0xBB, 0xCC))
+ self.assertEqualColor("#ABC", rgb(0xAA, 0xBB, 0xCC))
+ self.assertEqualColor("#abcdef", rgb(0xAB, 0xCD, 0xEF))
+ self.assertEqualColor("#ABCDEF", rgb(0xAB, 0xCD, 0xEF))
with self.assertRaises(ValueError):
- color('rgb(10, 20)')
+ color("rgb(10, 20)")
with self.assertRaises(ValueError):
- color('rgb(a, 10, 20)')
+ color("rgb(a, 10, 20)")
with self.assertRaises(ValueError):
- color('rgb(10, b, 20)')
+ color("rgb(10, b, 20)")
with self.assertRaises(ValueError):
- color('rgb(10, 20, c)')
+ color("rgb(10, 20, c)")
with self.assertRaises(ValueError):
- color('rgb(10, 20, 30, 0.5)')
+ color("rgb(10, 20, 30, 0.5)")
def test_rgba(self):
- self.assertEqualColor('rgba(1,2,3,0.5)', rgba(1, 2, 3, 0.5))
- self.assertEqualColor('rgba(1, 2, 3, 0.5)', rgba(1, 2, 3, 0.5))
- self.assertEqualColor('rgba( 1 , 2 , 3 , 0.5)', rgba(1, 2, 3, 0.5))
+ self.assertEqualColor("rgba(1,2,3,0.5)", rgba(1, 2, 3, 0.5))
+ self.assertEqualColor("rgba(1, 2, 3, 0.5)", rgba(1, 2, 3, 0.5))
+ self.assertEqualColor("rgba( 1 , 2 , 3 , 0.5)", rgba(1, 2, 3, 0.5))
- self.assertEqualColor('#1234', rgba(0x11, 0x22, 0x33, 0.2666))
- self.assertEqualColor('#11223344', rgba(0x11, 0x22, 0x33, 0.2666))
- self.assertEqualColor('#abcd', rgba(0xaa, 0xbb, 0xcc, 0.8666))
- self.assertEqualColor('#ABCD', rgba(0xaa, 0xbb, 0xcc, 0.8666))
- self.assertEqualColor('#abcdefba', rgba(0xab, 0xcd, 0xef, 0.7294))
- self.assertEqualColor('#ABCDEFBA', rgba(0xab, 0xcd, 0xef, 0.7294))
+ self.assertEqualColor("#1234", rgba(0x11, 0x22, 0x33, 0.2666))
+ self.assertEqualColor("#11223344", rgba(0x11, 0x22, 0x33, 0.2666))
+ self.assertEqualColor("#abcd", rgba(0xAA, 0xBB, 0xCC, 0.8666))
+ self.assertEqualColor("#ABCD", rgba(0xAA, 0xBB, 0xCC, 0.8666))
+ self.assertEqualColor("#abcdefba", rgba(0xAB, 0xCD, 0xEF, 0.7294))
+ self.assertEqualColor("#ABCDEFBA", rgba(0xAB, 0xCD, 0xEF, 0.7294))
with self.assertRaises(ValueError):
- color('rgba(10, 20, 30)')
+ color("rgba(10, 20, 30)")
with self.assertRaises(ValueError):
- color('rgba(a, 10, 20, 0.5)')
+ color("rgba(a, 10, 20, 0.5)")
with self.assertRaises(ValueError):
- color('rgba(10, b, 20, 0.5)')
+ color("rgba(10, b, 20, 0.5)")
with self.assertRaises(ValueError):
- color('rgba(10, 20, c, 0.5)')
+ color("rgba(10, 20, c, 0.5)")
with self.assertRaises(ValueError):
- color('rgba(10, 20, 30, c)')
+ color("rgba(10, 20, 30, c)")
with self.assertRaises(ValueError):
- color('rgba(10, 20, 30, 0.5, 5)')
+ color("rgba(10, 20, 30, 0.5, 5)")
def test_hsl(self):
- self.assertEqualHSL('hsl(1,20%,30%)', hsl(1, 0.2, 0.3))
- self.assertEqualHSL('hsl(1, 20%, 30%)', hsl(1, 0.2, 0.3))
- self.assertEqualHSL('hsl( 1, 20% , 30%)', hsl(1, 0.2, 0.3))
+ self.assertEqualHSL("hsl(1,20%,30%)", hsl(1, 0.2, 0.3))
+ self.assertEqualHSL("hsl(1, 20%, 30%)", hsl(1, 0.2, 0.3))
+ self.assertEqualHSL("hsl( 1, 20% , 30%)", hsl(1, 0.2, 0.3))
with self.assertRaises(ValueError):
- color('hsl(1, 20%)')
+ color("hsl(1, 20%)")
with self.assertRaises(ValueError):
- color('hsl(a, 20%, 30%)')
+ color("hsl(a, 20%, 30%)")
with self.assertRaises(ValueError):
- color('hsl(1, a, 30%)')
+ color("hsl(1, a, 30%)")
with self.assertRaises(ValueError):
- color('hsl(1, 20%, a)')
+ color("hsl(1, 20%, a)")
with self.assertRaises(ValueError):
- color('hsl(1, 20%, 30%, 0.5)')
+ color("hsl(1, 20%, 30%, 0.5)")
def test_hsla(self):
- self.assertEqualHSL('hsla(1,20%,30%,0.5)', hsla(1, 0.2, 0.3, 0.5))
- self.assertEqualHSL('hsla(1, 20%, 30%, 0.5)', hsla(1, 0.2, 0.3, 0.5))
- self.assertEqualHSL('hsla( 1, 20% , 30% , 0.5)', hsla(1, 0.2, 0.3, 0.5))
+ self.assertEqualHSL("hsla(1,20%,30%,0.5)", hsla(1, 0.2, 0.3, 0.5))
+ self.assertEqualHSL("hsla(1, 20%, 30%, 0.5)", hsla(1, 0.2, 0.3, 0.5))
+ self.assertEqualHSL("hsla( 1, 20% , 30% , 0.5)", hsla(1, 0.2, 0.3, 0.5))
with self.assertRaises(ValueError):
- color('hsla(1, 20%, 30%)')
+ color("hsla(1, 20%, 30%)")
with self.assertRaises(ValueError):
- color('hsla(a, 20%, 30%, 0.5)')
+ color("hsla(a, 20%, 30%, 0.5)")
with self.assertRaises(ValueError):
- color('hsla(1, a, 30%, 0.5)')
+ color("hsla(1, a, 30%, 0.5)")
with self.assertRaises(ValueError):
- color('hsla(1, 20%, a, 0.5)')
+ color("hsla(1, 20%, a, 0.5)")
with self.assertRaises(ValueError):
- color('hsla(1, 20%, 30%, a)')
+ color("hsla(1, 20%, 30%, a)")
with self.assertRaises(ValueError):
- color('hsla(1, 20%, 30%, 0.5, 5)')
+ color("hsla(1, 20%, 30%, 0.5, 5)")
def test_named_color(self):
- self.assertEqualColor('Red', rgb(0xFF, 0, 0))
- self.assertEqualColor('RED', rgb(0xFF, 0, 0))
- self.assertEqualColor('red', rgb(0xFF, 0, 0))
- self.assertEqualColor('rEd', rgb(0xFF, 0, 0))
+ self.assertEqualColor("Red", rgb(0xFF, 0, 0))
+ self.assertEqualColor("RED", rgb(0xFF, 0, 0))
+ self.assertEqualColor("red", rgb(0xFF, 0, 0))
+ self.assertEqualColor("rEd", rgb(0xFF, 0, 0))
- self.assertEqualColor('CornflowerBlue', rgb(0x64, 0x95, 0xED))
- self.assertEqualColor('cornflowerblue', rgb(0x64, 0x95, 0xED))
- self.assertEqualColor('CORNFLOWERBLUE', rgb(0x64, 0x95, 0xED))
- self.assertEqualColor('Cornflowerblue', rgb(0x64, 0x95, 0xED))
- self.assertEqualColor('CoRnFlOwErBlUe', rgb(0x64, 0x95, 0xED))
+ self.assertEqualColor("CornflowerBlue", rgb(0x64, 0x95, 0xED))
+ self.assertEqualColor("cornflowerblue", rgb(0x64, 0x95, 0xED))
+ self.assertEqualColor("CORNFLOWERBLUE", rgb(0x64, 0x95, 0xED))
+ self.assertEqualColor("Cornflowerblue", rgb(0x64, 0x95, 0xED))
+ self.assertEqualColor("CoRnFlOwErBlUe", rgb(0x64, 0x95, 0xED))
with self.assertRaises(ValueError):
- color('not a color')
+ color("not a color")
diff --git a/tests/colors/test_color_exceptions.py b/tests/colors/test_color_exceptions.py
index 228cce4..ea124f4 100644
--- a/tests/colors/test_color_exceptions.py
+++ b/tests/colors/test_color_exceptions.py
@@ -1,10 +1,9 @@
from unittest import TestCase
-from travertino.colors import rgb, rgba, hsl, hsla
+from travertino.colors import hsl, hsla, rgb, rgba
class RGBColorExceptionTests(TestCase):
-
def test_negative_red(self):
self.assertRaisesRegex(
ValueError, "^red value should be between 0-255. Got -1$", rgb, -1, 120, 10
@@ -17,7 +16,7 @@ def test_too_big_red(self):
rgb,
256,
120,
- 10
+ 10,
)
def test_negative_green(self):
@@ -27,7 +26,7 @@ def test_negative_green(self):
rgb,
120,
-1,
- 10
+ 10,
)
def test_too_big_green(self):
@@ -37,7 +36,7 @@ def test_too_big_green(self):
rgb,
120,
256,
- 10
+ 10,
)
def test_negative_blue(self):
@@ -47,7 +46,7 @@ def test_negative_blue(self):
rgb,
120,
10,
- -1
+ -1,
)
def test_too_big_blue(self):
@@ -57,12 +56,11 @@ def test_too_big_blue(self):
rgb,
120,
10,
- 256
+ 256,
)
class RGBAColorExceptionTests(TestCase):
-
def test_negative_red(self):
self.assertRaisesRegex(
ValueError,
@@ -71,7 +69,7 @@ def test_negative_red(self):
-1,
120,
10,
- 0.5
+ 0.5,
)
def test_too_big_red(self):
@@ -82,7 +80,7 @@ def test_too_big_red(self):
256,
120,
10,
- 0.5
+ 0.5,
)
def test_negative_green(self):
@@ -93,7 +91,7 @@ def test_negative_green(self):
120,
-1,
10,
- 0.5
+ 0.5,
)
def test_too_big_green(self):
@@ -104,7 +102,7 @@ def test_too_big_green(self):
120,
256,
10,
- 0.5
+ 0.5,
)
def test_negative_blue(self):
@@ -115,7 +113,7 @@ def test_negative_blue(self):
120,
10,
-1,
- 0.5
+ 0.5,
)
def test_too_big_blue(self):
@@ -126,7 +124,7 @@ def test_too_big_blue(self):
120,
10,
256,
- 0.5
+ 0.5,
)
def test_negative_alpha(self):
@@ -137,7 +135,7 @@ def test_negative_alpha(self):
120,
10,
60,
- -0.5
+ -0.5,
)
def test_too_big_alpha(self):
@@ -148,15 +146,19 @@ def test_too_big_alpha(self):
120,
10,
60,
- 1.1
+ 1.1,
)
class HSLColorExceptionTests(TestCase):
-
def test_negative_hue(self):
self.assertRaisesRegex(
- ValueError, "^hue value should be between 0-360. Got -1$", hsl, -1, 0.5, 0.8
+ ValueError,
+ "^hue value should be between 0-360. Got -1$",
+ hsl,
+ -1,
+ 0.5,
+ 0.8,
)
def test_too_big_hue(self):
@@ -166,7 +168,7 @@ def test_too_big_hue(self):
hsl,
361,
0.5,
- 0.8
+ 0.8,
)
def test_negative_saturation(self):
@@ -176,7 +178,7 @@ def test_negative_saturation(self):
hsl,
120,
-0.1,
- 0.8
+ 0.8,
)
def test_too_big_saturation(self):
@@ -186,7 +188,7 @@ def test_too_big_saturation(self):
hsl,
120,
1.1,
- 0.8
+ 0.8,
)
def test_negative_lightness(self):
@@ -196,7 +198,7 @@ def test_negative_lightness(self):
hsl,
120,
0.8,
- -0.1
+ -0.1,
)
def test_too_big_lightness(self):
@@ -206,12 +208,11 @@ def test_too_big_lightness(self):
hsl,
120,
0.8,
- 1.1
+ 1.1,
)
class HSLAColorExceptionTests(TestCase):
-
def test_negative_hue(self):
self.assertRaisesRegex(
ValueError,
@@ -220,7 +221,7 @@ def test_negative_hue(self):
-1,
0.5,
0.8,
- 0.5
+ 0.5,
)
def test_too_big_hue(self):
@@ -231,7 +232,7 @@ def test_too_big_hue(self):
361,
0.5,
0.8,
- 0.5
+ 0.5,
)
def test_negative_saturation(self):
@@ -242,7 +243,7 @@ def test_negative_saturation(self):
120,
-0.1,
0.8,
- 0.5
+ 0.5,
)
def test_too_big_saturation(self):
@@ -253,7 +254,7 @@ def test_too_big_saturation(self):
120,
1.1,
0.8,
- 0.5
+ 0.5,
)
def test_negative_lightness(self):
@@ -264,7 +265,7 @@ def test_negative_lightness(self):
120,
0.8,
-0.1,
- 0.5
+ 0.5,
)
def test_too_big_lightness(self):
@@ -275,7 +276,7 @@ def test_too_big_lightness(self):
120,
0.8,
1.1,
- 0.5
+ 0.5,
)
def test_negative_alpha(self):
@@ -297,5 +298,5 @@ def test_too_big_alpha(self):
120,
0.8,
0.5,
- 1.1
+ 1.1,
)
diff --git a/tests/test_choices.py b/tests/test_choices.py
index eb49142..ad4d80b 100644
--- a/tests/test_choices.py
+++ b/tests/test_choices.py
@@ -2,22 +2,23 @@
from unittest.mock import Mock
from travertino.colors import NAMED_COLOR, rgb
-from travertino.constants import TOP, GOLDENROD, REBECCAPURPLE
-from travertino.declaration import Choices, BaseStyle
+from travertino.constants import GOLDENROD, REBECCAPURPLE, TOP
+from travertino.declaration import BaseStyle, Choices
class PropertyChoiceTests(TestCase):
def assert_property(self, obj, value, check_mock=True):
self.assertEqual(obj.prop, value)
if check_mock:
- obj.apply.assert_called_once_with('prop', value)
+ obj.apply.assert_called_once_with("prop", value)
obj.apply.reset_mock()
def test_none(self):
class MyObject(BaseStyle):
def __init__(self):
self.apply = Mock()
- MyObject.validated_property('prop', choices=Choices(None), initial=None)
+
+ MyObject.validated_property("prop", choices=Choices(None), initial=None)
obj = MyObject()
self.assertIsNone(obj.prop)
@@ -32,38 +33,41 @@ def __init__(self):
obj.prop = REBECCAPURPLE
with self.assertRaises(ValueError):
- obj.prop = '#112233'
+ obj.prop = "#112233"
with self.assertRaises(ValueError):
- obj.prop = 'a'
+ obj.prop = "a"
with self.assertRaises(ValueError):
- obj.prop = 'b'
+ obj.prop = "b"
obj.prop = None
self.assert_property(obj, None, check_mock=False)
- obj.prop = 'none'
+ obj.prop = "none"
self.assert_property(obj, None, check_mock=False)
# Check the error message
try:
- obj.prop = 'invalid'
- self.fail('Should raise ValueError')
+ obj.prop = "invalid"
+ self.fail("Should raise ValueError")
except ValueError as v:
self.assertEqual(
str(v),
- "Invalid value 'invalid' for property 'prop'; Valid values are: none"
+ "Invalid value 'invalid' for property 'prop'; Valid values are: none",
)
def test_allow_string(self):
class MyObject(BaseStyle):
def __init__(self):
self.apply = Mock()
- MyObject.validated_property('prop', choices=Choices(string=True), initial='start')
+
+ MyObject.validated_property(
+ "prop", choices=Choices(string=True), initial="start"
+ )
obj = MyObject()
- self.assertEqual(obj.prop, 'start')
+ self.assertEqual(obj.prop, "start")
with self.assertRaises(ValueError):
obj.prop = 10
@@ -72,38 +76,39 @@ def __init__(self):
obj.prop = 3.14159
obj.prop = REBECCAPURPLE
- self.assert_property(obj, 'rebeccapurple')
+ self.assert_property(obj, "rebeccapurple")
- obj.prop = '#112233'
- self.assert_property(obj, '#112233')
+ obj.prop = "#112233"
+ self.assert_property(obj, "#112233")
- obj.prop = 'a'
- self.assert_property(obj, 'a')
+ obj.prop = "a"
+ self.assert_property(obj, "a")
- obj.prop = 'b'
- self.assert_property(obj, 'b')
+ obj.prop = "b"
+ self.assert_property(obj, "b")
with self.assertRaises(ValueError):
obj.prop = None
- obj.prop = 'none'
- self.assert_property(obj, 'none')
+ obj.prop = "none"
+ self.assert_property(obj, "none")
# Check the error message
try:
obj.prop = 99
- self.fail('Should raise ValueError')
+ self.fail("Should raise ValueError")
except ValueError as v:
self.assertEqual(
str(v),
- "Invalid value '99' for property 'prop'; Valid values are: "
+ "Invalid value '99' for property 'prop'; Valid values are: ",
)
def test_allow_integer(self):
class MyObject(BaseStyle):
def __init__(self):
self.apply = Mock()
- MyObject.validated_property('prop', choices=Choices(integer=True), initial=0)
+
+ MyObject.validated_property("prop", choices=Choices(integer=True), initial=0)
obj = MyObject()
self.assertEqual(obj.prop, 0)
@@ -120,35 +125,36 @@ def __init__(self):
obj.prop = REBECCAPURPLE
with self.assertRaises(ValueError):
- obj.prop = '#112233'
+ obj.prop = "#112233"
with self.assertRaises(ValueError):
- obj.prop = 'a'
+ obj.prop = "a"
with self.assertRaises(ValueError):
- obj.prop = 'b'
+ obj.prop = "b"
with self.assertRaises(ValueError):
obj.prop = None
with self.assertRaises(ValueError):
- obj.prop = 'none'
+ obj.prop = "none"
# Check the error message
try:
- obj.prop = 'invalid'
- self.fail('Should raise ValueError')
+ obj.prop = "invalid"
+ self.fail("Should raise ValueError")
except ValueError as v:
self.assertEqual(
str(v),
- "Invalid value 'invalid' for property 'prop'; Valid values are: "
+ "Invalid value 'invalid' for property 'prop'; Valid values are: ",
)
def test_allow_number(self):
class MyObject(BaseStyle):
def __init__(self):
self.apply = Mock()
- MyObject.validated_property('prop', choices=Choices(number=True), initial=0)
+
+ MyObject.validated_property("prop", choices=Choices(number=True), initial=0)
obj = MyObject()
self.assertEqual(obj.prop, 0)
@@ -163,35 +169,38 @@ def __init__(self):
obj.prop = REBECCAPURPLE
with self.assertRaises(ValueError):
- obj.prop = '#112233'
+ obj.prop = "#112233"
with self.assertRaises(ValueError):
- obj.prop = 'a'
+ obj.prop = "a"
with self.assertRaises(ValueError):
- obj.prop = 'b'
+ obj.prop = "b"
with self.assertRaises(ValueError):
obj.prop = None
with self.assertRaises(ValueError):
- obj.prop = 'none'
+ obj.prop = "none"
# Check the error message
try:
- obj.prop = 'invalid'
- self.fail('Should raise ValueError')
+ obj.prop = "invalid"
+ self.fail("Should raise ValueError")
except ValueError as v:
self.assertEqual(
str(v),
- "Invalid value 'invalid' for property 'prop'; Valid values are: "
+ "Invalid value 'invalid' for property 'prop'; Valid values are: ",
)
def test_allow_color(self):
class MyObject(BaseStyle):
def __init__(self):
self.apply = Mock()
- MyObject.validated_property('prop', choices=Choices(color=True), initial='goldenrod')
+
+ MyObject.validated_property(
+ "prop", choices=Choices(color=True), initial="goldenrod"
+ )
obj = MyObject()
self.assertEqual(obj.prop, NAMED_COLOR[GOLDENROD])
@@ -205,39 +214,42 @@ def __init__(self):
obj.prop = REBECCAPURPLE
self.assert_property(obj, NAMED_COLOR[REBECCAPURPLE])
- obj.prop = '#112233'
+ obj.prop = "#112233"
self.assert_property(obj, rgb(0x11, 0x22, 0x33))
with self.assertRaises(ValueError):
- obj.prop = 'a'
+ obj.prop = "a"
with self.assertRaises(ValueError):
- obj.prop = 'b'
+ obj.prop = "b"
with self.assertRaises(ValueError):
obj.prop = None
with self.assertRaises(ValueError):
- obj.prop = 'none'
+ obj.prop = "none"
# Check the error message
try:
- obj.prop = 'invalid'
- self.fail('Should raise ValueError')
+ obj.prop = "invalid"
+ self.fail("Should raise ValueError")
except ValueError as v:
self.assertEqual(
str(v),
- "Invalid value 'invalid' for property 'prop'; Valid values are: "
+ "Invalid value 'invalid' for property 'prop'; Valid values are: ",
)
def test_values(self):
class MyObject(BaseStyle):
def __init__(self):
self.apply = Mock()
- MyObject.validated_property('prop', choices=Choices('a', 'b', None), initial='a')
+
+ MyObject.validated_property(
+ "prop", choices=Choices("a", "b", None), initial="a"
+ )
obj = MyObject()
- self.assertEqual(obj.prop, 'a')
+ self.assertEqual(obj.prop, "a")
with self.assertRaises(ValueError):
obj.prop = 10
@@ -249,41 +261,39 @@ def __init__(self):
obj.prop = REBECCAPURPLE
with self.assertRaises(ValueError):
- obj.prop = '#112233'
+ obj.prop = "#112233"
obj.prop = None
self.assert_property(obj, None)
- obj.prop = 'a'
- self.assert_property(obj, 'a')
+ obj.prop = "a"
+ self.assert_property(obj, "a")
- obj.prop = 'none'
+ obj.prop = "none"
self.assert_property(obj, None)
- obj.prop = 'b'
- self.assert_property(obj, 'b')
+ obj.prop = "b"
+ self.assert_property(obj, "b")
# Check the error message
try:
- obj.prop = 'invalid'
- self.fail('Should raise ValueError')
+ obj.prop = "invalid"
+ self.fail("Should raise ValueError")
except ValueError as v:
self.assertEqual(
str(v),
- "Invalid value 'invalid' for property 'prop'; Valid values are: a, b, none"
+ "Invalid value 'invalid' for property 'prop'; Valid values are: a, b, none",
)
def test_multiple_choices(self):
class MyObject(BaseStyle):
def __init__(self):
self.apply = Mock()
+
MyObject.validated_property(
- 'prop',
- choices=Choices(
- 'a', 'b', None,
- number=True, color=True
- ),
- initial=None
+ "prop",
+ choices=Choices("a", "b", None, number=True, color=True),
+ initial=None,
)
obj = MyObject()
@@ -297,37 +307,38 @@ def __init__(self):
obj.prop = REBECCAPURPLE
self.assert_property(obj, NAMED_COLOR[REBECCAPURPLE])
- obj.prop = '#112233'
+ obj.prop = "#112233"
self.assert_property(obj, rgb(0x11, 0x22, 0x33))
obj.prop = None
self.assert_property(obj, None)
- obj.prop = 'a'
- self.assert_property(obj, 'a')
+ obj.prop = "a"
+ self.assert_property(obj, "a")
- obj.prop = 'none'
+ obj.prop = "none"
self.assert_property(obj, None)
- obj.prop = 'b'
- self.assert_property(obj, 'b')
+ obj.prop = "b"
+ self.assert_property(obj, "b")
# Check the error message
try:
- obj.prop = 'invalid'
- self.fail('Should raise ValueError')
+ obj.prop = "invalid"
+ self.fail("Should raise ValueError")
except ValueError as v:
self.assertEqual(
str(v),
"Invalid value 'invalid' for property 'prop'; "
- "Valid values are: a, b, none, , "
+ "Valid values are: a, b, none, , ",
)
def test_string_symbol(self):
class MyObject(BaseStyle):
def __init__(self):
self.apply = Mock()
- MyObject.validated_property('prop', choices=Choices(TOP, None), initial=None)
+
+ MyObject.validated_property("prop", choices=Choices(TOP, None), initial=None)
obj = MyObject()
@@ -335,7 +346,7 @@ def __init__(self):
# We can't just use the string directly, though - that would
# get optimized by the compiler. So we create a string and
# transform it into the value we want.
- val = 'TOP'
+ val = "TOP"
obj.prop = val.lower()
# Both equality and instance checking should work.
diff --git a/tests/test_declaration.py b/tests/test_declaration.py
index d9bfaaa..26b7d92 100644
--- a/tests/test_declaration.py
+++ b/tests/test_declaration.py
@@ -3,10 +3,9 @@
from travertino.declaration import BaseStyle, Choices
-
-VALUE1 = 'value1'
-VALUE2 = 'value2'
-VALUE3 = 'value3'
+VALUE1 = "value1"
+VALUE2 = "value2"
+VALUE3 = "value3"
VALUE_CHOICES = Choices(VALUE1, VALUE2, VALUE3, None, integer=True)
DEFAULT_VALUE_CHOICES = Choices(VALUE1, VALUE2, VALUE3, integer=True, default=True)
@@ -18,20 +17,20 @@ def __init__(self, **kwargs):
# Some properties with explicit initial values
-Style.validated_property('explicit_const', choices=VALUE_CHOICES, initial=VALUE1)
-Style.validated_property('explicit_value', choices=VALUE_CHOICES, initial=0)
-Style.validated_property('explicit_none', choices=VALUE_CHOICES, initial=None)
+Style.validated_property("explicit_const", choices=VALUE_CHOICES, initial=VALUE1)
+Style.validated_property("explicit_value", choices=VALUE_CHOICES, initial=0)
+Style.validated_property("explicit_none", choices=VALUE_CHOICES, initial=None)
# A property with an implicit default value.
# This usually means the default is platform specific.
-Style.validated_property('implicit', choices=DEFAULT_VALUE_CHOICES)
+Style.validated_property("implicit", choices=DEFAULT_VALUE_CHOICES)
# A set of directional properties
-Style.validated_property('thing_top', choices=VALUE_CHOICES, initial=0)
-Style.validated_property('thing_right', choices=VALUE_CHOICES, initial=0)
-Style.validated_property('thing_bottom', choices=VALUE_CHOICES, initial=0)
-Style.validated_property('thing_left', choices=VALUE_CHOICES, initial=0)
-Style.directional_property('thing%s')
+Style.validated_property("thing_top", choices=VALUE_CHOICES, initial=0)
+Style.validated_property("thing_right", choices=VALUE_CHOICES, initial=0)
+Style.validated_property("thing_bottom", choices=VALUE_CHOICES, initial=0)
+Style.validated_property("thing_left", choices=VALUE_CHOICES, initial=0)
+Style.directional_property("thing%s")
class TestNode:
@@ -48,7 +47,10 @@ def test_invalid_style(self):
# Define a style that has an invalid initial value on a validated property
class BadStyle(BaseStyle):
pass
- BadStyle.validated_property('value', choices=VALUE_CHOICES, initial='something')
+
+ BadStyle.validated_property(
+ "value", choices=VALUE_CHOICES, initial="something"
+ )
def test_create_and_copy(self):
style = Style(explicit_const=VALUE2, implicit=VALUE3)
@@ -62,16 +64,19 @@ def test_reapply(self):
node = TestNode(style=Style(explicit_const=VALUE2, implicit=VALUE3))
node.style.reapply()
- node.style.apply.assert_has_calls([
- call('explicit_const', VALUE2),
- call('explicit_value', 0),
- call('explicit_none', None),
- call('implicit', VALUE3),
- call('thing_left', 0),
- call('thing_top', 0),
- call('thing_right', 0),
- call('thing_bottom', 0),
- ], any_order=True)
+ node.style.apply.assert_has_calls(
+ [
+ call("explicit_const", VALUE2),
+ call("explicit_value", 0),
+ call("explicit_none", None),
+ call("implicit", VALUE3),
+ call("thing_left", 0),
+ call("thing_top", 0),
+ call("thing_right", 0),
+ call("thing_bottom", 0),
+ ],
+ any_order=True,
+ )
def test_property_with_explicit_const(self):
node = TestNode()
@@ -84,7 +89,7 @@ def test_property_with_explicit_const(self):
node.style.explicit_const = 10
self.assertEqual(node.style.explicit_const, 10)
- node.style.apply.assert_called_once_with('explicit_const', 10)
+ node.style.apply.assert_called_once_with("explicit_const", 10)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -99,7 +104,7 @@ def test_property_with_explicit_const(self):
# A dirty notification is set.
node.style.explicit_const = 20
self.assertEqual(node.style.explicit_const, 20)
- node.style.apply.assert_called_once_with('explicit_const', 20)
+ node.style.apply.assert_called_once_with("explicit_const", 20)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -107,7 +112,7 @@ def test_property_with_explicit_const(self):
# Clear the property
del node.style.explicit_const
self.assertIs(node.style.explicit_const, VALUE1)
- node.style.apply.assert_called_once_with('explicit_const', VALUE1)
+ node.style.apply.assert_called_once_with("explicit_const", VALUE1)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -130,7 +135,7 @@ def test_property_with_explicit_value(self):
node.style.explicit_value = 10
self.assertEqual(node.style.explicit_value, 10)
- node.style.apply.assert_called_once_with('explicit_value', 10)
+ node.style.apply.assert_called_once_with("explicit_value", 10)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -145,7 +150,7 @@ def test_property_with_explicit_value(self):
# A dirty notification is set.
node.style.explicit_value = 20
self.assertEqual(node.style.explicit_value, 20)
- node.style.apply.assert_called_once_with('explicit_value', 20)
+ node.style.apply.assert_called_once_with("explicit_value", 20)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -153,7 +158,7 @@ def test_property_with_explicit_value(self):
# Clear the property
del node.style.explicit_value
self.assertEqual(node.style.explicit_value, 0)
- node.style.apply.assert_called_once_with('explicit_value', 0)
+ node.style.apply.assert_called_once_with("explicit_value", 0)
def test_property_with_explicit_none(self):
node = TestNode()
@@ -166,7 +171,7 @@ def test_property_with_explicit_none(self):
node.style.explicit_none = 10
self.assertEqual(node.style.explicit_none, 10)
- node.style.apply.assert_called_once_with('explicit_none', 10)
+ node.style.apply.assert_called_once_with("explicit_none", 10)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -181,7 +186,7 @@ def test_property_with_explicit_none(self):
# A dirty notification is set.
node.style.explicit_none = 20
self.assertEqual(node.style.explicit_none, 20)
- node.style.apply.assert_called_once_with('explicit_none', 20)
+ node.style.apply.assert_called_once_with("explicit_none", 20)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -189,7 +194,7 @@ def test_property_with_explicit_none(self):
# Clear the property
del node.style.explicit_none
self.assertIsNone(node.style.explicit_none)
- node.style.apply.assert_called_once_with('explicit_none', None)
+ node.style.apply.assert_called_once_with("explicit_none", None)
def test_property_with_implicit_default(self):
node = TestNode()
@@ -202,7 +207,7 @@ def test_property_with_implicit_default(self):
node.style.implicit = 10
self.assertEqual(node.style.implicit, 10)
- node.style.apply.assert_called_once_with('implicit', 10)
+ node.style.apply.assert_called_once_with("implicit", 10)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -217,7 +222,7 @@ def test_property_with_implicit_default(self):
# A dirty notification is set.
node.style.implicit = 20
self.assertEqual(node.style.implicit, 20)
- node.style.apply.assert_called_once_with('implicit', 20)
+ node.style.apply.assert_called_once_with("implicit", 20)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -225,7 +230,7 @@ def test_property_with_implicit_default(self):
# Clear the property
del node.style.implicit
self.assertIsNone(node.style.implicit)
- node.style.apply.assert_called_once_with('implicit', None)
+ node.style.apply.assert_called_once_with("implicit", None)
def test_directional_property(self):
node = TestNode()
@@ -246,7 +251,7 @@ def test_directional_property(self):
self.assertEqual(node.style.thing_right, 0)
self.assertEqual(node.style.thing_bottom, 0)
self.assertEqual(node.style.thing_left, 0)
- node.style.apply.assert_called_once_with('thing_top', 10)
+ node.style.apply.assert_called_once_with("thing_top", 10)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -259,11 +264,13 @@ def test_directional_property(self):
self.assertEqual(node.style.thing_right, 10)
self.assertEqual(node.style.thing_bottom, 10)
self.assertEqual(node.style.thing_left, 10)
- node.style.apply.assert_has_calls([
- call('thing_right', 10),
- call('thing_bottom', 10),
- call('thing_left', 10),
- ])
+ node.style.apply.assert_has_calls(
+ [
+ call("thing_right", 10),
+ call("thing_bottom", 10),
+ call("thing_left", 10),
+ ]
+ )
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -276,12 +283,14 @@ def test_directional_property(self):
self.assertEqual(node.style.thing_right, 30)
self.assertEqual(node.style.thing_bottom, 30)
self.assertEqual(node.style.thing_left, 30)
- node.style.apply.assert_has_calls([
- call('thing_top', 30),
- call('thing_right', 30),
- call('thing_bottom', 30),
- call('thing_left', 30),
- ])
+ node.style.apply.assert_has_calls(
+ [
+ call("thing_top", 30),
+ call("thing_right", 30),
+ call("thing_bottom", 30),
+ call("thing_left", 30),
+ ]
+ )
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -294,12 +303,14 @@ def test_directional_property(self):
self.assertEqual(node.style.thing_right, 20)
self.assertEqual(node.style.thing_bottom, 10)
self.assertEqual(node.style.thing_left, 20)
- node.style.apply.assert_has_calls([
- call('thing_top', 10),
- call('thing_right', 20),
- call('thing_bottom', 10),
- call('thing_left', 20),
- ])
+ node.style.apply.assert_has_calls(
+ [
+ call("thing_top", 10),
+ call("thing_right", 20),
+ call("thing_bottom", 10),
+ call("thing_left", 20),
+ ]
+ )
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -312,7 +323,7 @@ def test_directional_property(self):
self.assertEqual(node.style.thing_right, 20)
self.assertEqual(node.style.thing_bottom, 30)
self.assertEqual(node.style.thing_left, 20)
- node.style.apply.assert_called_once_with('thing_bottom', 30)
+ node.style.apply.assert_called_once_with("thing_bottom", 30)
# Clear the applicator mock
node.style.apply.reset_mock()
@@ -325,7 +336,7 @@ def test_directional_property(self):
self.assertEqual(node.style.thing_right, 20)
self.assertEqual(node.style.thing_bottom, 30)
self.assertEqual(node.style.thing_left, 40)
- node.style.apply.assert_called_once_with('thing_left', 40)
+ node.style.apply.assert_called_once_with("thing_left", 40)
# Set a value directly with an invalid number of values
with self.assertRaises(ValueError):
@@ -345,7 +356,7 @@ def test_directional_property(self):
self.assertEqual(node.style.thing_right, 20)
self.assertEqual(node.style.thing_bottom, 30)
self.assertEqual(node.style.thing_left, 40)
- node.style.apply.assert_called_once_with('thing_top', 0)
+ node.style.apply.assert_called_once_with("thing_top", 0)
# Restore the top thing
node.style.thing_top = 10
@@ -361,11 +372,13 @@ def test_directional_property(self):
self.assertEqual(node.style.thing_right, 0)
self.assertEqual(node.style.thing_bottom, 0)
self.assertEqual(node.style.thing_left, 0)
- node.style.apply.assert_has_calls([
- call('thing_right', 0),
- call('thing_bottom', 0),
- call('thing_left', 0),
- ])
+ node.style.apply.assert_has_calls(
+ [
+ call("thing_right", 0),
+ call("thing_bottom", 0),
+ call("thing_left", 0),
+ ]
+ )
def test_set_multiple_properties(self):
node = TestNode()
@@ -378,10 +391,10 @@ def test_set_multiple_properties(self):
self.assertEqual(node.style.explicit_value, 20)
node.style.apply.assert_has_calls(
[
- call('explicit_value', 20),
- call('explicit_none', 10),
+ call("explicit_value", 20),
+ call("explicit_none", 10),
],
- any_order=True
+ any_order=True,
)
# Set a different pair of properties
@@ -392,10 +405,10 @@ def test_set_multiple_properties(self):
self.assertEqual(node.style.explicit_none, 10)
node.style.apply.assert_has_calls(
[
- call('explicit_const', VALUE2),
- call('explicit_value', 30),
+ call("explicit_const", VALUE2),
+ call("explicit_value", 30),
],
- any_order=True
+ any_order=True,
)
# Clear the applicator mock
@@ -423,7 +436,7 @@ def test_str(self):
"thing-bottom: 50; "
"thing-left: 60; "
"thing-right: 40; "
- "thing-top: 30"
+ "thing-top: 30",
)
def test_dict(self):
@@ -438,42 +451,51 @@ def test_dict(self):
self.assertEqual(
node.style.keys(),
- {'explicit_const', 'explicit_value', 'thing_bottom', 'thing_left', 'thing_right', 'thing_top'}
+ {
+ "explicit_const",
+ "explicit_value",
+ "thing_bottom",
+ "thing_left",
+ "thing_right",
+ "thing_top",
+ },
)
self.assertEqual(
sorted(node.style.items()),
- sorted([
- ('explicit_const', 'value2'),
- ('explicit_value', 20),
- ('thing_bottom', 50),
- ('thing_left', 60),
- ('thing_right', 40),
- ('thing_top', 30),
- ])
+ sorted(
+ [
+ ("explicit_const", "value2"),
+ ("explicit_value", 20),
+ ("thing_bottom", 50),
+ ("thing_left", 60),
+ ("thing_right", 40),
+ ("thing_top", 30),
+ ]
+ ),
)
# A property can be set, retrieved and cleared using the attribute name
- node.style['thing-bottom'] = 10
- self.assertEqual(node.style['thing-bottom'], 10)
- del node.style['thing-bottom']
- self.assertEqual(node.style['thing-bottom'], 0)
+ node.style["thing-bottom"] = 10
+ self.assertEqual(node.style["thing-bottom"], 10)
+ del node.style["thing-bottom"]
+ self.assertEqual(node.style["thing-bottom"], 0)
# A property can be set, retrieved and cleared using the Python attribute name
- node.style['thing_bottom'] = 10
- self.assertEqual(node.style['thing_bottom'], 10)
- del node.style['thing_bottom']
- self.assertEqual(node.style['thing_bottom'], 0)
+ node.style["thing_bottom"] = 10
+ self.assertEqual(node.style["thing_bottom"], 10)
+ del node.style["thing_bottom"]
+ self.assertEqual(node.style["thing_bottom"], 0)
# Clearing a valid property isn't an error
- del node.style['thing_bottom']
- self.assertEqual(node.style['thing_bottom'], 0)
+ del node.style["thing_bottom"]
+ self.assertEqual(node.style["thing_bottom"], 0)
# Non-existent properties raise KeyError
with self.assertRaises(KeyError):
- node.style['no-such-property'] = 'no-such-value'
+ node.style["no-such-property"] = "no-such-value"
with self.assertRaises(KeyError):
- node.style['no-such-property']
+ node.style["no-such-property"]
with self.assertRaises(KeyError):
- del node.style['no-such-property']
+ del node.style["no-such-property"]
diff --git a/tests/test_font.py b/tests/test_font.py
index b230748..d063ca0 100644
--- a/tests/test_font.py
+++ b/tests/test_font.py
@@ -21,240 +21,233 @@ def assertFont(self, font, family, size, style, variant, weight):
def test_equality(self):
self.assertEqual(
- Font('Comic Sans', '12 pt'),
- Font('Comic Sans', 12, NORMAL, NORMAL, NORMAL)
+ Font("Comic Sans", "12 pt"), Font("Comic Sans", 12, NORMAL, NORMAL, NORMAL)
)
def test_hash(self):
self.assertEqual(
- hash(Font('Comic Sans', 12)),
- hash(Font('Comic Sans', 12)),
+ hash(Font("Comic Sans", 12)),
+ hash(Font("Comic Sans", 12)),
)
self.assertNotEqual(
- hash(Font('Comic Sans', 12, weight=BOLD)),
- hash(Font('Comic Sans', 12)),
+ hash(Font("Comic Sans", 12, weight=BOLD)),
+ hash(Font("Comic Sans", 12)),
)
def test_repr(self):
- self.assertEqual(
- repr(Font('Comic Sans', 12)),
- ''
- )
+ self.assertEqual(repr(Font("Comic Sans", 12)), "")
self.assertEqual(
- repr(Font('Comic Sans', 12, style=ITALIC)),
- ''
+ repr(Font("Comic Sans", 12, style=ITALIC)), ""
)
self.assertEqual(
- repr(Font('Comic Sans', 12, style=ITALIC, variant=SMALL_CAPS)),
- ''
+ repr(Font("Comic Sans", 12, style=ITALIC, variant=SMALL_CAPS)),
+ "",
)
self.assertEqual(
- repr(Font('Comic Sans', 12, style=ITALIC, variant=SMALL_CAPS, weight=BOLD)),
- ''
+ repr(Font("Comic Sans", 12, style=ITALIC, variant=SMALL_CAPS, weight=BOLD)),
+ "",
)
self.assertEqual(
- repr(Font('Comic Sans', 12, variant=SMALL_CAPS, weight=BOLD)),
- ''
+ repr(Font("Comic Sans", 12, variant=SMALL_CAPS, weight=BOLD)),
+ "",
)
self.assertEqual(
- repr(Font('Comic Sans', 12, weight=BOLD)),
- ''
+ repr(Font("Comic Sans", 12, weight=BOLD)), ""
)
self.assertEqual(
- repr(Font('Comic Sans', 12, style=ITALIC, weight=BOLD)),
- ''
+ repr(Font("Comic Sans", 12, style=ITALIC, weight=BOLD)),
+ "",
)
# Check system default size handling
self.assertEqual(
- repr(Font('Comic Sans', SYSTEM_DEFAULT_FONT_SIZE)),
- ''
+ repr(Font("Comic Sans", SYSTEM_DEFAULT_FONT_SIZE)),
+ "",
)
self.assertEqual(
- repr(Font('Comic Sans', SYSTEM_DEFAULT_FONT_SIZE, style=ITALIC)),
- ''
+ repr(Font("Comic Sans", SYSTEM_DEFAULT_FONT_SIZE, style=ITALIC)),
+ "",
)
def test_simple_construction(self):
# Simplest case
self.assertFont(
- Font('Comic Sans', 12),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font("Comic Sans", 12), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
# String size
self.assertFont(
- Font('Comic Sans', '12'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font("Comic Sans", "12"), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
# String size with 'pt'
self.assertFont(
- Font('Comic Sans', '12pt'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font("Comic Sans", "12pt"), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
self.assertFont(
- Font('Comic Sans', '12 pt'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font("Comic Sans", "12 pt"), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
with self.assertRaises(ValueError):
- Font('Comic Sans', '12 quatloos'),
+ Font("Comic Sans", "12 quatloos"),
def test_family(self):
self.assertFont(
- Font('Comic Sans', 12),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font("Comic Sans", 12), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
- self.assertFont(
- Font('Wingdings', 12),
- 'Wingdings', 12, NORMAL, NORMAL, NORMAL
- )
+ self.assertFont(Font("Wingdings", 12), "Wingdings", 12, NORMAL, NORMAL, NORMAL)
self.assertFont(
- Font("'Comic Sans'", 12),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font("'Comic Sans'", 12), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
self.assertFont(
- Font('"Comic Sans"', 12),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font('"Comic Sans"', 12), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
def test_style(self):
self.assertFont(
- Font('Comic Sans', 12, style=ITALIC),
- 'Comic Sans', 12, ITALIC, NORMAL, NORMAL
+ Font("Comic Sans", 12, style=ITALIC),
+ "Comic Sans",
+ 12,
+ ITALIC,
+ NORMAL,
+ NORMAL,
)
self.assertFont(
- Font('Comic Sans', 12, style='italic'),
- 'Comic Sans', 12, ITALIC, NORMAL, NORMAL
+ Font("Comic Sans", 12, style="italic"),
+ "Comic Sans",
+ 12,
+ ITALIC,
+ NORMAL,
+ NORMAL,
)
self.assertFont(
- Font('Comic Sans', 12, style=OBLIQUE),
- 'Comic Sans', 12, OBLIQUE, NORMAL, NORMAL
+ Font("Comic Sans", 12, style=OBLIQUE),
+ "Comic Sans",
+ 12,
+ OBLIQUE,
+ NORMAL,
+ NORMAL,
)
self.assertFont(
- Font('Comic Sans', 12, style='oblique'),
- 'Comic Sans', 12, OBLIQUE, NORMAL, NORMAL
+ Font("Comic Sans", 12, style="oblique"),
+ "Comic Sans",
+ 12,
+ OBLIQUE,
+ NORMAL,
+ NORMAL,
)
self.assertFont(
- Font('Comic Sans', 12, style='something else'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font("Comic Sans", 12, style="something else"),
+ "Comic Sans",
+ 12,
+ NORMAL,
+ NORMAL,
+ NORMAL,
)
def test_make_normal_style(self):
- f = Font('Comic Sans', 12)
- self.assertFont(
- f.normal_style(),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
- )
+ f = Font("Comic Sans", 12)
+ self.assertFont(f.normal_style(), "Comic Sans", 12, NORMAL, NORMAL, NORMAL)
- f = Font('Comic Sans', 12, style=ITALIC)
- self.assertFont(
- f.normal_style(),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
- )
+ f = Font("Comic Sans", 12, style=ITALIC)
+ self.assertFont(f.normal_style(), "Comic Sans", 12, NORMAL, NORMAL, NORMAL)
def test_make_italic(self):
- f = Font('Comic Sans', 12)
- self.assertFont(
- f.italic(),
- 'Comic Sans', 12, ITALIC, NORMAL, NORMAL
- )
+ f = Font("Comic Sans", 12)
+ self.assertFont(f.italic(), "Comic Sans", 12, ITALIC, NORMAL, NORMAL)
def test_make_oblique(self):
- f = Font('Comic Sans', 12)
- self.assertFont(
- f.oblique(),
- 'Comic Sans', 12, OBLIQUE, NORMAL, NORMAL
- )
+ f = Font("Comic Sans", 12)
+ self.assertFont(f.oblique(), "Comic Sans", 12, OBLIQUE, NORMAL, NORMAL)
def test_variant(self):
self.assertFont(
- Font('Comic Sans', 12, variant=SMALL_CAPS),
- 'Comic Sans', 12, NORMAL, SMALL_CAPS, NORMAL
+ Font("Comic Sans", 12, variant=SMALL_CAPS),
+ "Comic Sans",
+ 12,
+ NORMAL,
+ SMALL_CAPS,
+ NORMAL,
)
self.assertFont(
- Font('Comic Sans', 12, variant='small-caps'),
- 'Comic Sans', 12, NORMAL, SMALL_CAPS, NORMAL
+ Font("Comic Sans", 12, variant="small-caps"),
+ "Comic Sans",
+ 12,
+ NORMAL,
+ SMALL_CAPS,
+ NORMAL,
)
self.assertFont(
- Font('Comic Sans', 12, variant='something else'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font("Comic Sans", 12, variant="something else"),
+ "Comic Sans",
+ 12,
+ NORMAL,
+ NORMAL,
+ NORMAL,
)
def test_make_normal_variant(self):
- f = Font('Comic Sans', 12)
- self.assertFont(
- f.normal_variant(),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
- )
+ f = Font("Comic Sans", 12)
+ self.assertFont(f.normal_variant(), "Comic Sans", 12, NORMAL, NORMAL, NORMAL)
- f = Font('Comic Sans', 12, variant=SMALL_CAPS)
- self.assertFont(
- f.normal_variant(),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
- )
+ f = Font("Comic Sans", 12, variant=SMALL_CAPS)
+ self.assertFont(f.normal_variant(), "Comic Sans", 12, NORMAL, NORMAL, NORMAL)
def test_make_small_caps(self):
- f = Font('Comic Sans', 12)
- self.assertFont(
- f.small_caps(),
- 'Comic Sans', 12, NORMAL, SMALL_CAPS, NORMAL
- )
+ f = Font("Comic Sans", 12)
+ self.assertFont(f.small_caps(), "Comic Sans", 12, NORMAL, SMALL_CAPS, NORMAL)
def test_weight(self):
self.assertFont(
- Font('Comic Sans', 12, weight=BOLD),
- 'Comic Sans', 12, NORMAL, NORMAL, BOLD
+ Font("Comic Sans", 12, weight=BOLD), "Comic Sans", 12, NORMAL, NORMAL, BOLD
)
self.assertFont(
- Font('Comic Sans', 12, weight='bold'),
- 'Comic Sans', 12, NORMAL, NORMAL, BOLD
+ Font("Comic Sans", 12, weight="bold"),
+ "Comic Sans",
+ 12,
+ NORMAL,
+ NORMAL,
+ BOLD,
)
self.assertFont(
- Font('Comic Sans', 12, weight='something else'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ Font("Comic Sans", 12, weight="something else"),
+ "Comic Sans",
+ 12,
+ NORMAL,
+ NORMAL,
+ NORMAL,
)
def test_make_normal_weight(self):
- f = Font('Comic Sans', 12)
- self.assertFont(
- f.normal_weight(),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
- )
+ f = Font("Comic Sans", 12)
+ self.assertFont(f.normal_weight(), "Comic Sans", 12, NORMAL, NORMAL, NORMAL)
- f = Font('Comic Sans', 12, weight=BOLD)
- self.assertFont(
- f.normal_weight(),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
- )
+ f = Font("Comic Sans", 12, weight=BOLD)
+ self.assertFont(f.normal_weight(), "Comic Sans", 12, NORMAL, NORMAL, NORMAL)
def test_make_bold(self):
- f = Font('Comic Sans', 12)
- self.assertFont(
- f.bold(),
- 'Comic Sans', 12, NORMAL, NORMAL, BOLD
- )
+ f = Font("Comic Sans", 12)
+ self.assertFont(f.bold(), "Comic Sans", 12, NORMAL, NORMAL, BOLD)
class ParseFontTests(TestCase):
@@ -266,7 +259,7 @@ def assertFont(self, font, family, size, style, variant, weight):
self.assertEqual(font.weight, weight)
def test_font_instance(self):
- f = Font('Comic Sans', 12)
+ f = Font("Comic Sans", 12)
parsed = font(f)
@@ -275,130 +268,144 @@ def test_font_instance(self):
def test_successful_combinations(self):
self.assertFont(
- font('12pt Comic Sans'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ font("12pt Comic Sans"), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
self.assertFont(
- font('italic 12pt Comic Sans'),
- 'Comic Sans', 12, ITALIC, NORMAL, NORMAL
+ font("italic 12pt Comic Sans"), "Comic Sans", 12, ITALIC, NORMAL, NORMAL
)
self.assertFont(
- font('italic small-caps 12pt Comic Sans'),
- 'Comic Sans', 12, ITALIC, SMALL_CAPS, NORMAL
+ font("italic small-caps 12pt Comic Sans"),
+ "Comic Sans",
+ 12,
+ ITALIC,
+ SMALL_CAPS,
+ NORMAL,
)
self.assertFont(
- font('italic small-caps bold 12pt Comic Sans'),
- 'Comic Sans', 12, ITALIC, SMALL_CAPS, BOLD
+ font("italic small-caps bold 12pt Comic Sans"),
+ "Comic Sans",
+ 12,
+ ITALIC,
+ SMALL_CAPS,
+ BOLD,
)
self.assertFont(
- font('small-caps bold 12pt Comic Sans'),
- 'Comic Sans', 12, NORMAL, SMALL_CAPS, BOLD
+ font("small-caps bold 12pt Comic Sans"),
+ "Comic Sans",
+ 12,
+ NORMAL,
+ SMALL_CAPS,
+ BOLD,
)
self.assertFont(
- font('italic bold 12 pt Comic Sans'),
- 'Comic Sans', 12, ITALIC, NORMAL, BOLD
+ font("italic bold 12 pt Comic Sans"), "Comic Sans", 12, ITALIC, NORMAL, BOLD
)
self.assertFont(
- font('bold 12 pt Comic Sans'),
- 'Comic Sans', 12, NORMAL, NORMAL, BOLD
+ font("bold 12 pt Comic Sans"), "Comic Sans", 12, NORMAL, NORMAL, BOLD
)
def test_font_sizes(self):
self.assertFont(
- font('12pt Comic Sans'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ font("12pt Comic Sans"), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
self.assertFont(
- font('12 pt Comic Sans'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ font("12 pt Comic Sans"), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
- self.assertFont(
- font('12 Comic Sans'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
- )
+ self.assertFont(font("12 Comic Sans"), "Comic Sans", 12, NORMAL, NORMAL, NORMAL)
with self.assertRaises(ValueError):
- font('12quatloo Comic Sans')
+ font("12quatloo Comic Sans")
def test_font_family(self):
self.assertFont(
- font("12pt 'Comic Sans'"),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ font("12pt 'Comic Sans'"), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
self.assertFont(
- font('12pt "Comic Sans"'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ font('12pt "Comic Sans"'), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
def test_normal(self):
self.assertFont(
- font('normal 12pt Comic Sans'),
- 'Comic Sans', 12, NORMAL, NORMAL, NORMAL
+ font("normal 12pt Comic Sans"), "Comic Sans", 12, NORMAL, NORMAL, NORMAL
)
self.assertFont(
- font('italic normal 12pt Comic Sans'),
- 'Comic Sans', 12, ITALIC, NORMAL, NORMAL
+ font("italic normal 12pt Comic Sans"),
+ "Comic Sans",
+ 12,
+ ITALIC,
+ NORMAL,
+ NORMAL,
)
self.assertFont(
- font('italic small-caps normal 12pt Comic Sans'),
- 'Comic Sans', 12, ITALIC, SMALL_CAPS, NORMAL
+ font("italic small-caps normal 12pt Comic Sans"),
+ "Comic Sans",
+ 12,
+ ITALIC,
+ SMALL_CAPS,
+ NORMAL,
)
def test_style(self):
self.assertFont(
- font('italic 12pt Comic Sans'),
- 'Comic Sans', 12, ITALIC, NORMAL, NORMAL
+ font("italic 12pt Comic Sans"), "Comic Sans", 12, ITALIC, NORMAL, NORMAL
)
self.assertFont(
- font('oblique 12pt Comic Sans'),
- 'Comic Sans', 12, OBLIQUE, NORMAL, NORMAL
+ font("oblique 12pt Comic Sans"), "Comic Sans", 12, OBLIQUE, NORMAL, NORMAL
)
with self.assertRaises(ValueError):
- font('wiggly small-caps bold 12pt Comic Sans')
+ font("wiggly small-caps bold 12pt Comic Sans")
def test_variant(self):
self.assertFont(
- font('italic small-caps 12pt Comic Sans'),
- 'Comic Sans', 12, ITALIC, SMALL_CAPS, NORMAL
+ font("italic small-caps 12pt Comic Sans"),
+ "Comic Sans",
+ 12,
+ ITALIC,
+ SMALL_CAPS,
+ NORMAL,
)
with self.assertRaises(ValueError):
- font('italic wiggly bold 12pt Comic Sans')
+ font("italic wiggly bold 12pt Comic Sans")
def test_weight(self):
self.assertFont(
- font('italic small-caps bold 12pt Comic Sans'),
- 'Comic Sans', 12, ITALIC, SMALL_CAPS, BOLD
+ font("italic small-caps bold 12pt Comic Sans"),
+ "Comic Sans",
+ 12,
+ ITALIC,
+ SMALL_CAPS,
+ BOLD,
)
with self.assertRaises(ValueError):
- font('italic small-caps wiggly 12pt Comic Sans')
+ font("italic small-caps wiggly 12pt Comic Sans")
def test_duplicates(self):
with self.assertRaises(ValueError):
- font('oblique italic 12pt Comic Sans')
+ font("oblique italic 12pt Comic Sans")
with self.assertRaises(ValueError):
- font('italic small-caps oblique 12pt Comic Sans')
+ font("italic small-caps oblique 12pt Comic Sans")
with self.assertRaises(ValueError):
- font('italic small-caps bold small-caps 12pt Comic Sans')
+ font("italic small-caps bold small-caps 12pt Comic Sans")
with self.assertRaises(ValueError):
- font('bold bold 12pt Comic Sans')
+ font("bold bold 12pt Comic Sans")
def test_invaid(self):
with self.assertRaises(ValueError):
diff --git a/tests/test_layout.py b/tests/test_layout.py
index c6e1530..1aa6847 100644
--- a/tests/test_layout.py
+++ b/tests/test_layout.py
@@ -44,7 +44,9 @@ def setUp(self):
self.grandchild1_1.layout.content_height = 16
self.grandchild1_2 = Node(style=Style())
- self.child1 = Node(style=Style(), children=[self.grandchild1_1, self.grandchild1_2])
+ self.child1 = Node(
+ style=Style(), children=[self.grandchild1_1, self.grandchild1_2]
+ )
self.child1.layout.content_width = 10
self.child1.layout.content_height = 16
self.child2 = Node(style=Style(), children=[])
@@ -55,16 +57,16 @@ def setUp(self):
def assertLayout(self, box, expected):
actual = {
- 'origin': (box._origin_left, box._origin_top),
- 'size': (box.width, box.height),
- 'content': (box.content_width, box.content_height),
- 'relative': (
+ "origin": (box._origin_left, box._origin_top),
+ "size": (box.width, box.height),
+ "content": (box.content_width, box.content_height),
+ "relative": (
box.content_top,
box.content_right,
box.content_bottom,
box.content_left,
),
- 'absolute': (
+ "absolute": (
box.absolute_content_top,
box.absolute_content_right,
box.absolute_content_bottom,
@@ -83,12 +85,12 @@ def test_initial(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (10, 16),
- 'content': (10, 16),
- 'relative': (0, 0, 0, 0),
- 'absolute': (0, 10, 16, 0),
- }
+ "origin": (0, 0),
+ "size": (10, 16),
+ "content": (10, 16),
+ "relative": (0, 0, 0, 0),
+ "absolute": (0, 10, 16, 0),
+ },
)
def test_set_content_top(self):
@@ -97,12 +99,12 @@ def test_set_content_top(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (10, 21),
- 'content': (10, 16),
- 'relative': (5, 0, 0, 0),
- 'absolute': (5, 10, 21, 0),
- }
+ "origin": (0, 0),
+ "size": (10, 21),
+ "content": (10, 16),
+ "relative": (5, 0, 0, 0),
+ "absolute": (5, 10, 21, 0),
+ },
)
# Set the top to a new value
@@ -111,12 +113,12 @@ def test_set_content_top(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (10, 23),
- 'content': (10, 16),
- 'relative': (7, 0, 0, 0),
- 'absolute': (7, 10, 23, 0),
- }
+ "origin": (0, 0),
+ "size": (10, 23),
+ "content": (10, 16),
+ "relative": (7, 0, 0, 0),
+ "absolute": (7, 10, 23, 0),
+ },
)
def test_set_content_left(self):
@@ -125,12 +127,12 @@ def test_set_content_left(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (15, 16),
- 'content': (10, 16),
- 'relative': (0, 0, 0, 5),
- 'absolute': (0, 15, 16, 5),
- }
+ "origin": (0, 0),
+ "size": (15, 16),
+ "content": (10, 16),
+ "relative": (0, 0, 0, 5),
+ "absolute": (0, 15, 16, 5),
+ },
)
# Set the left to a new value
@@ -139,12 +141,12 @@ def test_set_content_left(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (17, 16),
- 'content': (10, 16),
- 'relative': (0, 0, 0, 7),
- 'absolute': (0, 17, 16, 7),
- }
+ "origin": (0, 0),
+ "size": (17, 16),
+ "content": (10, 16),
+ "relative": (0, 0, 0, 7),
+ "absolute": (0, 17, 16, 7),
+ },
)
def test_set_content_width(self):
@@ -153,12 +155,12 @@ def test_set_content_width(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (5, 16),
- 'content': (5, 16),
- 'relative': (0, 0, 0, 0),
- 'absolute': (0, 5, 16, 0),
- }
+ "origin": (0, 0),
+ "size": (5, 16),
+ "content": (5, 16),
+ "relative": (0, 0, 0, 0),
+ "absolute": (0, 5, 16, 0),
+ },
)
# Set the width to a new value
@@ -167,12 +169,12 @@ def test_set_content_width(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (7, 16),
- 'content': (7, 16),
- 'relative': (0, 0, 0, 0),
- 'absolute': (0, 7, 16, 0),
- }
+ "origin": (0, 0),
+ "size": (7, 16),
+ "content": (7, 16),
+ "relative": (0, 0, 0, 0),
+ "absolute": (0, 7, 16, 0),
+ },
)
def test_set_content_height(self):
@@ -181,12 +183,12 @@ def test_set_content_height(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (10, 5),
- 'content': (10, 5),
- 'relative': (0, 0, 0, 0),
- 'absolute': (0, 10, 5, 0),
- }
+ "origin": (0, 0),
+ "size": (10, 5),
+ "content": (10, 5),
+ "relative": (0, 0, 0, 0),
+ "absolute": (0, 10, 5, 0),
+ },
)
# Set the height to a new value
@@ -195,12 +197,12 @@ def test_set_content_height(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (10, 7),
- 'content': (10, 7),
- 'relative': (0, 0, 0, 0),
- 'absolute': (0, 10, 7, 0),
- }
+ "origin": (0, 0),
+ "size": (10, 7),
+ "content": (10, 7),
+ "relative": (0, 0, 0, 0),
+ "absolute": (0, 10, 7, 0),
+ },
)
def test_descendent_offsets(self):
@@ -216,34 +218,34 @@ def test_descendent_offsets(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (18, 23),
- 'content': (10, 16),
- 'relative': (7, 0, 0, 8),
- 'absolute': (7, 18, 23, 8),
- }
+ "origin": (0, 0),
+ "size": (18, 23),
+ "content": (10, 16),
+ "relative": (7, 0, 0, 8),
+ "absolute": (7, 18, 23, 8),
+ },
)
self.assertLayout(
self.child1.layout,
{
- 'origin': (8, 7),
- 'size': (20, 25),
- 'content': (10, 16),
- 'relative': (9, 0, 0, 10),
- 'absolute': (16, 28, 32, 18),
- }
+ "origin": (8, 7),
+ "size": (20, 25),
+ "content": (10, 16),
+ "relative": (9, 0, 0, 10),
+ "absolute": (16, 28, 32, 18),
+ },
)
self.assertLayout(
self.grandchild1_1.layout,
{
- 'origin': (18, 16),
- 'size': (22, 27),
- 'content': (10, 16),
- 'relative': (11, 0, 0, 12),
- 'absolute': (27, 40, 43, 30),
- }
+ "origin": (18, 16),
+ "size": (22, 27),
+ "content": (10, 16),
+ "relative": (11, 0, 0, 12),
+ "absolute": (27, 40, 43, 30),
+ },
)
# Modify the grandchild position
@@ -254,34 +256,34 @@ def test_descendent_offsets(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (18, 23),
- 'content': (10, 16),
- 'relative': (7, 0, 0, 8),
- 'absolute': (7, 18, 23, 8),
- }
+ "origin": (0, 0),
+ "size": (18, 23),
+ "content": (10, 16),
+ "relative": (7, 0, 0, 8),
+ "absolute": (7, 18, 23, 8),
+ },
)
self.assertLayout(
self.child1.layout,
{
- 'origin': (8, 7),
- 'size': (20, 25),
- 'content': (10, 16),
- 'relative': (9, 0, 0, 10),
- 'absolute': (16, 28, 32, 18),
- }
+ "origin": (8, 7),
+ "size": (20, 25),
+ "content": (10, 16),
+ "relative": (9, 0, 0, 10),
+ "absolute": (16, 28, 32, 18),
+ },
)
self.assertLayout(
self.grandchild1_1.layout,
{
- 'origin': (18, 16),
- 'size': (24, 29),
- 'content': (10, 16),
- 'relative': (13, 0, 0, 14),
- 'absolute': (29, 42, 45, 32),
- }
+ "origin": (18, 16),
+ "size": (24, 29),
+ "content": (10, 16),
+ "relative": (13, 0, 0, 14),
+ "absolute": (29, 42, 45, 32),
+ },
)
# Modify the child position
@@ -292,34 +294,34 @@ def test_descendent_offsets(self):
self.assertLayout(
self.node.layout,
{
- 'origin': (0, 0),
- 'size': (18, 23),
- 'content': (10, 16),
- 'relative': (7, 0, 0, 8),
- 'absolute': (7, 18, 23, 8),
- }
+ "origin": (0, 0),
+ "size": (18, 23),
+ "content": (10, 16),
+ "relative": (7, 0, 0, 8),
+ "absolute": (7, 18, 23, 8),
+ },
)
self.assertLayout(
self.child1.layout,
{
- 'origin': (8, 7),
- 'size': (26, 31),
- 'content': (10, 16),
- 'relative': (15, 0, 0, 16),
- 'absolute': (22, 34, 38, 24),
- }
+ "origin": (8, 7),
+ "size": (26, 31),
+ "content": (10, 16),
+ "relative": (15, 0, 0, 16),
+ "absolute": (22, 34, 38, 24),
+ },
)
self.assertLayout(
self.grandchild1_1.layout,
{
- 'origin': (24, 22),
- 'size': (24, 29),
- 'content': (10, 16),
- 'relative': (13, 0, 0, 14),
- 'absolute': (35, 48, 51, 38),
- }
+ "origin": (24, 22),
+ "size": (24, 29),
+ "content": (10, 16),
+ "relative": (13, 0, 0, 14),
+ "absolute": (35, 48, 51, 38),
+ },
)
def test_absolute_equalities(self):
@@ -334,18 +336,22 @@ def test_absolute_equalities(self):
self.assertEqual(
self.node.layout.absolute_content_left + self.node.layout.content_width,
- self.node.layout.absolute_content_right
+ self.node.layout.absolute_content_right,
)
self.assertEqual(
self.node.layout.absolute_content_top + self.node.layout.content_height,
- self.node.layout.absolute_content_bottom
+ self.node.layout.absolute_content_bottom,
)
self.assertEqual(
- self.node.layout.content_left + self.node.layout.content_width + self.node.layout.content_right,
- self.node.layout.width
+ self.node.layout.content_left
+ + self.node.layout.content_width
+ + self.node.layout.content_right,
+ self.node.layout.width,
)
self.assertEqual(
- self.node.layout.content_top + self.node.layout.content_height + self.node.layout.content_bottom,
- self.node.layout.height
+ self.node.layout.content_top
+ + self.node.layout.content_height
+ + self.node.layout.content_bottom,
+ self.node.layout.height,
)
diff --git a/tests/test_node.py b/tests/test_node.py
index 8d16e6c..4823924 100644
--- a/tests/test_node.py
+++ b/tests/test_node.py
@@ -98,6 +98,7 @@ def test_create_node(self):
def test_refresh(self):
"The layout can be refreshed, and the applicator invoked"
+
# Define an applicator that tracks the node being rendered and it's size
class Applicator:
def __init__(self, node):
@@ -105,14 +106,18 @@ def __init__(self, node):
self.node = node
def set_bounds(self):
- self.tasks.append((self.node, self.node.layout.content_width, self.node.layout.content_height))
+ self.tasks.append(
+ (
+ self.node,
+ self.node.layout.content_width,
+ self.node.layout.content_height,
+ )
+ )
class TestNode(Node):
def __init__(self, style, children=None):
super().__init__(
- style=style,
- applicator=Applicator(self),
- children=children
+ style=style, applicator=Applicator(self), children=children
)
# Define a simple 2 level tree of nodes.
diff --git a/tests/test_size.py b/tests/test_size.py
index e18880f..23c7762 100644
--- a/tests/test_size.py
+++ b/tests/test_size.py
@@ -22,12 +22,12 @@ def setUp(self):
self.assertSize(self.size, (1, 2, 0.1))
def test_at_least_repr(self):
- self.assertEqual(repr(at_least(10)), 'at least 10')
+ self.assertEqual(repr(at_least(10)), "at least 10")
def test_size_repr(self):
- self.assertEqual(repr(self.size), '(1, 2)')
+ self.assertEqual(repr(self.size), "(1, 2)")
self.size.width = at_least(10)
- self.assertEqual(repr(self.size), '(at least 10, 2)')
+ self.assertEqual(repr(self.size), "(at least 10, 2)")
def test_set_width(self):
self.size.width = 10
diff --git a/tox.ini b/tox.ini
index bc12d4a..ee8643f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,22 +4,15 @@
# and then run "tox" from this directory.
[tox]
-envlist = flake8,towncrier-check,package,py{37,38,39,310,311,312}
+envlist = towncrier-check,package,py{37,38,39,310,311,312}
skip_missing_interpreters = true
[testenv]
-deps =
- pytest
- pytest-tldr
+extras =
+ dev
commands =
pytest -vv
-[testenv:flake8]
-skip_install = True
-deps =
- flake8
-commands = flake8 {posargs}
-
[testenv:towncrier-check]
skip_install = True
deps =
@@ -35,13 +28,15 @@ commands =
towncrier {posargs}
[testenv:package]
+package_env = none
+skip_install = True
deps =
check_manifest
- wheel
+ build
twine
commands =
check-manifest -v
- python setup.py sdist bdist_wheel
+ python -m build --outdir dist/ .
python -m twine check dist/*
[testenv:publish]