Skip to content

Commit dee9d46

Browse files
committed
Add first draft of names() function (refs #20).
1 parent bb87686 commit dee9d46

8 files changed

+117
-4
lines changed

.pre-commit-config.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ repos:
1616
- id: end-of-file-fixer
1717
- id: trailing-whitespace
1818
- repo: https://github.com/psf/black
19-
rev: 24.4.2
19+
rev: 24.8.0
2020
hooks:
2121
- id: black
2222
language_version: python3.8
2323
name: black (Python formatter)
2424
- repo: https://github.com/pycqa/flake8
25-
rev: 7.0.0
25+
rev: 7.1.1
2626
hooks:
2727
- id: flake8
2828
name: flake8 (Python linter)

docs/changelog.rst

+11
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ The API stability/deprecation policy for this library is as follows:
5656
Releases under CalVer
5757
---------------------
5858

59+
Version 24.8.0
60+
~~~~~~~~~~~~~~
61+
62+
*Under development*
63+
64+
* Added the :func:`~webcolors.names` function to allow retrieving lists of
65+
color names. The underlying mappings of color names/values still are not
66+
supported API; to obtain the color value corresponding to a name, use the
67+
appropriate conversion function.
68+
69+
5970
Version 24.6.0
6071
~~~~~~~~~~~~~~
6172

docs/conf.py

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
"""
77

8+
import doctest
89
import sys
910
from importlib.metadata import version as get_version
1011

@@ -50,6 +51,12 @@
5051

5152
# Doctest configuration.
5253
doctest_global_setup = "from webcolors import *"
54+
doctest_default_flags = (
55+
doctest.DONT_ACCEPT_TRUE_FOR_1
56+
| doctest.ELLIPSIS
57+
| doctest.IGNORE_EXCEPTION_DETAIL
58+
| doctest.NORMALIZE_WHITESPACE
59+
)
5360

5461
# OGP metadata configuration.
5562
ogp_enable_meta_description = True

docs/contents.rst

+6
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ specifications.
9393
Represents the HTML 4 specification. Value is ``"html4"``.
9494

9595

96+
Informative functions
97+
---------------------
98+
99+
.. autofunction:: names
100+
101+
96102
Normalization functions
97103
-----------------------
98104

noxfile.py

+23
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,29 @@ def docs_spellcheck(session: nox.Session) -> None:
185185
clean()
186186

187187

188+
@nox.session(python=["3.11"], tags=["docs", "tests"])
189+
def docs_test(session: nox.Session) -> None:
190+
"""
191+
Run the code samples in the documentation with doctest, to ensure they are
192+
correct.
193+
194+
"""
195+
session.install(".[docs]")
196+
session.run(
197+
f"python{session.python}",
198+
"-Im",
199+
"sphinx",
200+
"-c",
201+
"docs/",
202+
"-b",
203+
"doctest",
204+
"-d",
205+
"docs/_build/doctrees/html",
206+
"docs/",
207+
"docs/_build/html",
208+
)
209+
210+
188211
# Code formatting checks.
189212
#
190213
# These checks do *not* reformat code -- that happens in pre-commit hooks -- but will

src/webcolors/__init__.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
rgb_to_name,
2424
rgb_to_rgb_percent,
2525
)
26-
from ._definitions import CSS2, CSS3, CSS21, HTML4
26+
from ._definitions import CSS2, CSS3, CSS21, HTML4, names
2727
from ._html5 import (
2828
html5_parse_legacy_color,
2929
html5_parse_simple_color,
@@ -36,7 +36,7 @@
3636
)
3737
from ._types import HTML5SimpleColor, IntegerRGB, IntTuple, PercentRGB, PercentTuple
3838

39-
__version__ = "24.6.0"
39+
__version__ = "24.8.0a1"
4040

4141
__all__ = [
4242
"HTML4",
@@ -49,6 +49,7 @@
4949
"hex_to_name",
5050
"hex_to_rgb",
5151
"hex_to_rgb_percent",
52+
"names",
5253
"rgb_to_hex",
5354
"rgb_to_name",
5455
"rgb_to_rgb_percent",

src/webcolors/_definitions.py

+41
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# SPDX-License-Identifier: BSD-3-Clause
77

88
import re
9+
from typing import List
910

1011

1112
def _reversedict(dict_to_reverse: dict) -> dict:
@@ -299,3 +300,43 @@ def _get_hex_to_name_map(spec: str):
299300
if spec not in _SUPPORTED_SPECIFICATIONS:
300301
raise ValueError(_SPECIFICATION_ERROR_TEMPLATE.format(spec=spec))
301302
return _hex_to_names[spec]
303+
304+
305+
def names(spec: str = CSS3) -> List[str]:
306+
"""
307+
Return the list of valid color names for the given specification.
308+
309+
The color names will be normalized to all-lowercase, and will be returned in
310+
alphabetical order.
311+
312+
.. note:: **Spelling variants**
313+
314+
Some values representing named gray colors can map to either of two names in
315+
CSS3, because it supports both ``"gray"`` and ``"grey"`` spelling variants for
316+
those colors. Functions which produce a name from a color value in other formats
317+
all normalize to the ``"gray"`` spelling for consistency with earlier CSS and
318+
HTML specifications which only supported ``"gray"``. Here, however, *all* valid
319+
names are returned, including -- for CSS3 -- both variant spellings for each of
320+
the affected ``"gray"``/``"grey"`` colors.
321+
322+
Examples:
323+
324+
.. doctest::
325+
326+
>>> names(spec=HTML4)
327+
['aqua', 'black', 'blue', 'fuchsia', 'gray', 'green',
328+
'lime', 'maroon', 'navy', 'olive', 'purple', 'red',
329+
'silver', 'teal', 'white', 'yellow']
330+
>>> names(spec="CSS1")
331+
Traceback (most recent call last):
332+
...
333+
ValueError: "CSS1" is not a supported specification ...
334+
335+
336+
:raises ValueError: when the given spec is not supported.
337+
338+
"""
339+
if spec not in _SUPPORTED_SPECIFICATIONS:
340+
raise ValueError(_SPECIFICATION_ERROR_TEMPLATE.format(spec=spec))
341+
mapping = _names_to_hex[spec]
342+
return list(sorted(mapping.keys()))

tests/test_conversion.py

+24
Original file line numberDiff line numberDiff line change
@@ -411,3 +411,27 @@ def test_spelling_variants(self):
411411
(webcolors.rgb_percent_to_name, percent_tuple),
412412
):
413413
assert name == converter(value, spec=webcolors.CSS3)
414+
415+
def test_names_valid(self):
416+
"""
417+
names() correctly returns the set of names for a given spec.
418+
419+
"""
420+
for spec, mapping in (
421+
(webcolors.HTML4, webcolors._definitions._HTML4_NAMES_TO_HEX),
422+
(webcolors.CSS2, webcolors._definitions._CSS2_NAMES_TO_HEX),
423+
(webcolors.CSS21, webcolors._definitions._CSS21_NAMES_TO_HEX),
424+
(webcolors.CSS3, webcolors._definitions._CSS3_NAMES_TO_HEX),
425+
):
426+
with self.subTest(spec=spec):
427+
assert webcolors.names(spec) == list(sorted(mapping.keys()))
428+
429+
def test_names_invalid(self):
430+
"""
431+
names() raises ValueError when asked for an unsupported spec.
432+
433+
"""
434+
for spec in ("CSS0", "HTML12", "random"):
435+
with self.subTest(spec=spec):
436+
with self.assertRaises(ValueError):
437+
webcolors.names(spec)

0 commit comments

Comments
 (0)