././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1679896362.6626644 webcolors-1.13/0000755000076700000240000000000014410227453012463 5ustar00jamesstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670223976.0 webcolors-1.13/.editorconfig0000644000076700000240000000042114343314150015131 0ustar00jamesstaff# https://editorconfig.org/ root = true [*] indent_style = space indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true end_of_line = lf charset = utf-8 [*.py] max_line_length = 88 [docs/**.rst] max_line_length = 79 [*.{yaml,yml}] indent_size = 2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670224786.0 webcolors-1.13/.flake80000644000076700000240000000010714343315622013635 0ustar00jamesstaff[flake8] extend-ignore = E203 max-complexity = 13 max-line-length = 88 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676363497.0 webcolors-1.13/.pre-commit-config.yaml0000644000076700000240000000202114372643351016745 0ustar00jamesstaff# See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: check-added-large-files - id: check-ast - id: check-byte-order-marker - id: check-case-conflict - id: check-docstring-first - id: check-merge-conflict - id: check-toml - id: check-yaml - id: debug-statements - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/psf/black rev: 23.1.0 hooks: - id: black language_version: python3.7 name: black (Python formatter) - repo: https://github.com/pycqa/flake8 rev: 6.0.0 hooks: - id: flake8 name: flake8 (Python linter) - repo: https://github.com/econchick/interrogate rev: 1.5.0 hooks: - id: interrogate name: interrogate (Python docstring enforcer) args: [--quiet] - repo: https://github.com/pycqa/isort rev: 5.12.0 hooks: - id: isort name: isort (Python formatter) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1674028471.0 webcolors-1.13/.readthedocs.yaml0000644000076700000240000000044714361722667015733 0ustar00jamesstaff# .readthedocs.yaml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details version: 2 build: os: ubuntu-22.04 tools: python: "3.11" sphinx: configuration: docs/conf.py python: install: - method: pip path: .[docs] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1679895966.0 webcolors-1.13/LICENSE0000644000076700000240000000275614410226636013504 0ustar00jamesstaffCopyright (c) 2008, James Bennett All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1671848858.0 webcolors-1.13/MANIFEST.in0000644000076700000240000000042114351461632014221 0ustar00jamesstaffinclude LICENSE include MANIFEST.in include .editorconfig include *.yaml include docs/*.rst docs/*.txt docs/*.py docs/*.bat docs/Makefile include .flake8 include pyproject.toml include noxfile.py include tox.ini graft src graft tests global-exclude *.pyc prune docs/_build ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1679896362.6625211 webcolors-1.13/PKG-INFO0000644000076700000240000000431614410227453013564 0ustar00jamesstaffMetadata-Version: 2.1 Name: webcolors Version: 1.13 Summary: A library for working with the color formats defined by HTML and CSS. Author-email: James Bennett License: BSD-3-Clause Project-URL: documentation, https://webcolors.readthedocs.io Project-URL: homepage, https://github.com/ubernostrum/webcolors Keywords: color,css,html,web Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Topic :: Utilities Requires-Python: >=3.7 Description-Content-Type: text/x-rst Provides-Extra: docs Provides-Extra: tests License-File: LICENSE .. -*-restructuredtext-*- .. image:: https://github.com/ubernostrum/webcolors/workflows/CI/badge.svg :alt: CI status image :target: https://github.com/ubernostrum/webcolors/actions?query=workflow%3ACI ``webcolors`` is a module for working with HTML/CSS color definitions. Support is included for normalizing and converting between the following formats (RGB colorspace only; conversion to/from HSL can be handled by the ``colorsys`` module in the Python standard library): * Specification-defined color names * Six-digit hexadecimal * Three-digit hexadecimal * Integer ``rgb()`` triplet * Percentage ``rgb()`` triplet For example: .. code-block:: python >>> import webcolors >>> webcolors.hex_to_name("#daa520") 'goldenrod' Implementations are also provided for the HTML5 color parsing and serialization algorithms. For example, parsing the infamous "chucknorris" string into an rgb() triplet: .. code-block:: python >>> import webcolors >>> webcolors.html5_parse_legacy_color("chucknorris") HTML5SimpleColor(red=192, green=0, blue=0) Full documentation is `available online `_. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670226717.0 webcolors-1.13/README.rst0000644000076700000240000000220714343321435014153 0ustar00jamesstaff.. -*-restructuredtext-*- .. image:: https://github.com/ubernostrum/webcolors/workflows/CI/badge.svg :alt: CI status image :target: https://github.com/ubernostrum/webcolors/actions?query=workflow%3ACI ``webcolors`` is a module for working with HTML/CSS color definitions. Support is included for normalizing and converting between the following formats (RGB colorspace only; conversion to/from HSL can be handled by the ``colorsys`` module in the Python standard library): * Specification-defined color names * Six-digit hexadecimal * Three-digit hexadecimal * Integer ``rgb()`` triplet * Percentage ``rgb()`` triplet For example: .. code-block:: python >>> import webcolors >>> webcolors.hex_to_name("#daa520") 'goldenrod' Implementations are also provided for the HTML5 color parsing and serialization algorithms. For example, parsing the infamous "chucknorris" string into an rgb() triplet: .. code-block:: python >>> import webcolors >>> webcolors.html5_parse_legacy_color("chucknorris") HTML5SimpleColor(red=192, green=0, blue=0) Full documentation is `available online `_. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1679896362.6548517 webcolors-1.13/docs/0000755000076700000240000000000014410227453013413 5ustar00jamesstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1378901941.0 webcolors-1.13/docs/Makefile0000644000076700000240000000566712214057665015077 0ustar00jamesstaff# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf _build/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html @echo @echo "Build finished. The HTML pages are in _build/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml @echo @echo "Build finished. The HTML pages are in _build/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in _build/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in _build/qthelp, like this:" @echo "# qcollectiongenerator _build/qthelp/webcolors.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile _build/qthelp/webcolors.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex @echo @echo "Build finished; the LaTeX files are in _build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes @echo @echo "The overview file is in _build/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in _build/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in _build/doctest/output.txt." ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1675146344.0 webcolors-1.13/docs/changelog.rst0000644000076700000240000001324314366132150016076 0ustar00jamesstaff.. _changelog: Change log ========== This document lists the changes between each release of webcolors. Version 1.13, released 2023-??-?? --------------------------------- No bug fixes or new features. Other changes ~~~~~~~~~~~~~ * Supported Python versions are now 3.7, 3.8, 3.9, 3.10, and 3.11 * The codebase was significantly reorganized and modernized. Public API is unchanged. Imports should continue to be directly from the top-level ``webcolors`` module; attempting to import from submodules is not supported. * Now packaging declaratively via ``pyproject.toml`` with `PEP 517 `_ support from ``setuptools``. Version 1.12, released 2022-05-25 --------------------------------- No bug fixes or new features. Other changes ~~~~~~~~~~~~~ * Supported Python versions are now 3.7, 3.8, 3.9, and 3.10. Version 1.11.1, released 2020-02-17 ----------------------------------- Bugs fixed ~~~~~~~~~~ * Corrected an error regarding supported Python versions in the README file. Version 1.11, released 2020-02-17 --------------------------------- No bug fixes or new features. Other changes ~~~~~~~~~~~~~ * Python 2 has reached the end of its support cycle from the Python core team; accordingly, Python 2 support is dropped. Supported Python versions are now 3.5, 3.6, 3.7, and 3.8. Version 1.10, released 2019-09-08 --------------------------------- No bug fixes or new features. Other changes ~~~~~~~~~~~~~ * Similar to the change in version 1.9 which normalized conversions to named colors for ``gray``/``grey`` to always use the ``gray`` variant, the other named grays of CSS3 now normalize to the ``gray`` spelling. This affects the following colors: ``darkgray``/``darkgrey``, ``darkslategray``/``darkslategrey``, ``dimgray``/``dimgrey``, ``lightgray``/``lightgrey``, ``lightslategray``/``lightslategrey``, ``slategray``/``slategrey``. Version 1.9.1, released 2019-06-07 ---------------------------------- Bugs fixed ~~~~~~~~~~ * The ``__version__`` attribute of the installed webcolors module, although not documented or referenced anywhere, was accidentally not updated in the 1.9 release. It has now been updated (and now indicates 1.9.1). Version 1.9, released 2019-06-01 -------------------------------- No bug fixes. New features ~~~~~~~~~~~~ * Added :ref:`a set of constants to use when referring to specifications that define color names `. Other changes ~~~~~~~~~~~~~ * When asked to provide a color name, using the CSS3/SVG set of names, for the hexadecimal value ``#808080``, the integer triplet ``rgb(128, 128, 128)``, or the percentage triplet ``rgb(50%, 50%, 50%)``, webcolors now always returns ``u'gray'``, never ``u'grey'``. Previously, the behavior could be inconsistent as it depended on the Python version in use; ``u'gray'`` was picked because it was the spelling variant used in HTML 4, CSS1, and CSS2. Version 1.8.1, released 2018-02-12 ---------------------------------- The 1.8.1 release is a repackaging of 1.8 to produce both source (.tar.gz) and binary (.whl) package formats, following reports that the source-package-only release of 1.8 was causing installation issues for some users. See `issue 6 in the repository `_ for details. Version 1.8, released 2018-02-08 -------------------------------- No bug fixes. New features ~~~~~~~~~~~~ * Added the :class:`~webcolors.IntegerRGB`, :class:`~webcolors.PercentRGB`, and :class:`~webcolors.HTML5SimpleColor` named tuples. Other changes ~~~~~~~~~~~~~ * Drop support for Python 3.3 (Python core team no longer maintains 3.3). * Mark support for Python 3.6. * :ref:`The full verification tests ` now run correctly on Python 3. Version 1.7, released 2016-11-25 -------------------------------- No new features or bugfixes. Other changes ~~~~~~~~~~~~~ * Drop support for Python 2.6 (Python core team no longer maintains 2.6). * Mark support for Python 3.4. * On Python 3, the use of :class:`str` for all functions which take string arguments is now mandatory. Attempted use of :class:`bytes` will raise an exception. On Python 2, use of bytestrings is still permitted. Version 1.5.1, released 2015-11-23 ---------------------------------- No new features. Bug fixes ~~~~~~~~~ * Corrected multiple typos in documentation. Version 1.5, released 2015-03-07 -------------------------------- No bug fixes. New features ~~~~~~~~~~~~ * Python 3 support: webcolors now supports Python 3.3. * Added :ref:`HTML5 color algorithms `. Other changes ~~~~~~~~~~~~~ * Packaging improvements. Version 1.4, released 2012-02-10 -------------------------------- No new features. Bugs fixed ~~~~~~~~~~ * Integer and percentage ``rgb()`` triplets now normalized in accordance with CSS clipping rules. Other changes ~~~~~~~~~~~~~ * Packaging fixes. * Preparatory work for Python 3 support. Version 1.3.1, released 2009-10-24 ---------------------------------- No new features or bugfixes. Other changes ~~~~~~~~~~~~~ * Documentation expanded. * Documentation now maintained using `Sphinx `_. Version 1.3, released 2009-05-08 -------------------------------- No new features or bugfixes. Other changes ~~~~~~~~~~~~~ * Documentation expanded. Version 1.2, 2009-03-01 ----------------------- Bugs fixed: ~~~~~~~~~~~ * Corrected the download URL in the ``setup.py`` script. Version 1.1, released 2008-12-19 -------------------------------- No new features or bugfixes. Other changes ~~~~~~~~~~~~~ * Documentation expanded. Version 1.0, released 2008-10-28 -------------------------------- Initial stable release of webcolors. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670308627.0 webcolors-1.13/docs/colors.rst0000644000076700000240000001650414343561423015457 0ustar00jamesstaff.. _colors: An overview of colors on the web ================================ Colors on the web are typically specified in `the sRGB color space`_, where each color is made up of a red component, a green component and a blue component. This maps to the red, green and blue components of the pixels on a computer display, and to the three sets of cone cells in an average trichromatic human eye, whose peak responses are (roughly) to the wavelengths of light associated with red, green and blue. On the web, sRGB colors are specified in formats which describe the color as a 24-bit integer, where the first 8 bits provide the red value, the second 8 bits the green value and the final 8 bits the blue value. This gives a total space of 256 × 256 × 256 or 16,777,216 unique colors, though due to differences in display technology not all of these colors may be clearly distinguishable on any given physical display. HTML 4 ------ HTML 4 defined `two ways to specify sRGB colors`_: * The character ``#`` followed by three pairs of hexadecimal digits, specifying values for red, green and blue components in that order; for example, ``#0099cc``. * A set of predefined color names which correspond to specific hexadecimal values; for example, ``blue``. HTML 4 defines sixteen such colors. CSS1 ---- In `its description of color units`_, CSS1 added three new ways to specify sRGB colors: * The character ``#`` followed by three hexadecimal digits, which is expanded into three hexadecimal pairs by repeating each digit; thus ``#09c`` is equivalent to ``#0099cc``. * The string ``rgb``, followed by parentheses, between which are three base-10 integers in the range 0..255, which are taken to be the values of the red, green and blue components in that order; for example, ``rgb(0, 153, 204)``. * The same as above, except using percentages instead of numeric values; for example, ``rgb(0%, 60%, 80%)``. CSS1 also suggested a set of sixteen color names. These names were identical to the set defined in HTML 4, but CSS1 did not provide definitions of their values and stated that they were taken from "the Windows VGA palette". CSS2 ---- In its `section on colors`_, CSS2 allowed the same methods of specifying colors as CSS1, and defined and provided values for sixteen named colors, identical to the set found in HTML 4. CSS2 also specified `a list of names of system colors`_. These had no fixed color values, but would take on values from the operating system or other user interface, and allowed elements to be styled using the same colors as the surrounding user interface. These names are deprecated as of CSS3. The CSS2.1 revision did not add any new methods of specifying sRGB colors, but did define `one additional named color`_: ``orange``. CSS3 ---- `The CSS3 color module`_ adds one new way to specify colors: * A hue-saturation-lightness triplet (HSL), using the construct ``hsl()``. CSS3 also adds support for variable opacity of colors, by allowing the specification of alpha-channel information through the ``rgba()`` and ``hsla()`` constructs. These are used similarly to the ``rgb()`` and ``hsl()`` constructs, except a fourth value is supplied indicating the level of opacity from ``0.0`` (completely transparent) to ``1.0`` (completely opaque). Though not technically a color, the keyword ``transparent`` is also made available in lieu of a color value, and corresponds to ``rgba(0,0,0,0)``. CSS3 also defines a new set of 147 color names. This set is taken directly from `the named colors defined for SVG (Scalable Vector Graphics)`_ markup, and is a superset of the named colors defined in CSS2.1. HTML5 ----- HTML5 exists in two forms: a living document maintained by WHATWG, and a W3C Recommendation. The two HTML5 documents, as of this writing, share a common definition of color values and parsing, and formalize the parsing and serialization of colors according to prior standards and real-world implementations in web browsers. HTML5 does not introduce any new methods of specifying colors, but does simplify the description of colors and introduce useful terminology. * A set of three 8-bit numbers representing the red, blue and green components of an sRGB color is termed a "simple color". * A seven-character string which begins with the character ``#``, followed by six ASCII hex digits (i.e., ``A-Fa-f0-9``), representing the red, green and blue components of an sRGB color, is a "valid simple color". * A valid simple color expressed with only lowercase ASCII hex digits (i.e., ``a-f0-9``) is a "valid lowercase simple color". HTML5 provides three algorithms related to colors: 1. An algorithm for parsing simple color values, which works on any string that is a valid simple color as defined above. 2. An algorithm for serializing simple color values, which will always produce a valid lowercase simple color. 3. A legacy color-parsing algorithm, which will yield a simple color from a variety of inputs, including inputs which are valid simple colors, inputs which are valid for formats from other standards, and certain types of "junk" inputs which were common in real-world documents. The HTML5 legacy parsing algorithm does not support the non-color keyword ``transparent`` from CSS3 and will produce an error for that input. It also does not recognize the CSS2 "system color" keywords; it will convert each such keyword to a simple color, consistently, but in a way which does not follow CSS2's definitions of these keywords (which itself was system- and configuration-dependent). The implementations in this module are based on the definitions and algorithms of `the HTML5 specification's section on colors`_. .. _the sRGB color space: http://www.w3.org/Graphics/Color/sRGB .. _two ways to specify sRGB colors: http://www.w3.org/TR/html401/types.html#h-6.5 .. _its description of color units: http://www.w3.org/TR/CSS1/#color-units .. _section on colors: http://www.w3.org/TR/CSS2/syndata.html#color-units .. _a list of names of system colors: http://www.w3.org/TR/CSS2/ui.html#system-colors .. _one additional named color: https://www.w3.org/TR/CSS21/changes.html#q21.2 .. _The CSS3 color module: http://www.w3.org/TR/css3-color/ .. _the named colors defined for SVG (Scalable Vector Graphics): http://www.w3.org/TR/SVG11/types.html#ColorKeywords .. _the HTML5 specification's section on colors: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#colours .. _support: What this module supports ------------------------- The webcolors module supports the following methods of specifying sRGB colors, and conversions between them: * Six-digit hexadecimal * Three-digit hexadecimal * Integer ``rgb()`` triplet * Percentage ``rgb()`` triplet * The defined named colors of HTML 4, CSS2, CSS2.1, and CSS3 The webcolors module **does not support**: * The CSS1 named colors, which did not have defined values * The CSS2 system colors, which did not have fixed values * The ``transparent`` keyword, which denotes an effective lack of color * Opacity/alpha-channel information specified via the ``rgba()`` construct * Colors specified in the HSL color space, via ``hsl()`` or `hsla()` constructs If you need to convert between sRGB-specified colors and HSL-specified colors, or colors specified via other means, consult the :mod:`colorsys` module in the Python standard library, which can perform conversions amongst several common color systems. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1679895961.0 webcolors-1.13/docs/conf.py0000644000076700000240000000250714410226631014713 0ustar00jamesstaff""" Configuration file for the Sphinx documentation builder: https://www.sphinx-doc.org/ """ import sys extensions = [ "notfound.extension", "sphinx.ext.autodoc", "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.viewcode", "sphinxext.opengraph", "sphinx_copybutton", "sphinx_inline_tabs", ] templates_path = ["_templates"] source_suffix = ".rst" master_doc = "index" project = "webcolors" copyright = "2008, James Bennett" version = "1.13" release = "1.13" exclude_trees = ["_build"] pygments_style = "sphinx" htmlhelp_basename = "webcolorsdoc" latex_documents = [ ("index", "webcolors.tex", "webcolors Documentation", "James Bennett", "manual"), ] html_theme = "furo" intersphinx_mapping = { "python": ("https://docs.python.org/3", None), } # Spelling check needs an additional module that is not installed by default. # Add it only if spelling check is requested so docs can be generated without it. if "spelling" in sys.argv: extensions.append("sphinxcontrib.spelling") # Spelling language. spelling_lang = "en_US" # Location of word list. spelling_word_list_filename = "spelling_wordlist.txt" # Doctest configuration. doctest_global_setup = "from webcolors import *" # OGP metadata configuration. ogp_enable_meta_description = True ogp_site_url = "https://webcolors.readthedocs.io/" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1675145136.0 webcolors-1.13/docs/conformance.rst0000644000076700000240000001701214366127660016451 0ustar00jamesstaff.. _conformance: Conformance and testing ======================= Much of the behavior of webcolors is dictated by the relevant web standards, which define the acceptable color formats, how to determine valid values for each format and the values corresponding to defined color names. Maintaining correct conversions and conformance to those standards is crucial. The source distribution of webcolors (the ``.tar.gz`` file you can download from the Python Package Index) includes a ``tests/`` directory containing a normal test suite as well as supplemental test files which perform more comprehensive verification. The normal test suite --------------------- The normal test suite for webcolors aims for 100% coverage of code paths, but does *not* aim for 100% coverage of possible color value inputs and outputs. Instead, it uses a small number of test values to routinely exercise various functions. The test values used in most test functions are chosen to provide, where applicable, at least one of each of the following types of values: * An endpoint of the acceptable range of values (i.e., ``#ffffff`` and/or ``#000000`` for hexadecimal). * A value beyond the high end of the acceptable range (i.e., greater than 255 in an integer triplet, or greater than 100% for a percentage triplet). * A value beyond the low end of the acceptable range (i.e., less than 0 in an integer triplet, or less than 0% for a percentage triplet). * A "negative zero" value (-0 in an integer triplet, or -0% in a percentage triplet). * An arbitrary value not from an endpoint of the acceptable range (usually ``#000080``, chosen because the author likes navy blue). * A value which corresponds to a named color in CSS3/SVG but not in earlier standards (usually ``#daa520``, which is ``goldenrod`` in CSS3/SVG). Since this covers the cases most likely to produce problems, this test suite provides good basic confidence in the correctness of the tested functions. It runs on every commit to the repository, and on every release tag. You can see the results of test runs online `at GitHub `_. However, the normal test suite cannot guarantee that the color definitions included in webcolors correspond to those in the relevant standards, and cannot provide guarantees of correct conversions for all possible values. For that, additional tests are required. .. _full-verification: Full verification tests ----------------------- These tests are contained in two files which are not executed during normal test runs: ``tests/definitions.py`` and ``tests/full_colors.py``. They are not run as part of the normal test suite, but are run prior to each release of webcolors. Verifying color definitions ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``definitions.py`` test file verifies that the color definitions in webcolors are correct. It does this by downloading the relevant standards documents as HTML, parsing out the color definitions in them, and comparing them to the definitions in webcolors. That consists of: * Parsing out the names and hexadecimal values of the 16 named colors in the HTML 4 standard, and checking that the names and values in :data:`~webcolors.HTML4_NAMES_TO_HEX` match. * Parsing out the names and hexadecimal values of the 17 named colors in the CSS2.1 standard, and checking that the names and values in :data:`~webcolors.CSS21_NAMES_TO_HEX` match. * Parsing out the names and hexadecimal and integer values of the 147 named colors in the CSS3 color module (although the color set is taken from SVG, CSS3 provides both hexadecimal and integer values for them, while the SVG standard provides only integer values), and checking that the names and values in :data:`~webcolors.CSS3_NAMES_TO_HEX` match, and that :func:`~webcolors.name_to_rgb` returns the correct integer values. Fully verifying correctness of conversions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The `full_colors.py` test file exercises :func:`~webcolors.hex_to_rgb`, :func:`~webcolors.rgb_to_hex`, :func:`~webcolors.rgb_to_rgb_percent` and :func:`~webcolors.rgb_percent_to_rgb` as fully as is practical. For conversions between hexadecimal and integer ``rgb()``, it generates all 16,777,216 possible color values for each format in order (starting at ``#000000`` and ``(0,0,0)`` and incrementing), and verifies that each one converts to the corresponding value in the other format. Thus, it is possible to be confident that webcolors provides correct conversions between all possible color values in those formats. Testing the correctness of conversion to and from percentage ``rgb()``, however, is more difficult, and a full test is not provided, for two reasons: 1. Because percentage ``rgb()`` values can make use of floating-point values, and because standard floating-point types in most common programming languages (Python included) are inherently imprecise, exact verification is not possible. 2. The only rigorous definition of the format of a percentage value is in CSS2, `which declares a percentage to be `_ "a `` immediately followed by '%'". `The CSS2 definition of a number `_ places no limit on the length past the decimal point, and appears to be declaring any real number as a valid value, though percentage triplets clip their inputs to the range 0.0-100.0. As the subset of reals in the range 0.0 to 100.0 is uncountably infinite, testing all legal values is not possible on current hardware in any reasonable amount of time. Since precise correctness and completeness are not achievable, webcolors instead aims to achieve *consistency* in conversions. Specifically, the ``full_colors.py`` test generates all 16,777,216 integer ``rgb()`` triplets, and for each such triplet `t` verifies that the following assertion holds: .. code-block:: python t == rgb_percent_to_rgb(rgb_to_rgb_percent(t)) Running the tests ----------------- The standard test runner for webcolors is `nox `_, which supports testing against multiple Python versions and executing a variety of different test tasks. The source distribution of webcolors includes its ``noxfile.py`` file. To run the tests, install nox (``pip install nox``), then download and unpack a git checkout or source package of webcolors. To run the normal test suite against the complete set of supported Python versions: .. tab:: macOS/Linux/other Unix .. code-block:: shell python -m pip install nox python -m nox .. tab:: Windows .. code-block:: shell py -m pip install nox py -m nox This requires that you have each supported version of Python (for webcolors |release|, this is 3.7, 3.8, 3.9, 3.10, and 3.11) available. To test only against a specific version of Python, use the ``--python`` flag and pass the version to test. For example, to test on Python 3.10: .. tab:: macOS/Linux/other Unix .. code-block:: shell python -m nox --python "3.10" .. tab:: Windows .. code-block:: shell py -m nox --python "3.10" To run the full verification tests for definition correctness and conversions, specify the "release" test keyword instead (so named because these tests are usually run only prior to a new release of webcolors): .. tab:: macOS/Linux/other Unix .. code-block:: shell python -m nox --keyword release .. tab:: Windows .. code-block:: shell py -m nox --keyword release Note that this requires an internet connection, and is CPU-intensive. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670308543.0 webcolors-1.13/docs/contents.rst0000644000076700000240000001631314343561277016020 0ustar00jamesstaff.. module:: webcolors .. _contents: Module contents =============== The contents of the webcolors module fall into five categories: 1. A set of (optional) data types for representing color values. 2. Constants for several purposes. 3. Normalization functions which sanitize input in various formats prior to conversion or output. 4. Conversion functions between each method of specifying colors. 5. Implementations of the color parsing and serialization algorithms in HTML5. See :ref:`the documentation regarding conventions ` for information regarding the types and representation of various color formats in webcolors. All conversion functions which involve color names take an optional argument to determine the specification from which to draw color names. See :ref:`the set of specification identifiers ` for valid values. All conversion functions, when faced with identifiably invalid hexadecimal color values, or with a request to name a color which has no name in the requested specification, or with an invalid specification identifier, will raise :exc:`ValueError`. .. admonition:: **Imports and submodules** The public, supported API of webcolors is exported from its top-level module, ``webcolors``. Although the codebase is internally organized into several submodules for easier maintenance, the existence, names, and organization of these submodules is *not* part of webcolors' public API and cannot be relied upon. For example: although :func:`normalize_hex` is actually implemented in a submodule named ``webcolors.normalization``, it must always be referred to as ``webcolors.normalize_hex``, **never** as ``webcolors.normalization.normalize_hex``. Data types ---------- Integer and percentage ``rgb()`` triplets, and HTML5 simple colors, can be passed to functions in webcolors as plain 3-:class:`tuple` of the appropriate data type. But the following :class:`~typing.NamedTuple` instances are also provided to represent these types more richly, and functions in webcolors which return triplets or simple colors will return instances of these: .. autoclass:: IntegerRGB .. autoclass:: PercentRGB .. autoclass:: HTML5SimpleColor Additionally, to aid in type annotations, the following type aliases are defined, and used throughout this module: .. autodata:: IntTuple .. autodata:: PercentTuple Constants --------- Several sets of constants are provided in webcolors, for use when converting or identifying colors or specifications. .. _spec-constants: Specification identifiers ~~~~~~~~~~~~~~~~~~~~~~~~~~ The following constants are available for indicating the specification from which to draw color name choices, in functions which can work with multiple specifications. .. data:: CSS2 Represents the CSS2 specification. Value is ``"css2"``. .. data:: CSS21 Represents the CSS2.1 specification. Value is ``"css21"``. .. data:: CSS3 Represents the CSS3 specification. Value is ``"css3"``. .. data:: HTML4 Represents the HTML 4 specification. Value is ``"html4"``. .. _mapping-constants: Color mappings ~~~~~~~~~~~~~~ The following constants are available for direct use in mapping from color names to values, although it is strongly recommended to use one of the normalizing conversion functions instead. Mappings from names to hexadecimal values +++++++++++++++++++++++++++++++++++++++++ .. data:: HTML4_NAMES_TO_HEX A :class:`dict` whose keys are the normalized names of the sixteen named HTML 4 colors, and whose values are the normalized hexadecimal values of those colors. .. data:: CSS2_NAMES_TO_HEX An alias for :data:`~webcolors.HTML4_NAMES_TO_HEX`, as CSS2 defined the same set of colors. .. data:: CSS21_NAMES_TO_HEX A :class:`dict` whose keys are the normalized names of the seventeen named CSS2.1 colors, and whose values are the normalized hexadecimal values of those colors (sixteen of these are identical to HTML 4 and CSS2; the seventeenth color is ``"orange"``, added in CSS2.1). .. data:: CSS3_NAMES_TO_HEX A :class:`dict` whose keys are the normalized names of the 147 named CSS3 colors, and whose values are the normalized hexadecimal values of those colors. These colors are also identical to the 147 named colors of SVG. Mappings from hexadecimal values to names +++++++++++++++++++++++++++++++++++++++++ .. data:: HTML4_HEX_TO_NAMES A :class:`dict` whose keys are the normalized hexadecimal values of the sixteen named HTML 4 colors, and whose values are the corresponding normalized names. .. data:: CSS2_HEX_TO_NAMES An alias for :data:`~webcolors.HTML4_HEX_TO_NAMES`, as CSS2 defined the same set of colors. .. data:: CSS21_HEX_TO_NAMES A :class:`dict` whose keys are the normalized hexadecimal values of the seventeen named CSS2.1 colors, and whose values are the corresponding normalized names (sixteen of these are identical to HTML 4 and CSS2; the seventeenth color is ``"orange"``, added in CSS2.1). .. data:: CSS3_HEX_TO_NAMES A :class:`dict` whose keys are the normalized hexadecimal values of the 147 named CSS3 colors, and whose values are the corresponding normalized names. These colors are also identical to the 147 named colors of SVG. .. note:: **Spelling variants** Some values representing named gray colors can map to either of two names in CSS3, because it supports both ``"gray"`` and ``"grey"`` spelling variants for those colors. This mapping will always return the variant spelled ``"gray"`` (such as ``"lightgray"`` instead of ``"lightgrey"``). See :ref:`the documentation on name conventions ` for details. Normalization functions ----------------------- .. autofunction:: normalize_hex .. autofunction:: normalize_integer_triplet .. autofunction:: normalize_percent_triplet Conversions from color names to other formats --------------------------------------------- .. autofunction:: name_to_hex .. autofunction:: name_to_rgb .. autofunction:: name_to_rgb_percent Conversions from hexadecimal color values to other formats ---------------------------------------------------------- .. autofunction:: hex_to_name .. autofunction:: hex_to_rgb .. autofunction:: hex_to_rgb_percent Conversions from integer `rgb()` triplets to other formats ------------------------------------------------------------ .. autofunction:: rgb_to_name .. autofunction:: rgb_to_hex .. autofunction:: rgb_to_rgb_percent Conversions from percentage `rgb()` triplets to other formats --------------------------------------------------------------- .. autofunction:: rgb_percent_to_name .. autofunction:: rgb_percent_to_hex .. autofunction:: rgb_percent_to_rgb .. _html5-algorithms: HTML5 color algorithms ---------------------- .. warning:: Previously there were two competing HTML5 standards: one from WHATWG, and one from W3C. The WHATWG version is now the sole official HTML5 standard, and so the functions documented below implement the HTML5 color algorithms as given in `section 2.3.6 of the WHATWG HTML5 standard `_. .. autofunction:: html5_parse_simple_color .. autofunction:: html5_serialize_simple_color .. autofunction:: html5_parse_legacy_color ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670309757.0 webcolors-1.13/docs/conventions.rst0000644000076700000240000001241414343563575016531 0ustar00jamesstaff.. _conventions: Normalization and conventions ============================= Since the various formats used to specify colors in web documents do not always map cleanly to Python data types, and some variation is permitted in how to use each format in a web document, webcolors applies a set of conventions for representing color names and values, and for normalizing them. .. _string-types: Python string types ------------------- As Python 2 is no longer supported by the Python core team, webcolors now supports only Python 3, where the string type is a Unicode string. Python 3 does still have the :class:`bytes` type, but all string arguments to functions in webcolors must be :class:`str` and never :class:`bytes`. Hexadecimal color values ------------------------ For colors specified via hexadecimal values, webcolors will accept strings in the following formats: * The character ``#`` followed by three hexadecimal digits, where digits A-F may be upper- or lowercase. * The character ``#`` followed by six hexadecimal digits, where digits A-F may be upper- or lowercase (i.e., what HTML5 designates a "valid simple color" when all digits are uppercase, and a "valid lowercase simple color" when all digits are lowercase). For output which consists of a color specified via hexadecimal values, and for functions which perform intermediate conversion to hexadecimal before returning a result in another format, webcolors always normalizes such values to a string in the following format: * The character ``#`` followed by six hexadecimal digits, with digits A-F forced to lowercase (what HTML5 designates a "valid lowercase simple color"). The function :func:`~webcolors.normalize_hex` can be used to perform this normalization manually if desired. Integer and percentage ``rgb()`` triplets ----------------------------------------- Functions which work with integer ``rgb()`` triplets accept them as a 3-:class:`tuple` of Python :class:`int`. Functions which work with percentage ``rgb()`` triplets accept them as 3-:class:`tuple` of Python strings (see :ref:`above regarding Python string types `). Plain tuples are accepted by all functions which deal with integer or percentage ``rgb()`` triplets, but three types of :func:`~collections.namedtuple` are also provided to represent these values: :class:`~webcolors.IntegerRGB` for integer triplets, :class:`~webcolors.PercentRGB` for percentage triplets, and :class:`~webcolors.HTML5SimpleColor` for an HTML5 simple color. Functions which return an integer or percentage ``rgb()`` triplet, or an HTML5 simple color, will return values of these types. Internally, Python :class:`float` is used in some conversions to and from the triplet representations; for each function which may have the precision of its results affected by this, a note is provided in the documentation. For colors specified via ``rgb()`` triplets, values contained in the triplets will be normalized in accordance with CSS clipping rules: * Integer values less than 0 will be normalized to 0, and percentage values less than 0% will be normalized to 0%. * Integer values greater than 255 will be normalized to 255, and percentage values greater than 100% will be normalized to 100%. * The "negative zero" values -0 and -0% will be normalized to 0 and 0%, respectively. The functions :func:`~webcolors.normalize_integer_triplet` and :func:`~webcolors.normalize_percent_triplet` can be used to perform this normalization manually if desired. .. _color-name-conventions: Color names ----------- For colors specified via predefined names, webcolors will accept strings containing names case-insensitively, so long as they contain no spaces or non-alphabetic characters. Thus, for example, ``"AliceBlue"`` and ``"aliceblue"`` are both accepted, and both will refer to the same color: ``rgb(240, 248, 255)``. For output which consists of a color name, and for functions which perform intermediate conversion to a predefined name before returning a result in another format, webcolors always normalizes such values to be entirely lowercase. .. note:: **Spelling variants** HTML 4, CSS1, and CSS2 each defined a color named ``"gray"``. In CSS3, this color can be named either ``"gray"`` or ``"grey"``, and several other related color values each have two names in CSS3: ``"darkgray"``/``"darkgrey"``, ``"darkslategray"``/``"darkslategrey"``, ``"dimgray"``/``"dimgrey"``, ``"lightgray"``/``"lightgrey"``, ``"lightslategray"``/``"lightslategrey"``, ``"slategray"``/``"slategrey"``. Reversing from the hexadecimal value, integer tuple, or percent tuple to a name, for these colors, requires picking one spelling, and webcolors chooses the ``"gray"`` spellings for consistency with HTML 4, CSS1, and CSS2. Identifying sets of named colors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For purposes of identifying the specification from which to draw the selection of defined color names, webcolors uses strings naming the specifications, and provides :ref:`a set of constants containing the correct values `. Note that the CSS1 named colors are not supported here, as CSS1 merely "suggested" a set of color names, and declined to provide values for them. The CSS2 "system colors" are also not represented here, as they had no fixed defined values and are now deprecated. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670308865.0 webcolors-1.13/docs/faq.rst0000644000076700000240000001477514343562001014726 0ustar00jamesstaff.. _faq: Frequently asked questions ========================== The following notes answer common questions, and may be useful to you when using webcolors. What versions of Python are supported? -------------------------------------- The webcolors module supports and is tested on Python 3.7, 3.8, 3.9, 3.10, and 3.11. As of the release of webcolors |release|, these are the only versions of Python receiving upstream security support from the Python core team. How closely does this module follow the standards? -------------------------------------------------- As closely as is practical (see below regarding floating-point values), within :ref:`the supported formats `; the webcolors module was written with the relevant standards documents close at hand. See :ref:`the conformance documentation ` for details. Why aren't ``rgb_to_rgb_percent()`` and ``rgb_percent_to_rgb()`` precise? ------------------------------------------------------------------------- This is due to limitations in the representation of floating-point numbers in programming languages. Python, like many programming languages, uses `IEEE floating-point `_, which is inherently imprecise for some values. This imprecision only appears when converting between integer and percentage ```rgb()``` triplets, as in :func:`~webcolors.rgb_to_rgb_percent` and :func:`~webcolors.rgb_percent_to_rgb`. To work around this, some common values (255, 128, 64, 32, 16 and 0) are handled as special cases, with hard-coded precise results. For all other values, conversion to percentage ``rgb()`` triplet uses a standard Python :class:`float`, rounding the result to two decimal places. See :ref:`the conformance documentation ` for details on how this affects testing. Why does webcolors prefer American spellings? --------------------------------------------- In CSS3, several color names are defined multiple times with identical values, to support both American and British spelling variants for ``"gray"``/``"grey"``. These colors are: ``"darkgray"``/``"darkgrey"``, ``"darkslategray"``/``"darkslategrey"``, ``"dimgray"``/``"dimgrey"``, ``"gray"``/``"grey"``, ``"lightgray"``/``"lightgrey"``, ``"lightslategray"``/``"lightslategrey"``, ``"slategray"``/``"slategrey"``. Using any of the conversions from names to other formats (:func:`~webcolors.name_to_hex`, :func:`~webcolors.name_to_rgb`, or :func:`~webcolors.name_to_rgb_percent`) will accept either spelling provided the `spec` argument is :data:`~webcolors.CSS3`. However, converting from other formats to a name requires picking one of these spellings. Since webcolors uses a Python :class:`dict` to store its :ref:`name-to-value mappings `, simply reversing those mappings risks inconsistency: swapping the keys and values of a :class:`dict` in Python depends on the key order, which varies from one version of Python to another and in several supported Python versions is not guaranteed to be consistent and/or is documented as an implementation detail not to be relied on. So webcolors must manually pick a spelling to normalize to, and chooses `gray`. This choice was made for consistency with HTML 4, CSS1, and CSS2, each of which only allowed `gray`. Why aren't HSL values supported? -------------------------------- In the author's experience, actual use of HSL values on the web is extremely rare; the overwhelming majority of all colors used on the web are specified using sRGB, through hexadecimal color values or through integer or percentage ``rgb()`` triplets. This decreases the importance of supporting the ``hsl()`` construct. Additionally, Python already has the :mod:`colorsys` module in the standard library, which offers functions for converting between RGB, HSL, HSV and YIQ color systems. If you need conversion to/from HSL or another color system, use :mod:`colorsys`. Why aren't alpha-channel constructs like ``rgba()`` supported? -------------------------------------------------------------- Because the alpha-channel information can't really be usefully converted. As of CSS3, the ``hsla()`` construct is the only other color format that carries alpha-channel information, and as explained above, HSL colors are not supported in this module. The in-progress W3C CSS Colors Level 4 module does provide an 8-digit hexadecimal color representation where the final two digits carry alpha-channel information. If and when that module becomes a W3C Recommendation with broad support in web client software, support for alpha-channel constructs in this module may be re-evaluated, though it would still be limited to converting between only those constructs which carry alpha-channel information (for example, an ``rgba()`` or an eight-digit hexadecimal color value could not be losslessly round-tripped to a color name and back). Why not use a more object-oriented design with classes for the colors? ---------------------------------------------------------------------- Representing color values with Python classes would introduce overhead for no real gain. Real-world use cases tend to involve working directly with the actual values, so settling on conventions for how to represent them as Python types, and then offering a function-based interface, accomplishes everything needed without the additional indirection layer of having to instantiate and serialize a color-wrapping object. Keeping a function-based interface also maintains consistency with Python's built-in :mod:`colorsys` module which has the same style of interface for converting amongst color spaces. Note that if an object-oriented interface is desired, `the third-party colormath module `_ does have a class-based interface (and rightly so, as it offers a wider range of color representation and manipulation options than webcolors). How am I allowed to use this module? ------------------------------------ The webcolors module is distributed under a `three-clause BSD license `_. This is an open-source license which grants you broad freedom to use, redistribute, modify and distribute modified versions of webcolors. For details, see the file ``LICENSE`` in the source distribution of webcolors. .. _three-clause BSD license: http://opensource.org/licenses/BSD-3-Clause I found a bug or want to make an improvement! --------------------------------------------- The canonical development repository for webcolors is online at . Issues and pull requests can both be filed there. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1671409991.0 webcolors-1.13/docs/index.rst0000644000076700000240000000303414347730507015264 0ustar00jamesstaffwebcolors |release| =================== This module provides utility functions for working with the color names and color value formats defined by the HTML and CSS specifications for use in documents on the web. Support is included for normalizing and converting between the following formats (RGB colorspace only; conversion to/from HSL can be handled by the :mod:`colorsys` module in the Python standard library): * Specification-defined color names * Six-digit hexadecimal * Three-digit hexadecimal * Integer ``rgb()`` triplet * Percentage ``rgb()`` triplet For example:: >>> import webcolors >>> webcolors.hex_to_name("#daa520") 'goldenrod' Implementations are also provided for the HTML5 color parsing and serialization algorithms. For example, parsing the infamous "chucknorris" string into an ``rgb()`` triplet:: >>> import webcolors >>> webcolors.html5_parse_legacy_color("chucknorris") HTML5SimpleColor(red=192, blue=0, green=0) Documentation contents ---------------------- .. toctree:: :maxdepth: 1 install colors conventions contents conformance changelog faq .. seealso:: * `The sRGB color space `_ * `HTML 4: Colors `_ * `CSS1: Color units `_ * `CSS2: Colors `_ * `CSS3 color module `_ * `HTML5: Colors `_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1675144971.0 webcolors-1.13/docs/install.rst0000644000076700000240000000376614366127413015634 0ustar00jamesstaff.. _install: Installation guide ================== The |release| version of webcolors is officially tested and supported on the following versions of Python: * Python 3.7 * Python 3.8 * Python 3.9 * Python 3.10 * Python 3.11 Installing webcolors -------------------- To install webcolors, run the following command from a command prompt/terminal: .. tab:: macOS/Linux/other Unix .. code-block:: shell python -m pip install webcolors .. tab:: Windows .. code-block:: shell py -m pip install webcolors This will use ``pip``, the standard Python package-installation tool. If you are using a supported version of Python, your installation of Python should have come with ``pip`` bundled. If ``pip`` does not appear to be present, you can try running the following from a command prompt/terminal: .. tab:: macOS/Linux/other Unix .. code-block:: shell python -m ensurepip --upgrade .. tab:: Windows .. code-block:: shell py -m ensurepip --upgrade Instructions are also available for `how to obtain and manually install or upgrade pip `_. If you don't already have a supported version of Django installed, using ``pip`` to install webcolors will also install the latest supported version of Django. Installing from a source checkout --------------------------------- If you want to work on webcolors, you can obtain a source checkout. The development repository for webcolors is at . If you have `git `_ installed, you can obtain a copy of the repository by typing:: git clone https://github.com/ubernostrum/webcolors.git From there, you can use git commands to check out the specific revision you want, and perform an "editable" install (allowing you to change code as you work on it) by typing: .. tab:: macOS/Linux/other Unix .. code-block:: shell python -m pip install -e . .. tab:: Windows .. code-block:: shell py -m pip install -e . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1378901941.0 webcolors-1.13/docs/make.bat0000644000076700000240000000562512214057665015036 0ustar00jamesstaff@ECHO OFF REM Command file for Sphinx documentation set SPHINXBUILD=sphinx-build set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (_build\*) do rmdir /q /s %%i del /q /s _build\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html echo. echo.Build finished. The HTML pages are in _build/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% _build/dirhtml echo. echo.Build finished. The HTML pages are in _build/dirhtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in _build/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in _build/qthelp, like this: echo.^> qcollectiongenerator _build\qthelp\webcolors.qhcp echo.To view the help file: echo.^> assistant -collectionFile _build\qthelp\webcolors.ghc goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex echo. echo.Build finished; the LaTeX files are in _build/latex. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes echo. echo.The overview file is in _build/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck echo. echo.Link check complete; look for any errors in the above output ^ or in _build/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% _build/doctest echo. echo.Testing of doctests in the sources finished, look at the ^ results in _build/doctest/output.txt. goto end ) :end ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1671416541.0 webcolors-1.13/docs/spelling_wordlist.txt0000644000076700000240000000035514347745335017740 0ustar00jamesstaffamongst bugfixes bytestrings declaratively chucknorris codebase colorspace gz HSL identifiably incrementing internet losslessly nox online sRGB rgb submodule submodules superset trichromatic tuple tuples uncountably unprefixed versa whl ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1674029103.0 webcolors-1.13/noxfile.py0000644000076700000240000002477014361724057014522 0ustar00jamesstaff""" Automated testing via nox (https://nox.thea.codes/). Combined with a working installation of nox (``pip install nox``), this file specifies a matrix of tests, linters, and other quality checks which can be run individually or as a suite. To see available tasks, run ``nox --list``. To run all available tasks -- which requires functioning installs of all supported Python versions -- run ``nox``. To run a single task, use ``nox -s`` with the name of that task. """ import os import pathlib import shutil import typing import nox nox.options.default_venv_backend = "venv" nox.options.keywords = "not release" nox.options.reuse_existing_virtualenvs = True nox.options.default_venv_backend = "venv" nox.options.reuse_existing_virtualenvs = True PACKAGE_NAME = "webcolors" NOXFILE_PATH = pathlib.Path(__file__).parents[0] ARTIFACT_PATHS = ( NOXFILE_PATH / "src" / f"{PACKAGE_NAME}.egg-info", NOXFILE_PATH / "build", NOXFILE_PATH / "dist", NOXFILE_PATH / "__pycache__", NOXFILE_PATH / "src" / "__pycache__", NOXFILE_PATH / "src" / PACKAGE_NAME / "__pycache__", NOXFILE_PATH / "tests" / "__pycache__", ) def clean(paths: typing.Iterable[os.PathLike] = ARTIFACT_PATHS) -> None: """ Clean up after a test run. """ [ shutil.rmtree(path) if path.is_dir() else path.unlink() for path in paths if path.exists() ] # Tasks which run the package's test suites. # ----------------------------------------------------------------------------------- @nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11"], tags=["tests"]) def tests_with_coverage(session: nox.Session) -> None: """ Run the package's unit tests, with coverage report. """ session.install(".[tests]") session.run( f"python{session.python}", "-Wonce::DeprecationWarning", "-Im", "pytest", "-vv", "--ignore=src", "--cov=webcolors", "--cov-report", "term-missing", ) clean() @nox.session(python=["3.11"], tags=["tests", "release"]) def tests_definitions(session: nox.Session) -> None: """ Run the full color definitions test suite (requires an internet connection). """ session.install("pytest", "bs4", "html5lib", "requests", ".[tests]") session.run( f"python{session.python}", "-Im", "pytest", "-vv", "tests/definitions.py" ) clean() @nox.session(python=["3.11"], tags=["tests", "release"]) def tests_full_colors(session: nox.Session) -> None: """ Run the full color conversion test suite (slow/CPU-intensive). """ session.install(".[tests]") session.run( f"python{session.python}", "-Im", "pytest", "-vv", "tests/full_colors.py" ) clean() # Tasks which test the package's documentation. # ----------------------------------------------------------------------------------- @nox.session(python=["3.11"], tags=["docs"]) def docs_build(session: nox.Session) -> None: """ Build the package's documentation as HTML. """ session.install(".[docs]") session.chdir("docs") session.run( f"{session.bin}/python{session.python}", "-Im", "sphinx", "-b", "html", "-d", f"{session.bin}/../tmp/doctrees", ".", f"{session.bin}/../tmp/html", ) clean() @nox.session(python=["3.11"], tags=["docs"]) def docs_docstrings(session: nox.Session) -> None: """ Enforce the presence of docstrings on all modules, classes, functions, and methods. """ session.install("interrogate") session.run(f"python{session.python}", "-Im", "interrogate", "--version") session.run( f"python{session.python}", "-Im", "interrogate", "-v", "src/", "tests/", "noxfile.py", ) clean() @nox.session(python=["3.11"], tags=["docs"]) def docs_spellcheck(session: nox.Session) -> None: """ Spell-check the package's documentation. """ session.install( "pyenchant", "sphinxcontrib-spelling", ".[docs]", ) build_dir = session.create_tmp() session.chdir("docs") session.run( f"{session.bin}/python{session.python}", "-Im", "sphinx", "-W", # Promote warnings to errors, so that misspelled words fail the build. "-b", "spelling", "-d", f"{build_dir}/doctrees", ".", f"{build_dir}/html", # On Apple Silicon Macs, this environment variable needs to be set so # pyenchant can find the "enchant" C library. See # https://github.com/pyenchant/pyenchant/issues/265#issuecomment-1126415843 env={"PYENCHANT_LIBRARY_PATH": os.getenv("PYENCHANT_LIBRARY_PATH", "")}, ) clean() @nox.session(python=["3.11"], tags=["docs", "tests"]) def docs_test(session: nox.Session) -> None: """ Run the code samples in the documentation with doctest, to ensure they are correct. """ session.install(".[docs]") build_dir = session.create_tmp() session.chdir("docs") session.run( f"{session.bin}/python{session.python}", "-Im", "sphinx", "-b", "doctest", "-d", f"{build_dir}/doctrees", ".", f"{build_dir}/html", ) clean() # Code formatting checks. # # These checks do *not* reformat code -- that happens in pre-commit hooks -- but will # fail a CI build if they find any code that needs reformatting. # ----------------------------------------------------------------------------------- @nox.session(python=["3.11"], tags=["formatters"]) def format_black(session: nox.Session) -> None: """ Check code formatting with Black. """ session.install("black") session.run(f"python{session.python}", "-Im", "black", "--version") session.run( f"python{session.python}", "-Im", "black", "--check", "--diff", "src/", "tests/", "docs/", "noxfile.py", ) clean() @nox.session(python=["3.11"], tags=["formatters"]) def format_isort(session: nox.Session) -> None: """ Check code formating with Black. """ session.install("isort") session.run(f"python{session.python}", "-Im", "isort", "--version") session.run( f"python{session.python}", "-Im", "isort", "--check-only", "--diff", "src/", "tests/", "docs/", "noxfile.py", ) clean() # Linters. # ----------------------------------------------------------------------------------- @nox.session(python=["3.11"], tags=["linters", "security"]) def lint_bandit(session: nox.Session) -> None: """ Lint code with the Bandit security analyzer. """ session.install("bandit[toml]") session.run(f"python{session.python}", "-Im", "bandit", "--version") session.run( f"python{session.python}", "-Im", "bandit", "-c", "./pyproject.toml", "-r", "src/", "tests/", ) clean() @nox.session(python=["3.11"], tags=["linters"]) def lint_flake8(session: nox.Session) -> None: """ Lint code with flake8. """ session.install("flake8", "flake8-bugbear") session.run(f"python{session.python}", "-Im", "flake8", "--version") session.run( f"python{session.python}", "-Im", "flake8", "src/", "tests/", "docs/", "noxfile.py", ) clean() @nox.session(python=["3.11"], tags=["linters"]) def lint_pylint(session: nox.Session) -> None: """ Lint code with Pyling. """ # Pylint requires that all dependencies be importable during the run. This package # does not have any direct dependencies, nor does the normal test suite, but the # full conformance suite does require a few extra libraries, so they're installed # here. session.install("pylint", "bs4", "html5lib", "requests") session.run(f"python{session.python}", "-Im", "pylint", "--version") session.run(f"python{session.python}", "-Im", "pylint", "src/", "tests/") clean() # Packaging checks. # ----------------------------------------------------------------------------------- @nox.session(python=["3.11"], tags=["packaging"]) def package_build(session: nox.Session) -> None: """ Check that the package builds. """ session.install("build") session.run(f"python{session.python}", "-Im", "build", "--version") session.run(f"python{session.python}", "-Im", "build") clean() @nox.session(python=["3.11"], tags=["packaging"]) def package_description(session: nox.Session) -> None: """ Check that the package description will render on the Python Package Index. """ package_dir = session.create_tmp() session.install("build", "twine") session.run(f"python{session.python}", "-Im", "build", "--version") session.run(f"python{session.python}", "-Im", "twine", "--version") session.run( f"python{session.python}", "-Im", "build", "--wheel", "--outdir", f"{package_dir}/build", ) session.run( f"python{session.python}", "-Im", "twine", "check", f"{package_dir}/build/*" ) clean() @nox.session(python=["3.11"], tags=["packaging"]) def package_manifest(session: nox.Session) -> None: """ Check that the set of files in the package matches the set under version control. """ session.install("check-manifest") session.run(f"python{session.python}", "-Im", "check_manifest", "--version") session.run(f"python{session.python}", "-Im", "check_manifest", "--verbose") clean() @nox.session(python=["3.11"], tags=["packaging"]) def package_pyroma(session: nox.Session) -> None: """ Check package quality with pyroma. """ session.install("pyroma") session.run(f"python{session.python}", "-Im", "pyroma", ".") clean() @nox.session(python=["3.11"], tags=["packaging"]) def package_wheel(session: nox.Session) -> None: """ Check the built wheel package for common errors. """ package_dir = session.create_tmp() session.install("build", "check-wheel-contents") session.run(f"python{session.python}", "-Im", "build", "--version") session.run(f"python{session.python}", "-Im", "check_wheel_contents", "--version") session.run( f"python{session.python}", "-Im", "build", "--wheel", "--outdir", f"{package_dir}/build", ) session.run( f"python{session.python}", "-Im", "check_wheel_contents", f"{package_dir}/build" ) clean() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676363467.0 webcolors-1.13/pyproject.toml0000644000076700000240000000301314372643313015400 0ustar00jamesstaff[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] authors = [ {name = "James Bennett", email = "james@b-list.org"} ] classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Topic :: Utilities", ] name = "webcolors" description = "A library for working with the color formats defined by HTML and CSS." dynamic = ["version"] keywords = ["color", "css", "html", "web"] license = {text = "BSD-3-Clause"} readme = "README.rst" requires-python = ">=3.7" [project.urls] documentation = "https://webcolors.readthedocs.io" homepage = "https://github.com/ubernostrum/webcolors" [project.optional-dependencies] docs = [ "furo", "sphinx", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-notfound-page", "sphinxext-opengraph", ] tests = [ "pytest", "pytest-cov", ] [tool.bandit] skips = ["B101"] [tool.black] target-version = ["py37"] [tool.coverage.report] fail_under = 100 [tool.interrogate] ignore-init-module = true [tool.isort] profile = "black" [tool.setuptools.dynamic] version = {attr = "webcolors.__version__"} ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1679896362.6627133 webcolors-1.13/setup.cfg0000644000076700000240000000004614410227453014304 0ustar00jamesstaff[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1679896362.6522102 webcolors-1.13/src/0000755000076700000240000000000014410227453013252 5ustar00jamesstaff././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1679896362.6555932 webcolors-1.13/src/webcolors/0000755000076700000240000000000014410227453015251 5ustar00jamesstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1679895949.0 webcolors-1.13/src/webcolors/__init__.py0000644000076700000240000000367214410226615017371 0ustar00jamesstaff""" Utility functions for working with the color names and color value formats defined by the HTML and CSS specifications for use in documents on the web. See documentation (in docs/ directory of source distribution) for details of the supported formats, conventions and conversions. """ from .constants import ( CSS2, CSS2_HEX_TO_NAMES, CSS2_NAMES_TO_HEX, CSS3, CSS3_HEX_TO_NAMES, CSS3_NAMES_TO_HEX, CSS21, CSS21_HEX_TO_NAMES, CSS21_NAMES_TO_HEX, HTML4, HTML4_HEX_TO_NAMES, HTML4_NAMES_TO_HEX, ) from .conversion import ( hex_to_name, hex_to_rgb, hex_to_rgb_percent, name_to_hex, name_to_rgb, name_to_rgb_percent, rgb_percent_to_hex, rgb_percent_to_name, rgb_percent_to_rgb, rgb_to_hex, rgb_to_name, rgb_to_rgb_percent, ) from .html5 import ( html5_parse_legacy_color, html5_parse_simple_color, html5_serialize_simple_color, ) from .normalization import ( normalize_hex, normalize_integer_triplet, normalize_percent_triplet, ) from .types import HTML5SimpleColor, IntegerRGB, IntTuple, PercentRGB, PercentTuple __version__ = "1.13" __all__ = [ "HTML4", "CSS2", "CSS21", "CSS3", "HTML4_NAMES_TO_HEX", "HTML4_HEX_TO_NAMES", "CSS2_NAMES_TO_HEX", "CSS2_HEX_TO_NAMES", "CSS21_HEX_TO_NAMES", "CSS21_NAMES_TO_HEX", "CSS3_HEX_TO_NAMES", "CSS3_NAMES_TO_HEX", "name_to_hex", "name_to_rgb", "name_to_rgb_percent", "hex_to_name", "hex_to_rgb", "hex_to_rgb_percent", "rgb_to_hex", "rgb_to_name", "rgb_to_rgb_percent", "rgb_percent_to_hex", "rgb_percent_to_name", "rgb_percent_to_rgb", "html5_parse_simple_color", "html5_parse_legacy_color", "html5_serialize_simple_color", "normalize_hex", "normalize_integer_triplet", "normalize_percent_triplet", "IntegerRGB", "PercentRGB", "HTML5SimpleColor", "IntTuple", "PercentTuple", ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1668498722.0 webcolors-1.13/src/webcolors/constants.py0000644000076700000240000001757214334642442017657 0ustar00jamesstaff""" Constants representing valid formats and values for colors. """ import re def _reversedict(dict_to_reverse: dict) -> dict: """ Internal helper for generating reverse mappings; given a dictionary, returns a new dictionary with keys and values swapped. """ return {value: key for key, value in dict_to_reverse.items()} HEX_COLOR_RE = re.compile(r"^#([a-fA-F0-9]{3}|[a-fA-F0-9]{6})$") HTML4 = "html4" CSS2 = "css2" CSS21 = "css21" CSS3 = "css3" SUPPORTED_SPECIFICATIONS = (HTML4, CSS2, CSS21, CSS3) SPECIFICATION_ERROR_TEMPLATE = ( f"{{spec}} is not a supported specification for color name lookups; " f"supported specifications are: {SUPPORTED_SPECIFICATIONS}." ) # Mappings of color names to normalized hexadecimal color values. # -------------------------------------------------------------------------------- # The HTML 4 named colors. # # The canonical source for these color definitions is the HTML 4 # specification: # # http://www.w3.org/TR/html401/types.html#h-6.5 # # The file tests/definitions.py in the source distribution of this # module downloads a copy of the HTML 4 standard and parses out the # color names to ensure the values below are correct. HTML4_NAMES_TO_HEX = { "aqua": "#00ffff", "black": "#000000", "blue": "#0000ff", "fuchsia": "#ff00ff", "green": "#008000", "gray": "#808080", "lime": "#00ff00", "maroon": "#800000", "navy": "#000080", "olive": "#808000", "purple": "#800080", "red": "#ff0000", "silver": "#c0c0c0", "teal": "#008080", "white": "#ffffff", "yellow": "#ffff00", } # CSS2 used the same list as HTML 4. CSS2_NAMES_TO_HEX = HTML4_NAMES_TO_HEX # CSS2.1 added orange. CSS21_NAMES_TO_HEX = {"orange": "#ffa500", **HTML4_NAMES_TO_HEX} # The CSS3/SVG named colors. # # The canonical source for these color definitions is the SVG # specification's color list (which was adopted as CSS 3's color # definition): # # http://www.w3.org/TR/SVG11/types.html#ColorKeywords # # CSS3 also provides definitions of these colors: # # http://www.w3.org/TR/css3-color/#svg-color # # SVG provides the definitions as RGB triplets. CSS3 provides them # both as RGB triplets and as hexadecimal. Since hex values are more # common in real-world HTML and CSS, the mapping below is to hex # values instead. The file tests/definitions.py in the source # distribution of this module downloads a copy of the CSS3 color # module and parses out the color names to ensure the values below are # correct. CSS3_NAMES_TO_HEX = { "aliceblue": "#f0f8ff", "antiquewhite": "#faebd7", "aqua": "#00ffff", "aquamarine": "#7fffd4", "azure": "#f0ffff", "beige": "#f5f5dc", "bisque": "#ffe4c4", "black": "#000000", "blanchedalmond": "#ffebcd", "blue": "#0000ff", "blueviolet": "#8a2be2", "brown": "#a52a2a", "burlywood": "#deb887", "cadetblue": "#5f9ea0", "chartreuse": "#7fff00", "chocolate": "#d2691e", "coral": "#ff7f50", "cornflowerblue": "#6495ed", "cornsilk": "#fff8dc", "crimson": "#dc143c", "cyan": "#00ffff", "darkblue": "#00008b", "darkcyan": "#008b8b", "darkgoldenrod": "#b8860b", "darkgray": "#a9a9a9", "darkgrey": "#a9a9a9", "darkgreen": "#006400", "darkkhaki": "#bdb76b", "darkmagenta": "#8b008b", "darkolivegreen": "#556b2f", "darkorange": "#ff8c00", "darkorchid": "#9932cc", "darkred": "#8b0000", "darksalmon": "#e9967a", "darkseagreen": "#8fbc8f", "darkslateblue": "#483d8b", "darkslategray": "#2f4f4f", "darkslategrey": "#2f4f4f", "darkturquoise": "#00ced1", "darkviolet": "#9400d3", "deeppink": "#ff1493", "deepskyblue": "#00bfff", "dimgray": "#696969", "dimgrey": "#696969", "dodgerblue": "#1e90ff", "firebrick": "#b22222", "floralwhite": "#fffaf0", "forestgreen": "#228b22", "fuchsia": "#ff00ff", "gainsboro": "#dcdcdc", "ghostwhite": "#f8f8ff", "gold": "#ffd700", "goldenrod": "#daa520", "gray": "#808080", "grey": "#808080", "green": "#008000", "greenyellow": "#adff2f", "honeydew": "#f0fff0", "hotpink": "#ff69b4", "indianred": "#cd5c5c", "indigo": "#4b0082", "ivory": "#fffff0", "khaki": "#f0e68c", "lavender": "#e6e6fa", "lavenderblush": "#fff0f5", "lawngreen": "#7cfc00", "lemonchiffon": "#fffacd", "lightblue": "#add8e6", "lightcoral": "#f08080", "lightcyan": "#e0ffff", "lightgoldenrodyellow": "#fafad2", "lightgray": "#d3d3d3", "lightgrey": "#d3d3d3", "lightgreen": "#90ee90", "lightpink": "#ffb6c1", "lightsalmon": "#ffa07a", "lightseagreen": "#20b2aa", "lightskyblue": "#87cefa", "lightslategray": "#778899", "lightslategrey": "#778899", "lightsteelblue": "#b0c4de", "lightyellow": "#ffffe0", "lime": "#00ff00", "limegreen": "#32cd32", "linen": "#faf0e6", "magenta": "#ff00ff", "maroon": "#800000", "mediumaquamarine": "#66cdaa", "mediumblue": "#0000cd", "mediumorchid": "#ba55d3", "mediumpurple": "#9370db", "mediumseagreen": "#3cb371", "mediumslateblue": "#7b68ee", "mediumspringgreen": "#00fa9a", "mediumturquoise": "#48d1cc", "mediumvioletred": "#c71585", "midnightblue": "#191970", "mintcream": "#f5fffa", "mistyrose": "#ffe4e1", "moccasin": "#ffe4b5", "navajowhite": "#ffdead", "navy": "#000080", "oldlace": "#fdf5e6", "olive": "#808000", "olivedrab": "#6b8e23", "orange": "#ffa500", "orangered": "#ff4500", "orchid": "#da70d6", "palegoldenrod": "#eee8aa", "palegreen": "#98fb98", "paleturquoise": "#afeeee", "palevioletred": "#db7093", "papayawhip": "#ffefd5", "peachpuff": "#ffdab9", "peru": "#cd853f", "pink": "#ffc0cb", "plum": "#dda0dd", "powderblue": "#b0e0e6", "purple": "#800080", "red": "#ff0000", "rosybrown": "#bc8f8f", "royalblue": "#4169e1", "saddlebrown": "#8b4513", "salmon": "#fa8072", "sandybrown": "#f4a460", "seagreen": "#2e8b57", "seashell": "#fff5ee", "sienna": "#a0522d", "silver": "#c0c0c0", "skyblue": "#87ceeb", "slateblue": "#6a5acd", "slategray": "#708090", "slategrey": "#708090", "snow": "#fffafa", "springgreen": "#00ff7f", "steelblue": "#4682b4", "tan": "#d2b48c", "teal": "#008080", "thistle": "#d8bfd8", "tomato": "#ff6347", "turquoise": "#40e0d0", "violet": "#ee82ee", "wheat": "#f5deb3", "white": "#ffffff", "whitesmoke": "#f5f5f5", "yellow": "#ffff00", "yellowgreen": "#9acd32", } # Mappings of normalized hexadecimal color values to color names. # -------------------------------------------------------------------------------- HTML4_HEX_TO_NAMES = _reversedict(HTML4_NAMES_TO_HEX) CSS2_HEX_TO_NAMES = HTML4_HEX_TO_NAMES CSS21_HEX_TO_NAMES = _reversedict(CSS21_NAMES_TO_HEX) CSS3_HEX_TO_NAMES = _reversedict(CSS3_NAMES_TO_HEX) # CSS3 defines both "gray" and "grey", as well as defining either # variant for other related colors like "darkgray"/"darkgrey". For a # "forward" lookup from name to hex, this is straightforward, but a # "reverse" lookup from hex to name requires picking one spelling. # # The way in which _reversedict() generates the reverse mappings will # pick a spelling based on the ordering of dictionary keys, which # varies according to the version and implementation of Python in use, # and in some Python versions is explicitly not to be relied on for # consistency. So here we manually pick a single spelling that will # consistently be returned. Since "gray" was the only spelling # supported in HTML 4, CSS1, and CSS2, "gray" and its variants are # chosen. CSS3_HEX_TO_NAMES["#a9a9a9"] = "darkgray" CSS3_HEX_TO_NAMES["#2f4f4f"] = "darkslategray" CSS3_HEX_TO_NAMES["#696969"] = "dimgray" CSS3_HEX_TO_NAMES["#808080"] = "gray" CSS3_HEX_TO_NAMES["#d3d3d3"] = "lightgray" CSS3_HEX_TO_NAMES["#778899"] = "lightslategray" CSS3_HEX_TO_NAMES["#708090"] = "slategray" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1671502068.0 webcolors-1.13/src/webcolors/conversion.py0000644000076700000240000003270214350214364020014 0ustar00jamesstaff""" Functions which convert between various types of color values. """ from . import constants, normalization, types # Conversions from color names to other formats. # -------------------------------------------------------------------------------- def name_to_hex(name: str, spec: str = constants.CSS3) -> str: """ Convert a color name to a normalized hexadecimal color value. The color name will be normalized to lower-case before being looked up. Examples: .. doctest:: >>> name_to_hex("white") '#ffffff' >>> name_to_hex("navy") '#000080' >>> name_to_hex("goldenrod") '#daa520' >>> name_to_hex("goldenrod", spec=HTML4) Traceback (most recent call last): ... ValueError: "goldenrod" is not defined as a named color in html4. :param name: The color name to convert. :param spec: The specification from which to draw the list of color names. Default is :data:`CSS3`. :raises ValueError: when the given name has no definition in the given spec. """ if spec not in constants.SUPPORTED_SPECIFICATIONS: raise ValueError(constants.SPECIFICATION_ERROR_TEMPLATE.format(spec=spec)) hex_value = getattr(constants, f"{spec.upper()}_NAMES_TO_HEX").get(name.lower()) if hex_value is None: raise ValueError(f'"{name}" is not defined as a named color in {spec}') return hex_value def name_to_rgb(name: str, spec: str = constants.CSS3) -> types.IntegerRGB: """ Convert a color name to a 3-:class:`tuple` of :class:`int` suitable for use in an ``rgb()`` triplet specifying that color. The color name will be normalized to lower-case before being looked up. Examples: .. doctest:: >>> name_to_rgb("white") IntegerRGB(red=255, green=255, blue=255) >>> name_to_rgb("navy") IntegerRGB(red=0, green=0, blue=128) >>> name_to_rgb("goldenrod") IntegerRGB(red=218, green=165, blue=32) :param name: The color name to convert. :param spec: The specification from which to draw the list of color names. Default is :data:`CSS3.` :raises ValueError: when the given name has no definition in the given spec. """ return hex_to_rgb(name_to_hex(name, spec=spec)) def name_to_rgb_percent(name: str, spec: str = constants.CSS3) -> types.PercentRGB: """ Convert a color name to a 3-:class:`tuple` of percentages suitable for use in an ``rgb()`` triplet specifying that color. The color name will be normalized to lower-case before being looked up. Examples: .. doctest:: >>> name_to_rgb_percent("white") PercentRGB(red='100%', green='100%', blue='100%') >>> name_to_rgb_percent("navy") PercentRGB(red='0%', green='0%', blue='50%') >>> name_to_rgb_percent("goldenrod") PercentRGB(red='85.49%', green='64.71%', blue='12.5%') :param name: The color name to convert. :param spec: The specification from which to draw the list of color names. Default is :data:`CSS3`. :raises ValueError: when the given name has no definition in the given spec. """ return rgb_to_rgb_percent(name_to_rgb(name, spec=spec)) # Conversions from hexadecimal color values to other formats. # -------------------------------------------------------------------------------- def hex_to_name(hex_value: str, spec: str = constants.CSS3) -> str: """ Convert a hexadecimal color value to its corresponding normalized color name, if any such name exists. The hexadecimal value will be normalized before being looked up. .. note:: **Spelling variants** Some values representing named gray colors can map to either of two names in CSS3, because it supports both ``"gray"`` and ``"grey"`` spelling variants for those colors. This function will always return the variant spelled ``"gray"`` (such as ``"lightgray"`` instead of ``"lightgrey"``). See :ref:`the documentation on name conventions ` for details. Examples: .. doctest:: >>> hex_to_name("#ffffff") 'white' >>> hex_to_name("#fff") 'white' >>> hex_to_name("#000080") 'navy' >>> hex_to_name("#daa520") 'goldenrod' >>> hex_to_name("#daa520", spec=HTML4) Traceback (most recent call last): ... ValueError: "#daa520" has no defined color name in html4. :param hex_value: The hexadecimal color value to convert. :param spec: The specification from which to draw the list of color names. Default is :data:`CSS3`. :raises ValueError: when the given color has no name in the given spec, or when the supplied hex value is invalid. """ if spec not in constants.SUPPORTED_SPECIFICATIONS: raise ValueError(constants.SPECIFICATION_ERROR_TEMPLATE.format(spec=spec)) name = getattr(constants, f"{spec.upper()}_HEX_TO_NAMES").get( normalization.normalize_hex(hex_value) ) if name is None: raise ValueError(f'"{hex_value}" has no defined color name in {spec}.') return name def hex_to_rgb(hex_value: str) -> types.IntegerRGB: """ Convert a hexadecimal color value to a 3-:class:`tuple` of :class:`int` suitable for use in an ``rgb()`` triplet specifying that color. The hexadecimal value will be normalized before being converted. Examples: .. doctest:: >>> hex_to_rgb("#fff") IntegerRGB(red=255, green=255, blue=255) >>> hex_to_rgb("#000080") IntegerRGB(red=0, green=0, blue=128) :param hex_value: The hexadecimal color value to convert. :raises ValueError: when the supplied hex value is invalid. """ int_value = int(normalization.normalize_hex(hex_value)[1:], 16) return types.IntegerRGB(int_value >> 16, int_value >> 8 & 0xFF, int_value & 0xFF) def hex_to_rgb_percent(hex_value: str) -> types.PercentRGB: """ Convert a hexadecimal color value to a 3-:class:`tuple` of percentages suitable for use in an ``rgb()`` triplet representing that color. The hexadecimal value will be normalized before being converted. Examples: .. doctest:: >>> hex_to_rgb_percent("#ffffff") PercentRGB(red='100%', green='100%', blue='100%') >>> hex_to_rgb_percent("#000080") PercentRGB(red='0%', green='0%', blue='50%') :param hex_value: The hexadecimal color value to convert. :raises ValueError: when the supplied hex value is invalid. """ return rgb_to_rgb_percent(hex_to_rgb(hex_value)) # Conversions from integer rgb() triplets to other formats. # -------------------------------------------------------------------------------- def rgb_to_name(rgb_triplet: types.IntTuple, spec: str = constants.CSS3) -> str: """ Convert a 3-:class:`tuple` of :class:`int`, suitable for use in an ``rgb()`` color triplet, to its corresponding normalized color name, if any such name exists. To determine the name, the triplet will be converted to a normalized hexadecimal value. .. note:: **Spelling variants** Some values representing named gray colors can map to either of two names in CSS3, because it supports both ``"gray"`` and ``"grey"`` spelling variants for those colors. This function will always return the variant spelled ``"gray"`` (such as ``"lightgray"`` instead of ``"lightgrey"``). See :ref:`the documentation on name conventions ` for details. Examples: .. doctest:: >>> rgb_to_name((255, 255, 255)) 'white' >>> rgb_to_name((0, 0, 128)) 'navy' :param rgb_triplet: The ``rgb()`` triplet. :param spec: The specification from which to draw the list of color names. Default is :data:`CSS3`. :raises ValueError: when the given color has no name in the given spec. """ return hex_to_name( rgb_to_hex(normalization.normalize_integer_triplet(rgb_triplet)), spec=spec ) def rgb_to_hex(rgb_triplet: types.IntTuple) -> str: """ Convert a 3-:class:`tuple` of :class:`int`, suitable for use in an ``rgb()`` color triplet, to a normalized hexadecimal value for that color. Examples: .. doctest:: >>> rgb_to_hex((255, 255, 255)) '#ffffff' >>> rgb_to_hex((0, 0, 128)) '#000080' :param rgb_triplet: The ``rgb()`` triplet. """ red, green, blue = normalization.normalize_integer_triplet(rgb_triplet) return f"#{red:02x}{green:02x}{blue:02x}" def rgb_to_rgb_percent(rgb_triplet: types.IntTuple) -> types.PercentRGB: """ Convert a 3-:class:`tuple` of :class:`int`, suitable for use in an ``rgb()`` color triplet, to a 3-:class:`tuple` of percentages suitable for use in representing that color. .. note:: **Floating-point precision** This function makes some trade-offs in terms of the accuracy of the final representation. For some common integer values, special-case logic is used to ensure a precise result (e.g., integer 128 will always convert to ``"50%"``, integer 32 will always convert to ``"12.5%"``), but for all other values a standard Python :class:`float` is used and rounded to two decimal places, which may result in a loss of precision for some values due to the inherent imprecision of `IEEE floating-point numbers `_. Examples: .. doctest:: >>> rgb_to_rgb_percent((255, 255, 255)) PercentRGB(red='100%', green='100%', blue='100%') >>> rgb_to_rgb_percent((0, 0, 128)) PercentRGB(red='0%', green='0%', blue='50%') >>> rgb_to_rgb_percent((218, 165, 32)) PercentRGB(red='85.49%', green='64.71%', blue='12.5%') :param rgb_triplet: The ``rgb()`` triplet. """ # In order to maintain precision for common values, # special-case them. specials = { 255: "100%", 128: "50%", 64: "25%", 32: "12.5%", 16: "6.25%", 0: "0%", } return types.PercentRGB._make( specials.get(d, f"{d / 255.0 * 100:.02f}%") for d in normalization.normalize_integer_triplet(rgb_triplet) ) # Conversions from percentage rgb() triplets to other formats. # -------------------------------------------------------------------------------- def rgb_percent_to_name( rgb_percent_triplet: types.PercentTuple, spec: str = constants.CSS3 ) -> str: """ Convert a 3-:class:`tuple` of percentages, suitable for use in an ``rgb()`` color triplet, to its corresponding normalized color name, if any such name exists. To determine the name, the triplet will be converted to a normalized hexadecimal value. .. note:: **Spelling variants** Some values representing named gray colors can map to either of two names in CSS3, because it supports both ``"gray"`` and ``"grey"`` spelling variants for those colors. This function will always return the variant spelled ``"gray"`` (such as ``"lightgray"`` instead of ``"lightgrey"``). See :ref:`the documentation on name conventions ` for details. Examples: .. doctest:: >>> rgb_percent_to_name(("100%", "100%", "100%")) 'white' >>> rgb_percent_to_name(("0%", "0%", "50%")) 'navy' >>> rgb_percent_to_name(("85.49%", "64.71%", "12.5%")) 'goldenrod' :param rgb_percent_triplet: The ``rgb()`` triplet. :param spec: The specification from which to draw the list of color names. Default is :data:`CSS3`. :raises ValueError: when the given color has no name in the given spec. """ return rgb_to_name( rgb_percent_to_rgb( normalization.normalize_percent_triplet(rgb_percent_triplet) ), spec=spec, ) def rgb_percent_to_hex(rgb_percent_triplet: types.PercentTuple) -> str: """ Convert a 3-:class:`tuple` of percentages, suitable for use in an ``rgb()`` color triplet, to a normalized hexadecimal color value for that color. Examples: .. doctest:: >>> rgb_percent_to_hex(("100%", "100%", "0%")) '#ffff00' >>> rgb_percent_to_hex(("0%", "0%", "50%")) '#000080' >>> rgb_percent_to_hex(("85.49%", "64.71%", "12.5%")) '#daa520' :param rgb_percent_triplet: The ``rgb()`` triplet. """ return rgb_to_hex( rgb_percent_to_rgb(normalization.normalize_percent_triplet(rgb_percent_triplet)) ) def rgb_percent_to_rgb( rgb_percent_triplet: types.PercentTuple, ) -> types.IntegerRGB: """ Convert a 3-:class:`tuple` of percentages, suitable for use in an ``rgb()`` color triplet, to a 3-:class:`tuple` of :class:`int` suitable for use in representing that color. Some precision may be lost in this conversion. See the note regarding precision for :func:`~webcolors.rgb_to_rgb_percent` for details. Examples: .. doctest:: >>> rgb_percent_to_rgb(("100%", "100%", "100%")) IntegerRGB(red=255, green=255, blue=255) >>> rgb_percent_to_rgb(("0%", "0%", "50%")) IntegerRGB(red=0, green=0, blue=128) >>> rgb_percent_to_rgb(("85.49%", "64.71%", "12.5%")) IntegerRGB(red=218, green=165, blue=32) :param rgb_percent_triplet: The ``rgb()`` triplet. """ return types.IntegerRGB._make( map( normalization._percent_to_integer, # pylint: disable=protected-access normalization.normalize_percent_triplet(rgb_percent_triplet), ) ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670978403.0 webcolors-1.13/src/webcolors/html5.py0000644000076700000240000002306414346215543016666 0ustar00jamesstaff""" HTML5 color algorithms. Note that these functions are written in a way that may seem strange to developers familiar with Python, because they do not use the most efficient or idiomatic way of accomplishing their tasks. This is because, for compliance, these functions are written as literal translations into Python of the algorithms in HTML5: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#colours For ease of understanding, the relevant steps of the algorithm from the standard are included as comments interspersed in the implementation. """ import string from . import constants, types def html5_parse_simple_color(value: str) -> types.HTML5SimpleColor: """ Apply the HTML5 simple color parsing algorithm. Examples: .. doctest:: >>> html5_parse_simple_color("#ffffff") HTML5SimpleColor(red=255, green=255, blue=255) >>> html5_parse_simple_color("#fff") Traceback (most recent call last): ... ValueError: An HTML5 simple color must be a string seven characters long. :param value: The color to parse. :type value: :class:`str`, which must consist of exactly the character ``"#"`` followed by six hexadecimal digits :raises ValueError: when the given value is not a Unicode string of length 7, consisting of exactly the character ``#`` followed by six hexadecimal digits. """ # 1. Let input be the string being parsed. # # 2. If input is not exactly seven characters long, then return an # error. if not isinstance(value, str) or len(value) != 7: raise ValueError( "An HTML5 simple color must be a Unicode string seven characters long." ) # 3. If the first character in input is not a U+0023 NUMBER SIGN # character (#), then return an error. if not value.startswith("#"): raise ValueError( "An HTML5 simple color must begin with the character '#' (U+0023)." ) # 4. If the last six characters of input are not all ASCII hex # digits, then return an error. if not all(c in string.hexdigits for c in value[1:]): raise ValueError( "An HTML5 simple color must contain exactly six ASCII hex digits." ) # 5. Let result be a simple color. # # 6. Interpret the second and third characters as a hexadecimal # number and let the result be the red component of result. # # 7. Interpret the fourth and fifth characters as a hexadecimal # number and let the result be the green component of result. # # 8. Interpret the sixth and seventh characters as a hexadecimal # number and let the result be the blue component of result. # # 9. Return result. return types.HTML5SimpleColor( int(value[1:3], 16), int(value[3:5], 16), int(value[5:7], 16) ) def html5_serialize_simple_color(simple_color: types.IntTuple) -> str: """ Apply the HTML5 simple color serialization algorithm. Examples: .. doctest:: >>> html5_serialize_simple_color((0, 0, 0)) '#000000' >>> html5_serialize_simple_color((255, 255, 255)) '#ffffff' :param simple_color: The color to serialize. """ red, green, blue = simple_color # 1. Let result be a string consisting of a single "#" (U+0023) # character. result = "#" # 2. Convert the red, green, and blue components in turn to # two-digit hexadecimal numbers using lowercase ASCII hex # digits, zero-padding if necessary, and append these numbers # to result, in the order red, green, blue. format_string = "{:02x}" result += format_string.format(red) result += format_string.format(green) result += format_string.format(blue) # 3. Return result, which will be a valid lowercase simple color. return result def html5_parse_legacy_color(value: str) -> types.HTML5SimpleColor: """ Apply the HTML5 legacy color parsing algorithm. Note that, since this algorithm is intended to handle many types of malformed color values present in real-world Web documents, it is *extremely* forgiving of input, but the results of parsing inputs with high levels of "junk" (i.e., text other than a color value) may be surprising. Examples: .. doctest:: >>> html5_parse_legacy_color("black") HTML5SimpleColor(red=0, green=0, blue=0) >>> html5_parse_legacy_color("chucknorris") HTML5SimpleColor(red=192, green=0, blue=0) >>> html5_parse_legacy_color("Window") HTML5SimpleColor(red=0, green=13, blue=0) :param value: The color to parse. :raises ValueError: when the given value is not a Unicode string, when it is the empty string, or when it is precisely the string ``"transparent"``. """ # 1. Let input be the string being parsed. if not isinstance(value, str): raise ValueError( "HTML5 legacy color parsing requires a Unicode string as input." ) # 2. If input is the empty string, then return an error. if value == "": raise ValueError("HTML5 legacy color parsing forbids empty string as a value.") # 3. Strip leading and trailing whitespace from input. value = value.strip() # 4. If input is an ASCII case-insensitive match for the string # "transparent", then return an error. if value.lower() == "transparent": raise ValueError('HTML5 legacy color parsing forbids "transparent" as a value.') # 5. If input is an ASCII case-insensitive match for one of the # keywords listed in the SVG color keywords section of the CSS3 # Color specification, then return the simple color # corresponding to that keyword. keyword_hex = constants.CSS3_NAMES_TO_HEX.get(value.lower()) if keyword_hex is not None: return html5_parse_simple_color(keyword_hex) # 6. If input is four characters long, and the first character in # input is a "#" (U+0023) character, and the last three # characters of input are all ASCII hex digits, then run these # substeps: if ( len(value) == 4 and value.startswith("#") and all(c in string.hexdigits for c in value[1:]) ): # 1. Let result be a simple color. # # 2. Interpret the second character of input as a hexadecimal # digit; let the red component of result be the resulting # number multiplied by 17. # # 3. Interpret the third character of input as a hexadecimal # digit; let the green component of result be the resulting # number multiplied by 17. # # 4. Interpret the fourth character of input as a hexadecimal # digit; let the blue component of result be the resulting # number multiplied by 17. result = types.HTML5SimpleColor( int(value[1], 16) * 17, int(value[2], 16) * 17, int(value[3], 16) * 17 ) # 5. Return result. return result # 7. Replace any characters in input that have a Unicode code # point greater than U+FFFF (i.e. any characters that are not # in the basic multilingual plane) with the two-character # string "00". value = "".join("00" if ord(c) > 0xFFFF else c for c in value) # 8. If input is longer than 128 characters, truncate input, # leaving only the first 128 characters. if len(value) > 128: value = value[:128] # 9. If the first character in input is a "#" (U+0023) character, # remove it. if value.startswith("#"): value = value[1:] # 10. Replace any character in input that is not an ASCII hex # digit with the character "0" (U+0030). value = "".join(c if c in string.hexdigits else "0" for c in value) # 11. While input's length is zero or not a multiple of three, # append a "0" (U+0030) character to input. while (len(value) == 0) or (len(value) % 3 != 0): value += "0" # 12. Split input into three strings of equal length, to obtain # three components. Let length be the length of those # components (one third the length of input). length = int(len(value) / 3) red = value[:length] green = value[length : length * 2] blue = value[length * 2 :] # 13. If length is greater than 8, then remove the leading # length-8 characters in each component, and let length be 8. if length > 8: red, green, blue = (red[length - 8 :], green[length - 8 :], blue[length - 8 :]) length = 8 # 14. While length is greater than two and the first character in # each component is a "0" (U+0030) character, remove that # character and reduce length by one. while (length > 2) and (red[0] == "0" and green[0] == "0" and blue[0] == "0"): red, green, blue = (red[1:], green[1:], blue[1:]) length -= 1 # 15. If length is still greater than two, truncate each # component, leaving only the first two characters in each. if length > 2: red, green, blue = (red[:2], green[:2], blue[:2]) # 16. Let result be a simple color. # # 17. Interpret the first component as a hexadecimal number; let # the red component of result be the resulting number. # # 18. Interpret the second component as a hexadecimal number; let # the green component of result be the resulting number. # # 19. Interpret the third component as a hexadecimal number; let # the blue component of result be the resulting number. # # 20. Return result. return types.HTML5SimpleColor(int(red, 16), int(green, 16), int(blue, 16)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670309802.0 webcolors-1.13/src/webcolors/normalization.py0000644000076700000240000000763414343563652020534 0ustar00jamesstaff""" Normalization utilities for color values. """ from . import constants, types def normalize_hex(hex_value: str) -> str: """ Normalize a hexadecimal color value to a string consisting of the character `#` followed by six lowercase hexadecimal digits (what HTML5 terms a "valid lowercase simple color"). If the supplied value cannot be interpreted as a hexadecimal color value, :exc:`ValueError` is raised. See :ref:`the conventions used by this module ` for information on acceptable formats for hexadecimal values. Examples: .. doctest:: >>> normalize_hex("#0099cc") '#0099cc' >>> normalize_hex("#0099CC") '#0099cc' >>> normalize_hex("#09c") '#0099cc' >>> normalize_hex("#09C") '#0099cc' >>> normalize_hex("#0099gg") Traceback (most recent call last): ... ValueError: '#0099gg' is not a valid hexadecimal color value. >>> normalize_hex("0099cc") Traceback (most recent call last): ... ValueError: '0099cc' is not a valid hexadecimal color value. :param hex_value: The hexadecimal color value to normalize. :raises ValueError: when the input is not a valid hexadecimal color value. """ match = constants.HEX_COLOR_RE.match(hex_value) if match is None: raise ValueError(f'"{hex_value}" is not a valid hexadecimal color value.') hex_digits = match.group(1) if len(hex_digits) == 3: hex_digits = "".join(2 * s for s in hex_digits) return f"#{hex_digits.lower()}" def _normalize_integer_rgb(value: int) -> int: """ Internal normalization function for clipping integer values into the permitted range (0-255, inclusive). """ return 0 if value < 0 else 255 if value > 255 else value def normalize_integer_triplet( rgb_triplet: types.IntTuple, ) -> types.IntegerRGB: """ Normalize an integer ``rgb()`` triplet so that all values are within the range 0..255. Examples: .. doctest:: >>> normalize_integer_triplet((128, 128, 128)) IntegerRGB(red=128, green=128, blue=128) >>> normalize_integer_triplet((0, 0, 0)) IntegerRGB(red=0, green=0, blue=0) >>> normalize_integer_triplet((255, 255, 255)) IntegerRGB(red=255, green=255, blue=255) >>> normalize_integer_triplet((270, -20, -0)) IntegerRGB(red=255, green=0, blue=0) :param rgb_triplet: The percentage `rgb()` triplet to normalize. """ return types.IntegerRGB._make( _normalize_integer_rgb(value) for value in rgb_triplet ) def _normalize_percent_rgb(value: str) -> str: """ Internal normalization function for clipping percent values into the permitted range (0%-100%, inclusive). """ value = value.split("%")[0] percent = float(value) if "." in value else int(value) return "0%" if percent < 0 else "100%" if percent > 100 else f"{percent}%" def normalize_percent_triplet( rgb_triplet: types.PercentTuple, ) -> types.PercentRGB: """ Normalize a percentage ``rgb()`` triplet so that all values are within the range 0%..100%. Examples: .. doctest:: >>> normalize_percent_triplet(("50%", "50%", "50%")) PercentRGB(red='50%', green='50%', blue='50%') >>> normalize_percent_triplet(("0%", "100%", "0%")) PercentRGB(red='0%', green='100%', blue='0%') >>> normalize_percent_triplet(("-10%", "-0%", "500%")) PercentRGB(red='0%', green='0%', blue='100%') :param rgb_triplet: The percentage `rgb()` triplet to normalize. """ return types.PercentRGB._make( _normalize_percent_rgb(value) for value in rgb_triplet ) def _percent_to_integer(percent: str) -> int: """ Internal helper for converting a percentage value to an integer between 0 and 255 inclusive. """ return int(round(float(percent.split("%")[0]) / 100 * 255)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1668498722.0 webcolors-1.13/src/webcolors/types.py0000644000076700000240000000345514334642442017002 0ustar00jamesstaff""" Types and type aliases used to represent colors in various formats. """ import typing class IntegerRGB(typing.NamedTuple): """ :class:`~typing.NamedTuple` representing an integer RGB triplet. Has three fields, each of type :class:`int` and in the range 0-255 inclusive: .. attribute:: red The red portion of the color value. .. attribute:: green The green portion of the color value. .. attribute:: blue The blue portion of the color value. """ red: int green: int blue: int class PercentRGB(typing.NamedTuple): """ :class:`~typing.NamedTuple` representing a percentage RGB triplet. Has three fields, each of type :class:`str` and representing a percentage value in the range 0%-100% inclusive: .. attribute:: red The red portion of the color value. .. attribute:: green The green portion of the color value. .. attribute:: blue The blue portion of the color value. """ red: str green: str blue: str class HTML5SimpleColor(typing.NamedTuple): """ :class:`~typing.NamedTuple` representing an HTML5 simple color. Has three fields, each of type :class:`int` and in the range 0-255 inclusive: .. attribute:: red The red portion of the color value. .. attribute:: green The green portion of the color value. .. attribute:: blue The blue portion of the color value. """ red: int green: int blue: int # Union type representing the possible types of an integer RGB tuple. IntTuple = typing.Union[IntegerRGB, HTML5SimpleColor, typing.Tuple[int, int, int]] # Union type representing the possible types of a percentage RGB tuple. PercentTuple = typing.Union[PercentRGB, typing.Tuple[str, str, str]] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1679896362.6562123 webcolors-1.13/src/webcolors.egg-info/0000755000076700000240000000000014410227453016743 5ustar00jamesstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1679896362.0 webcolors-1.13/src/webcolors.egg-info/PKG-INFO0000644000076700000240000000431614410227452020043 0ustar00jamesstaffMetadata-Version: 2.1 Name: webcolors Version: 1.13 Summary: A library for working with the color formats defined by HTML and CSS. Author-email: James Bennett License: BSD-3-Clause Project-URL: documentation, https://webcolors.readthedocs.io Project-URL: homepage, https://github.com/ubernostrum/webcolors Keywords: color,css,html,web Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Topic :: Utilities Requires-Python: >=3.7 Description-Content-Type: text/x-rst Provides-Extra: docs Provides-Extra: tests License-File: LICENSE .. -*-restructuredtext-*- .. image:: https://github.com/ubernostrum/webcolors/workflows/CI/badge.svg :alt: CI status image :target: https://github.com/ubernostrum/webcolors/actions?query=workflow%3ACI ``webcolors`` is a module for working with HTML/CSS color definitions. Support is included for normalizing and converting between the following formats (RGB colorspace only; conversion to/from HSL can be handled by the ``colorsys`` module in the Python standard library): * Specification-defined color names * Six-digit hexadecimal * Three-digit hexadecimal * Integer ``rgb()`` triplet * Percentage ``rgb()`` triplet For example: .. code-block:: python >>> import webcolors >>> webcolors.hex_to_name("#daa520") 'goldenrod' Implementations are also provided for the HTML5 color parsing and serialization algorithms. For example, parsing the infamous "chucknorris" string into an rgb() triplet: .. code-block:: python >>> import webcolors >>> webcolors.html5_parse_legacy_color("chucknorris") HTML5SimpleColor(red=192, green=0, blue=0) Full documentation is `available online `_. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1679896362.0 webcolors-1.13/src/webcolors.egg-info/SOURCES.txt0000644000076700000240000000147514410227452020635 0ustar00jamesstaff.editorconfig .flake8 .pre-commit-config.yaml .readthedocs.yaml LICENSE MANIFEST.in README.rst noxfile.py pyproject.toml docs/Makefile docs/changelog.rst docs/colors.rst docs/conf.py docs/conformance.rst docs/contents.rst docs/conventions.rst docs/faq.rst docs/index.rst docs/install.rst docs/make.bat docs/spelling_wordlist.txt src/webcolors/__init__.py src/webcolors/constants.py src/webcolors/conversion.py src/webcolors/html5.py src/webcolors/normalization.py src/webcolors/types.py src/webcolors.egg-info/PKG-INFO src/webcolors.egg-info/SOURCES.txt src/webcolors.egg-info/dependency_links.txt src/webcolors.egg-info/requires.txt src/webcolors.egg-info/top_level.txt tests/__init__.py tests/definitions.py tests/full_colors.py tests/test_conformance.py tests/test_conversion.py tests/test_html5.py tests/test_normalization.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1679896362.0 webcolors-1.13/src/webcolors.egg-info/dependency_links.txt0000644000076700000240000000000114410227452023010 0ustar00jamesstaff ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1679896362.0 webcolors-1.13/src/webcolors.egg-info/requires.txt0000644000076700000240000000017514410227452021345 0ustar00jamesstaff [docs] furo sphinx sphinx-copybutton sphinx-inline-tabs sphinx-notfound-page sphinxext-opengraph [tests] pytest pytest-cov ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1679896362.0 webcolors-1.13/src/webcolors.egg-info/top_level.txt0000644000076700000240000000001214410227452021465 0ustar00jamesstaffwebcolors ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1679896362.662314 webcolors-1.13/tests/0000755000076700000240000000000014410227453013625 5ustar00jamesstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1399112166.0 webcolors-1.13/tests/__init__.py0000644000076700000240000000000012331140746015723 0ustar00jamesstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1671433456.0 webcolors-1.13/tests/definitions.py0000644000076700000240000001137214350006360016511 0ustar00jamesstaff""" Test accuracy of the mappings of color names and values, by extracting the definitions of the colors from the relevant standards documents. """ import re import unittest import html5lib # noqa: F401 pylint: disable=unused-import import requests from bs4 import BeautifulSoup import webcolors class HTML4DefinitionTests(unittest.TestCase): """ Extract the names and values of the 16 defined HTML 4 colors from the online version of the standard, and check them against this module's definitions of them. """ def setUp(self): """ Fetch the HTML 4 color definitions and store them on self.html4_colors. """ self.html4_colors = {} soup = BeautifulSoup( requests.get("http://www.w3.org/TR/html401/types.html", timeout=5).content, "html.parser", ) color_table = soup.find( "table", attrs={"summary": "Table of color names and their sRGB values"} ) for cell in color_table.findAll("td"): if "width" not in cell.attrs: color_name, color_value = cell.text.split(" = ") self.html4_colors[color_name] = color_value.replace('"', "").strip() def test_color_definitions(self): """ Ensure the values in this module match those in the HTML 4 specification. """ for color_name, color_value in self.html4_colors.items(): extracted = webcolors.HTML4_NAMES_TO_HEX[color_name.lower()] assert color_value.lower() == extracted class CSS21DefinitionTests(unittest.TestCase): """ Extract the names and values of the 17 defined CSS 2.1 colors from the online version of the standard, and check them against this module's definitions of them. """ def setUp(self): """ Fetch the CSS2.1 color definitions and store them on self.css21_colors. """ self.color_matching_re = re.compile(r"^([a-z]+) (#[a-fA-F0-9]{6})$") self.css21_colors = {} soup = BeautifulSoup( requests.get("http://www.w3.org/TR/CSS2/syndata.html", timeout=5).content, "html.parser", ) color_table = soup.find("div", attrs={"id": "TanteksColorDiagram20020613"}) for color_square in color_table.findAll("span", attrs={"class": "colorsquare"}): color_name, color_value = self.color_matching_re.search( color_square.text ).groups() self.css21_colors[color_name] = color_value def test_color_definitions(self): """ Ensure thie values in this module match those in the CSS2.1 specification. """ for color_name, color_value in self.css21_colors.items(): extracted = webcolors.CSS21_NAMES_TO_HEX[color_name.lower()] assert color_value.lower() == extracted class CSS3DefinitionTests(unittest.TestCase): """ Extract the names and values of the 147 defined CSS 3 colors from the online version of the standard, and check them against this module's definitions of them. """ def setUp(self): """ Fetch the CSS3 color definitions and store them on self.css3_colors. """ self.css3_colors = {} soup = BeautifulSoup( requests.get("http://www.w3.org/TR/css3-color/", timeout=5).content, "html5lib", ) color_table = soup.findAll("table", attrs={"class": "colortable"})[1] color_names = [dfn.text for dfn in color_table.findAll("dfn")] hex_values = [ td.text.strip() for td in color_table.findAll( "td", attrs={"class": "c", "style": "background:silver"} ) if td.text.startswith("#") ] rgb_values = [ td.text.strip() for td in color_table.findAll( "td", attrs={"class": "c", "style": "background:silver"} ) if not td.text.startswith("#") and not td.text.startswith("&") and td.text.strip() ] for i, color_name in enumerate(color_names): self.css3_colors[color_name] = { "hex": hex_values[i], "rgb": tuple(map(int, rgb_values[i].split(","))), } def test_color_definitions(self): """ Ensure the values in this module match those in the CSS3 specification. """ for color_name, color_values in self.css3_colors.items(): extracted_hex = webcolors.CSS3_NAMES_TO_HEX[color_name.lower()] extracted_rgb = webcolors.name_to_rgb(color_name) assert color_values["hex"].lower() == extracted_hex assert color_values["rgb"] == extracted_rgb if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670468924.0 webcolors-1.13/tests/full_colors.py0000644000076700000240000000560514344252474016537 0ustar00jamesstaff""" Test case which exercises webcolors' conversion functions across all 16,777,216 possible hexadecimal values and all 16,777,216 possible integer rgb() triplet values. You should not ever need to run this test; it is not part of the normal unit-test suite, and is used only as a final check when preparing a new release of webcolors. Because it generates each of the nearly 17 million color values multiple times, this test case takes some time to run and consumes most or all available CPU while running. As a consolation, it is somewhat efficient with respect to memory. Due to the inherent imprecision of floating-point percentage values, and the fact that the legal (with respect to the CSS standards) set of percentage rgb() triplets is uncountably infinite, percentage rgb() triplets are not exhaustively tested here, and the normal test suite is used to ensure correctness of the conversion functions for those values. The only test performed here for percentage rgb() triplets is to ensure that converting an integer rgb() triplet to percentage and back returns the original integer values, for consistency. """ import unittest import webcolors def hex_colors(): """ Generator which yields all 2**24 hexadecimal color values, in order starting from #000000. """ for i in range(16777217): yield f"#{i:06x}" def int_colors(): """ Generator which yields all 2**24 integer rgb() triplets, in order starting from (0,0,0). """ red_counter = tuple(range(256)) green_counter = tuple(range(256)) blue_counter = tuple(range(256)) for red_value in red_counter: for green_value in green_counter: for blue_value in blue_counter: yield (red_value, green_value, blue_value) class FullColorTest(unittest.TestCase): """ Exercise color conversion on all testable values. """ def test_full_colors(self): """ Test conversion between hexadecimal and integer rgb() for all 2**24 possible values. """ for hex_color, int_triplet in zip(hex_colors(), int_colors()): assert int_triplet == webcolors.hex_to_rgb(hex_color) assert hex_color == webcolors.rgb_to_hex(int_triplet) def test_triplet_conversion(self): """ Test conversion between integer and percentage rgb() as fully as possible. Because exhaustive testing is not possible (the set of valid percentgae rgb() triplets is uncountably infinite), this test ensures that for each of the 2**24 possible integer triplets, conversion to percentage and back gives the starting value. """ for int_triplet in int_colors(): conversion = webcolors.rgb_percent_to_rgb( webcolors.rgb_to_rgb_percent(int_triplet) ) assert int_triplet == conversion if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1668327479.0 webcolors-1.13/tests/test_conformance.py0000644000076700000240000001621414334124067017536 0ustar00jamesstaff""" Conformance tests which do not require an internet connection or HTML parsing libraries, and so can be run as part of the normal test suite of webcolors. For tests which extract the relevant values, during the test run, from the online standards documents (and so require both an internet connection and an HTML parsing library), see the file ``definitions.py`` in this directory. """ import unittest import webcolors # The mappings of color names to values below are used for conformance # testing; while the main webcolors module makes use of alphabetized, # normalized mappings to hex values, the mappings below are the # definitions in precisely the form they take in the relevant # standards documents (they were produced via automated extraction # from the HTML of those documents, to avoid the possibility of human # copy/paste error). # # Sources are: # # HTML 4 colors: http://www.w3.org/TR/html401/types.html#h-6.5 # # SVG colors (which CSS 3 adopted): # http://www.w3.org/TR/SVG/types.html#ColorKeywords # # Conformance of this module with the relevant standards is proven by # comparing its output to these mappings. HTML4_COLOR_DEFINITIONS = { "Black": "#000000", "Silver": "#C0C0C0", "Gray": "#808080", "White": "#FFFFFF", "Maroon": "#800000", "Red": "#FF0000", "Purple": "#800080", "Fuchsia": "#FF00FF", "Green": "#008000", "Lime": "#00FF00", "Olive": "#808000", "Yellow": "#FFFF00", "Navy": "#000080", "Blue": "#0000FF", "Teal": "#008080", "Aqua": "#00FFFF", } SVG_COLOR_DEFINITIONS = { "aliceblue": (240, 248, 255), "antiquewhite": (250, 235, 215), "aqua": (0, 255, 255), "aquamarine": (127, 255, 212), "azure": (240, 255, 255), "beige": (245, 245, 220), "bisque": (255, 228, 196), "black": (0, 0, 0), "blanchedalmond": (255, 235, 205), "blue": (0, 0, 255), "blueviolet": (138, 43, 226), "brown": (165, 42, 42), "burlywood": (222, 184, 135), "cadetblue": (95, 158, 160), "chartreuse": (127, 255, 0), "chocolate": (210, 105, 30), "coral": (255, 127, 80), "cornflowerblue": (100, 149, 237), "cornsilk": (255, 248, 220), "crimson": (220, 20, 60), "cyan": (0, 255, 255), "darkblue": (0, 0, 139), "darkcyan": (0, 139, 139), "darkgoldenrod": (184, 134, 11), "darkgray": (169, 169, 169), "darkgreen": (0, 100, 0), "darkgrey": (169, 169, 169), "darkkhaki": (189, 183, 107), "darkmagenta": (139, 0, 139), "darkolivegreen": (85, 107, 47), "darkorange": (255, 140, 0), "darkorchid": (153, 50, 204), "darkred": (139, 0, 0), "darksalmon": (233, 150, 122), "darkseagreen": (143, 188, 143), "darkslateblue": (72, 61, 139), "darkslategray": (47, 79, 79), "darkslategrey": (47, 79, 79), "darkturquoise": (0, 206, 209), "darkviolet": (148, 0, 211), "deeppink": (255, 20, 147), "deepskyblue": (0, 191, 255), "dimgray": (105, 105, 105), "dimgrey": (105, 105, 105), "dodgerblue": (30, 144, 255), "firebrick": (178, 34, 34), "floralwhite": (255, 250, 240), "forestgreen": (34, 139, 34), "fuchsia": (255, 0, 255), "gainsboro": (220, 220, 220), "ghostwhite": (248, 248, 255), "gold": (255, 215, 0), "goldenrod": (218, 165, 32), "gray": (128, 128, 128), "grey": (128, 128, 128), "green": (0, 128, 0), "greenyellow": (173, 255, 47), "honeydew": (240, 255, 240), "hotpink": (255, 105, 180), "indianred": (205, 92, 92), "indigo": (75, 0, 130), "ivory": (255, 255, 240), "khaki": (240, 230, 140), "lavender": (230, 230, 250), "lavenderblush": (255, 240, 245), "lawngreen": (124, 252, 0), "lemonchiffon": (255, 250, 205), "lightblue": (173, 216, 230), "lightcoral": (240, 128, 128), "lightcyan": (224, 255, 255), "lightgoldenrodyellow": (250, 250, 210), "lightgray": (211, 211, 211), "lightgreen": (144, 238, 144), "lightgrey": (211, 211, 211), "lightpink": (255, 182, 193), "lightsalmon": (255, 160, 122), "lightseagreen": (32, 178, 170), "lightskyblue": (135, 206, 250), "lightslategray": (119, 136, 153), "lightslategrey": (119, 136, 153), "lightsteelblue": (176, 196, 222), "lightyellow": (255, 255, 224), "lime": (0, 255, 0), "limegreen": (50, 205, 50), "linen": (250, 240, 230), "magenta": (255, 0, 255), "maroon": (128, 0, 0), "mediumaquamarine": (102, 205, 170), "mediumblue": (0, 0, 205), "mediumorchid": (186, 85, 211), "mediumpurple": (147, 112, 219), "mediumseagreen": (60, 179, 113), "mediumslateblue": (123, 104, 238), "mediumspringgreen": (0, 250, 154), "mediumturquoise": (72, 209, 204), "mediumvioletred": (199, 21, 133), "midnightblue": (25, 25, 112), "mintcream": (245, 255, 250), "mistyrose": (255, 228, 225), "moccasin": (255, 228, 181), "navajowhite": (255, 222, 173), "navy": (0, 0, 128), "oldlace": (253, 245, 230), "olive": (128, 128, 0), "olivedrab": (107, 142, 35), "orange": (255, 165, 0), "orangered": (255, 69, 0), "orchid": (218, 112, 214), "palegoldenrod": (238, 232, 170), "palegreen": (152, 251, 152), "paleturquoise": (175, 238, 238), "palevioletred": (219, 112, 147), "papayawhip": (255, 239, 213), "peachpuff": (255, 218, 185), "peru": (205, 133, 63), "pink": (255, 192, 203), "plum": (221, 160, 221), "powderblue": (176, 224, 230), "purple": (128, 0, 128), "red": (255, 0, 0), "rosybrown": (188, 143, 143), "royalblue": (65, 105, 225), "saddlebrown": (139, 69, 19), "salmon": (250, 128, 114), "sandybrown": (244, 164, 96), "seagreen": (46, 139, 87), "seashell": (255, 245, 238), "sienna": (160, 82, 45), "silver": (192, 192, 192), "skyblue": (135, 206, 235), "slateblue": (106, 90, 205), "slategray": (112, 128, 144), "slategrey": (112, 128, 144), "snow": (255, 250, 250), "springgreen": (0, 255, 127), "steelblue": (70, 130, 180), "tan": (210, 180, 140), "teal": (0, 128, 128), "thistle": (216, 191, 216), "tomato": (255, 99, 71), "turquoise": (64, 224, 208), "violet": (238, 130, 238), "wheat": (245, 222, 179), "white": (255, 255, 255), "whitesmoke": (245, 245, 245), "yellow": (255, 255, 0), "yellowgreen": (154, 205, 50), } class ConformanceTests(unittest.TestCase): """ Demonstrate that this module conforms to the relevant standards documents governing colors on the Web. """ def test_html_definition_conformance(self): """ Compare the results of name-to-hex conversion to the canonical hex values provided in the HTML 4 specification. """ for color, hex_value in HTML4_COLOR_DEFINITIONS.items(): normalized = webcolors.normalize_hex(hex_value) assert normalized == webcolors.name_to_hex(color) def test_svg_definition_conformance(self): """ Compare the results of name-to-rgb-triplet conversion to the canonical triplet values provided in the SVG specification. """ for color, triplet in SVG_COLOR_DEFINITIONS.items(): assert triplet == webcolors.name_to_rgb(color) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1668498722.0 webcolors-1.13/tests/test_conversion.py0000644000076700000240000003100014334642442017421 0ustar00jamesstaff""" Test the color-format conversion utilities. """ import unittest import webcolors class HexConversionTests(unittest.TestCase): """ Test the functions which convert from hex color codes to other formats. """ def test_hex_to_name(self): """ Test conversion from hex to color name. """ test_pairs = ( ("#ffffff", "white"), ("#fff", "white"), ("#000080", "navy"), ("#daa520", "goldenrod"), ) for hex_value, name in test_pairs: assert name == webcolors.hex_to_name(hex_value) def test_hex_to_name_unnamed(self): """ A hex code which does not correspond to a named color, or does not correspond to a named color in the given specification, raises ValueError. """ # No name in any spec. self.assertRaises(ValueError, webcolors.hex_to_name, "#123456") # This is 'goldenrod' in CSS 3 list, unnamed in HTML 4. self.assertRaises( ValueError, webcolors.hex_to_name, "#daa520", spec=webcolors.HTML4 ) def test_hex_to_name_specs(self): """ Using one of the supported specifications succeeds; using an unsupported specification raises ValueError. """ for supported_spec in webcolors.constants.SUPPORTED_SPECIFICATIONS: result = webcolors.hex_to_name("#ffffff", spec=supported_spec) assert "white" == result for unsupported_spec in ("css1", "css4", "html5"): self.assertRaises( ValueError, webcolors.hex_to_name, "#ffffff", spec=unsupported_spec ) def test_hex_to_rgb(self): """ Test conversion from hex to integer RGB triplet. """ test_pairs = ( ("#fff", (255, 255, 255)), ("#ffffff", (255, 255, 255)), ("#000080", (0, 0, 128)), ) for hex_value, triplet in test_pairs: result = webcolors.hex_to_rgb(hex_value) assert isinstance(result, webcolors.IntegerRGB) assert triplet == result def test_hex_to_rgb_percent(self): """ Test conversion from hex to percent RGB triplet. """ test_pairs = ( ("#fff", ("100%", "100%", "100%")), ("#ffffff", ("100%", "100%", "100%")), ("#000080", ("0%", "0%", "50%")), ) for hex_value, triplet in test_pairs: result = webcolors.hex_to_rgb_percent(hex_value) assert isinstance(result, webcolors.PercentRGB) assert triplet == result class IntegerRGBConversionTests(unittest.TestCase): """ Test the functions which convert from integer RGB triplets to other formats. """ def test_rgb_to_name(self): """ Test conversion from integer RGB triplet to color name. """ test_pairs = ( ((255, 255, 255), "white"), ((0, 0, 128), "navy"), ((218, 165, 32), "goldenrod"), (webcolors.IntegerRGB(218, 165, 32), "goldenrod"), ) for triplet, name in test_pairs: assert name == webcolors.rgb_to_name(triplet) def test_rgb_to_name_unnamed(self): """ An integer RGB triplet which does not correspond to a named color, or does not correspond to a named color in the given specification, raises ValueError. """ # No name in any spec. self.assertRaises(ValueError, webcolors.rgb_to_name, (18, 52, 86)) # This is 'goldenrod' in CSS 3 list, unnamed in HTML 4. self.assertRaises( ValueError, webcolors.rgb_to_name, (218, 165, 32), spec=webcolors.HTML4 ) def test_rgb_to_name_specs(self): """ Using one of the supported specifications succeeds; an unsupported specification raises ValueError. """ for supported_spec in webcolors.constants.SUPPORTED_SPECIFICATIONS: result = webcolors.rgb_to_name((255, 255, 255), spec=supported_spec) assert "white" == result for unsupported_spec in ("css1", "css4", "html5"): self.assertRaises( ValueError, webcolors.rgb_to_name, (255, 255, 255), spec=unsupported_spec, ) def test_rgb_to_hex(self): """ Test conversion from integer RGB triplet to hex. """ test_pairs = ( ((255, 255, 255), "#ffffff"), ((0, 0, 128), "#000080"), ((218, 165, 32), "#daa520"), ) for triplet, hex_value in test_pairs: assert hex_value == webcolors.rgb_to_hex(triplet) def test_rgb_to_rgb_percent(self): """ Test conversion from integer RGB triplet to percent RGB triplet. """ test_pairs = ( ((255, 255, 255), ("100%", "100%", "100%")), ((0, 0, 128), ("0%", "0%", "50%")), ((218, 165, 32), ("85.49%", "64.71%", "12.5%")), ) for triplet, percent_triplet in test_pairs: result = webcolors.rgb_to_rgb_percent(triplet) assert isinstance(result, webcolors.PercentRGB) assert percent_triplet == result class NameConversionTests(unittest.TestCase): """ Test the functions which convert from color names to other formats. """ def test_name_to_hex(self): """ Test correct conversion of color names to hex. """ test_pairs = ( ("white", "#ffffff"), ("navy", "#000080"), ("goldenrod", "#daa520"), ) for name, hex_value in test_pairs: assert hex_value == webcolors.name_to_hex(name) def test_name_to_hex_bad_name(self): """ A name which does not correspond to a color, or does not correspond to a color in the given specification, raises ValueError. """ test_values = ( {"name": "goldenrod", "spec": "html4"}, {"name": "glue", "spec": "css21"}, {"name": "breen", "spec": "css3"}, ) for kwarg_dict in test_values: self.assertRaises(ValueError, webcolors.name_to_hex, **kwarg_dict) def test_name_to_hex_specs(self): """ Using one of the supported specifications succeeds; using an unsupported specification raises ValueError. """ for supported_spec in webcolors.constants.SUPPORTED_SPECIFICATIONS: result = webcolors.name_to_hex("white", spec=supported_spec) assert "#ffffff" == result for unsupported_spec in ("css1", "css4", "html5"): self.assertRaises( ValueError, webcolors.name_to_hex, "white", spec=unsupported_spec ) def test_name_to_rgb(self): """ Test conversion from color name to integer RGB triplet. """ test_pairs = ( ("white", (255, 255, 255)), ("navy", (0, 0, 128)), ("goldenrod", (218, 165, 32)), ) for name, triplet in test_pairs: result = webcolors.name_to_rgb(name) assert isinstance(result, webcolors.IntegerRGB) assert triplet == result def test_name_to_rgb_percent(self): """ Test conversion from color name to percent RGB triplet. """ test_pairs = ( ("white", ("100%", "100%", "100%")), ("navy", ("0%", "0%", "50%")), ("goldenrod", ("85.49%", "64.71%", "12.5%")), ) for name, triplet in test_pairs: result = webcolors.name_to_rgb_percent(name) assert isinstance(result, webcolors.PercentRGB) assert triplet == result class PercentRGBConversionTests(unittest.TestCase): """ Test the functions which convert from percent RGB triplets to other formats. """ def test_rgb_percent_to_name(self): """ Test conversion from percent RGB triplet to color name. """ test_pairs = ( (("100%", "100%", "100%"), "white"), (("0%", "0%", "50%"), "navy"), (("85.49%", "64.71%", "12.5%"), "goldenrod"), (webcolors.PercentRGB("85.49%", "64.71%", "12.5%"), "goldenrod"), ) for triplet, name in test_pairs: assert name == webcolors.rgb_percent_to_name(triplet) def test_rgb_percent_to_name_unnamed(self): """ A percent RGB triplet which does not correspond to a named color, or does not correspond to a named color in the given specification, raises ValueError. """ # No name in any spec. self.assertRaises( ValueError, webcolors.rgb_percent_to_name, ("7.06%", "20.39%", "33.73%") ) # This is 'goldenrod' in CSS 3 list, unnamed in HTML 4. self.assertRaises( ValueError, webcolors.rgb_percent_to_name, ("85.49%", "64.71%", "12.5%"), spec=webcolors.HTML4, ) def test_rgb_percent_to_name_specs(self): """ Using one of the supported specifications succeeds; an unsupported specification raises ValueError. """ for supported_spec in ("html4", "css2", "css21", "css3"): result = webcolors.rgb_percent_to_name( ("100%", "100%", "100%"), spec=supported_spec ) assert "white" == result for unsupported_spec in ("css1", "css4", "html5"): self.assertRaises( ValueError, webcolors.rgb_percent_to_name, ("100%", "100%", "100%"), spec=unsupported_spec, ) def test_rgb_percent_to_hex(self): """ Test conversion from percent RGB triplet to hex. """ test_pairs = ( (("100%", "100%", "0%"), "#ffff00"), (("0%", "0%", "50%"), "#000080"), (("85.49%", "64.71%", "12.5%"), "#daa520"), ) for triplet, hex_value in test_pairs: assert hex_value == webcolors.rgb_percent_to_hex(triplet) def test_rgb_percent_to_rgb(self): """ Test conversion from percent RGB triplet to integer RGB triplet. """ test_pairs = ( (("100%", "100%", "0%"), (255, 255, 0)), (("0%", "0%", "50%"), (0, 0, 128)), (("85.49%", "64.71%", "12.5%"), (218, 165, 32)), ) for triplet, int_triplet in test_pairs: result = webcolors.rgb_percent_to_rgb(triplet) assert isinstance(result, webcolors.IntegerRGB) assert int_triplet == result class ConversionTests(unittest.TestCase): """ Test other aspects of convevrsion not covered by format-specific test cases. """ def test_spelling_variants(self): """ When asked to name a color value that maps to either of 'gray' or 'grey' in CSS3, or a related color like 'darkgray'/'darkgrey', webcolors always picks 'gray' as the spelling. """ test_values = ( ( "#a9a9a9", (169, 169, 169), ("66.27%", "66.27%", "66.27%"), "darkgray", ), ( "#2f4f4f", (47, 79, 79), ("18.43%", "30.98%", "30.98%"), "darkslategray", ), ( "#696969", (105, 105, 105), ("41.18%", "41.18%", "41.18%"), "dimgray", ), ("#808080", (128, 128, 128), ("50%", "50%", "50%"), "gray"), ( "#d3d3d3", (211, 211, 211), ("82.75%", "82.75%", "82.75%"), "lightgray", ), ( "#d3d3d3", (211, 211, 211), ("82.75%", "82.75%", "82.75%"), "lightgray", ), ( "#778899", (119, 136, 153), ("46.67%", "53.33%", "60.00%"), "lightslategray", ), ("#708090", (112, 128, 144), ("43.92%", "50%", "56.47%"), "slategray"), ) for hex_value, int_tuple, percent_tuple, name in test_values: for converter, value in ( (webcolors.hex_to_name, hex_value), (webcolors.rgb_to_name, int_tuple), (webcolors.rgb_percent_to_name, percent_tuple), ): assert name == converter(value, spec=webcolors.CSS3) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1668498722.0 webcolors-1.13/tests/test_html5.py0000644000076700000240000000701714334642442016300 0ustar00jamesstaff""" Tests for the HTML5 color algorithms. """ import unittest import webcolors class HTML5Tests(unittest.TestCase): """ Test the functions which implement the HTML5 color algorithms. """ def test_parse_simple_color(self): """ Test implementation of the HTML5 simple color parsing algorithm. """ test_pairs = ( ("#ffffff", (255, 255, 255)), ("#000080", (0, 0, 128)), ("#daa520", (218, 165, 32)), ) for raw, parsed in test_pairs: result = webcolors.html5_parse_simple_color(raw) assert isinstance(result, webcolors.HTML5SimpleColor) assert parsed == result def test_parse_simple_color_error(self): """ Test error conditions of the HTML5 simple color parsing algorithm. """ test_values = ( "0099ccc", "#09c", "#0000", "#0000000", "#0000gg", "#000000".encode("ascii"), ) for value in test_values: self.assertRaises(ValueError, webcolors.html5_parse_simple_color, value) def test_serialize_simple_color(self): """ Test implementation of the HTML5 simple color serialization algorithm. """ test_pairs = ( ((0, 0, 0), "#000000"), ((0, 0, 128), "#000080"), ((218, 165, 32), "#daa520"), (webcolors.IntegerRGB(218, 165, 32), "#daa520"), (webcolors.HTML5SimpleColor(218, 165, 32), "#daa520"), ) for raw, serialized in test_pairs: result = webcolors.html5_serialize_simple_color(raw) assert serialized == result def test_parse_legacy_color(self): """ Test implementation of the HTML5 legacy color parsing algorithm. """ # One of these is the famous "chucknorris" value. Another is a # CSS 2 system color. The final two are randomly-generated but # believable junk strings. Correct output values obtained # manually. test_pairs = ( ("chucknorris", (192, 0, 0)), ("Window", (0, 13, 0)), ("RE|SXLuAse", (224, 0, 224)), ("+=@FnnWL!Yb}5Dk", (0, 0, 176)), ("A" * 129, (170, 170, 170)), ) for raw, parsed in test_pairs: result = webcolors.html5_parse_legacy_color(raw) assert isinstance(result, webcolors.HTML5SimpleColor) assert parsed == result def test_parse_legacy_color_names(self): """ Test the HTML5 legacy color parsing of SVG/CSS3 color names. """ for name in webcolors.CSS3_NAMES_TO_HEX: parsed = webcolors.html5_parse_legacy_color(name) assert parsed == webcolors.name_to_rgb(name) def test_parse_legacy_color_hex(self): """ Test the HTML5 legacy color parsing of three- and six-digit hexadecimal color values. """ test_values = ("#000", "#000000", "#fff", "#ffffff", "#000080") for value in test_values: parsed = webcolors.html5_parse_legacy_color(value) assert parsed == webcolors.hex_to_rgb(value) def test_parse_legacy_color_error(self): """ Test error conditions of the HTML5 legacy color parsing algorithm. """ test_values = ("#000000".encode("ascii"), "transparent", "") for value in test_values: self.assertRaises(ValueError, webcolors.html5_parse_legacy_color, value) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1668498722.0 webcolors-1.13/tests/test_normalization.py0000644000076700000240000000603214334642442020131 0ustar00jamesstaff""" Test the color-value normalization functions. """ import unittest import webcolors class NormalizationTests(unittest.TestCase): """ Test both the publicly-exposed and internal normalization functions. """ def test_normalize_hex(self): """ Hexadecimal normalization normalizes valid hex color codes to 6 digits, lowercase. """ test_pairs = ( ("#0099cc", "#0099cc"), ("#0099CC", "#0099cc"), ("#09c", "#0099cc"), ("#09C", "#0099cc"), ) for raw, normalized in test_pairs: assert normalized == webcolors.normalize_hex(raw) def test_normalize_hex_format(self): """ Hex normalization raises ValueError on invalid hex color code. """ test_values = ("0099cc", "#0000gg", "#0000", "#00000000") for value in test_values: self.assertRaises(ValueError, webcolors.normalize_hex, value) def test_normalize_integer_rgb(self): """ Integer normalization clips to 0-255. """ # pylint: disable=protected-access test_pairs = ((255, 255), (0, 0), (128, 128), (-20, 0), (270, 255), (-0, 0)) for raw, normalized in test_pairs: assert normalized == webcolors.normalization._normalize_integer_rgb(raw) def test_normalize_integer_triplet(self): """ Integer triplet normalization clips all values to 0-255. """ test_pairs = ( ((128, 128, 128), (128, 128, 128)), ((0, 0, 0), (0, 0, 0)), ((255, 255, 255), (255, 255, 255)), ((270, -20, 128), (255, 0, 128)), ((-0, -0, -0), (0, 0, 0)), ) for triplet, normalized in test_pairs: result = webcolors.normalize_integer_triplet(triplet) assert isinstance(result, webcolors.IntegerRGB) assert normalized == result def test_normalize_percent_rgb(self): """ Percent normalization clips to 0%-100%. """ # pylint: disable=protected-access test_pairs = ( ("0%", "0%"), ("100%", "100%"), ("62%", "62%"), ("-5%", "0%"), ("250%", "100%"), ("85.49%", "85.49%"), ("-0%", "0%"), ) for raw, normalized in test_pairs: assert normalized == webcolors.normalization._normalize_percent_rgb(raw) def test_normalize_percent_triplet(self): """ Percent triplet normalization clips all values to 0%-100%. """ test_pairs = ( (("50%", "50%", "50%"), ("50%", "50%", "50%")), (("0%", "100%", "0%"), ("0%", "100%", "0%")), (("-10%", "250%", "500%"), ("0%", "100%", "100%")), (("-0%", "-0%", "-0%"), ("0%", "0%", "0%")), ) for triplet, normalized in test_pairs: result = webcolors.normalize_percent_triplet(triplet) assert isinstance(result, webcolors.PercentRGB) assert normalized == result