diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 4ef1387..b25e478 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -3,7 +3,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.11" + python: "3.12" sphinx: configuration: docs/conf.py python: diff --git a/bin/update-tables.py b/bin/update-tables.py index 2bb9e18..83b2310 100644 --- a/bin/update-tables.py +++ b/bin/update-tables.py @@ -409,7 +409,6 @@ def fetch_table_vs16_data() -> UnicodeTableRenderCtx: For that reason, and that these values are not expected to change, only this single shared table is exported. - One example, where v3.2 became v1.1 ("-" 12.0, "+" 15.1):: -2620 FE0F ; Basic_Emoji ; skull and crossbones # 3.2 [1] (☠️) diff --git a/bin/verify-table-integrity.py b/bin/verify-table-integrity.py index bab458d..688aea6 100644 --- a/bin/verify-table-integrity.py +++ b/bin/verify-table-integrity.py @@ -85,6 +85,7 @@ def bisearch_pair(ucs, table): def main(log: logging.Logger): + # local from wcwidth import ZERO_WIDTH, WIDE_EASTASIAN, list_versions reversed_uni_versions = list(reversed(list_versions())) diff --git a/docs/conf.py b/docs/conf.py index c3f5811..fac366c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -68,7 +68,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. diff --git a/docs/intro.rst b/docs/intro.rst index 26025d6..7c38ffa 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -95,7 +95,7 @@ Briefly, return values of function ``wcwidth()`` are: Function ``wcswidth()`` simply returns the sum of all values for each character along a string, or ``-1`` when it occurs anywhere along a string. -Full API Documentation at https://wcwidth.readthedocs.org +Full API Documentation at https://wcwidth.readthedocs.io ========== Developing @@ -105,9 +105,9 @@ Install wcwidth in editable mode:: pip install -e . -Execute unit tests using tox_:: +Execute unit tests using tox_ for all supported Python versions:: - tox -e py36,py37,py38,py39,py310,py311,py312 + tox -e py36,py37,py38,py39,py310,py311,py312,py313,py314 Updating Unicode Version ------------------------ @@ -264,7 +264,7 @@ History Environment variable ``UNICODE_VERSION``, such as ``13.0``, or ``6.3.0``. See the `jquast/ucs-detect`_ CLI utility for automatic detection. * **Enhancement**: - API Documentation is published to readthedocs.org. + API Documentation is published to readthedocs.io. * **Updated** tables for *all* Unicode Specifications with files published in a programmatically consumable format, versions 4.1.0 through 13.0 diff --git a/docs/requirements.txt b/docs/requirements.txt index 3c973e4..016e11e 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,57 +1,60 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.12 # by the following command: # -# pip-compile --allow-unsafe --no-emit-index-url --output-file=docs/requirements.txt --strip-extras requirements-docs.in +# pip-compile --allow-unsafe --cert=None --client-cert=None --index-url=None --no-emit-index-url --output-file=docs/requirements.txt --pip-args=None --strip-extras requirements-docs.in # -alabaster==0.7.13 + +alabaster==1.0.0 # via sphinx -babel==2.12.1 +babel==2.17.0 # via sphinx -certifi==2024.7.4 +certifi==2025.8.3 # via requests -charset-normalizer==3.3.0 +charset-normalizer==3.4.3 # via requests -docutils==0.17.1 +docutils==0.21.2 # via # sphinx # sphinx-rtd-theme -idna==3.7 +idna==3.10 # via requests imagesize==1.4.1 # via sphinx jinja2==3.1.6 # via sphinx -markupsafe==2.1.3 +markupsafe==3.0.2 # via jinja2 -packaging==23.2 +packaging==25.0 # via sphinx -pygments==2.16.1 +pygments==2.19.2 # via sphinx -requests==2.32.4 +requests==2.32.5 # via sphinx -snowballstemmer==2.2.0 +roman-numerals-py==3.1.0 # via sphinx -sphinx==4.5.0 +snowballstemmer==3.0.1 + # via sphinx +sphinx==8.2.3 # via # -r requirements-docs.in # sphinx-rtd-theme # sphinxcontrib-jquery -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==3.0.2 # via -r requirements-docs.in -sphinxcontrib-applehelp==1.0.4 +sphinxcontrib-applehelp==2.0.0 # via sphinx -sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-devhelp==2.0.0 # via sphinx -sphinxcontrib-htmlhelp==2.0.1 +sphinxcontrib-htmlhelp==2.1.0 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-qthelp==2.0.0 # via sphinx -sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-serializinghtml==2.0.0 # via sphinx urllib3==2.5.0 # via requests diff --git a/requirements-docs.in b/requirements-docs.in index 98869c6..ab3f3dd 100644 --- a/requirements-docs.in +++ b/requirements-docs.in @@ -1,2 +1,2 @@ -Sphinx~=4.5 +Sphinx sphinx_rtd_theme diff --git a/requirements-tests39.txt b/requirements-tests39.txt index 1d1d6b6..f4897dc 100644 --- a/requirements-tests39.txt +++ b/requirements-tests39.txt @@ -4,7 +4,8 @@ # # pip-compile --allow-unsafe --no-emit-index-url --output-file=requirements-tests39.txt --strip-extras requirements-tests39.in # -coverage==7.9.1 + +coverage==7.10.6 # via pytest-cov exceptiongroup==1.3.0 # via pytest @@ -18,20 +19,20 @@ pluggy==1.6.0 # pytest-cov py-cpuinfo==9.0.0 # via pytest-benchmark -pygments==2.19.1 +pygments==2.19.2 # via pytest -pytest==8.4.0 +pytest==8.4.2 # via # -r requirements-tests39.in # pytest-benchmark # pytest-cov pytest-benchmark==5.1.0 # via -r requirements-tests39.in -pytest-cov==6.2.1 +pytest-cov==7.0.0 # via -r requirements-tests39.in tomli==2.2.1 # via # coverage # pytest -typing-extensions==4.14.0 +typing-extensions==4.15.0 # via exceptiongroup diff --git a/requirements-update.txt b/requirements-update.txt index ecabfcb..0441ec2 100644 --- a/requirements-update.txt +++ b/requirements-update.txt @@ -2,25 +2,26 @@ # This file is autogenerated by pip-compile with Python 3.12 # by the following command: # -# pip-compile --allow-unsafe --no-emit-index-url --output-file=requirements-update.txt --strip-extras requirements-update.in +# pip-compile --allow-unsafe --cert=None --client-cert=None --index-url=None --no-emit-index-url --output-file=requirements-update.txt --pip-args=None --strip-extras requirements-update.in # -certifi==2023.7.22 + +certifi==2025.8.3 # via requests -charset-normalizer==3.3.0 +charset-normalizer==3.4.3 # via requests -idna==3.4 +idna==3.10 # via requests -jinja2==3.1.3 +jinja2==3.1.6 # via -r requirements-update.in -markupsafe==2.1.3 +markupsafe==3.0.2 # via jinja2 -python-dateutil==2.8.2 +python-dateutil==2.9.0.post0 # via -r requirements-update.in -requests==2.31.0 +requests==2.32.5 # via -r requirements-update.in -six==1.16.0 +six==1.17.0 # via python-dateutil -typing-extensions==4.8.0 +typing-extensions==4.15.0 # via -r requirements-update.in -urllib3==2.0.7 +urllib3==2.5.0 # via requests diff --git a/tests/test_emojis.py b/tests/test_emojis.py index 1d6c7be..310d0c3 100644 --- a/tests/test_emojis.py +++ b/tests/test_emojis.py @@ -123,7 +123,7 @@ def test_longer_emoji_zwj_sequence(): "\u200d" # 'Cf', 'N' -- ZERO WIDTH JOINER "\U0001F9D1" # 'So', 'W' -- ADULT "\U0001F3FD" # 'Sk', 'W' -- EMOJI MODIFIER FITZPATRICK TYPE-4 - ) * 2 + ) * 2 # This test adapted from https://www.unicode.org/L2/L2023/23107-terminal-suppt.pdf expect_length_each = (2, 0, 0, 1, 0, 0, 2, 0, 2, 0) * 2 expect_length_phrase = 4 @@ -140,8 +140,8 @@ def test_longer_emoji_zwj_sequence(): def read_sequences_from_file(filename): fp = open(os.path.join(os.path.dirname(__file__), filename), 'r', encoding='utf-8') lines = [line.strip() - for line in fp.readlines() - if not line.startswith('#') and line.strip()] + for line in fp.readlines() + if not line.startswith('#') and line.strip()] fp.close() sequences = [make_sequence_from_line(line) for line in lines] return lines, sequences @@ -218,6 +218,7 @@ def test_unicode_9_vs16(): assert length_each == expect_length_each assert length_phrase == expect_length_phrase + def test_unicode_8_vs16(): """Verify that VS-16 has no effect on unicode_version 8.0 and earler""" phrase = ("\u2640" # FEMALE SIGN @@ -232,4 +233,4 @@ def test_unicode_8_vs16(): # verify. assert length_each == expect_length_each - assert length_phrase == expect_length_phrase \ No newline at end of file + assert length_phrase == expect_length_phrase diff --git a/tests/test_table_integrity.py b/tests/test_table_integrity.py index 66e63dd..e680498 100644 --- a/tests/test_table_integrity.py +++ b/tests/test_table_integrity.py @@ -1,15 +1,18 @@ """ Executes verify-table-integrity.py as a unit test. """ +# std imports import os import sys import subprocess +# 3rd party import pytest + @pytest.mark.skipif(sys.version_info[:2] != (3, 12), reason='Test only with a single version of python') def test_verify_table_integrity(): subprocess.check_output([sys.executable, os.path.join(os.path.dirname(__file__), os.path.pardir, 'bin', - 'verify-table-integrity.py')]) \ No newline at end of file + 'verify-table-integrity.py')]) diff --git a/tox.ini b/tox.ini index 0346af7..9d66fbf 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,7 @@ [tox] -envlist = update, compile, autopep8, docformatter, isort, pylint, flake8, pydocstyle, docs, verify_tables, py{36, 37, 38, 39, 310, 311, 312}, pypy{36, 37, 38, 39, 310} +envlist = update, compile, autopep8, docformatter, isort, pylint, flake8, pydocstyle, docs, verify_tables, py{36, 37, 38, 39, 310, 311, 312, 313, 314}, pypy{36, 37, 38, 39, 310} skip_missing_interpreters = true +# needed for Python 3.6 # https://tox.wiki/en/4.11.3/faq.html#testing-end-of-life-python-versions requires = virtualenv<20.22.0 @@ -67,18 +68,18 @@ source = wcwidth/ # version for the newest to oldest python versions for testing, must also use some # targeted versions to 'compile' those requirements into their frozen form, # otherwise incompatible packages would be pinned. At the time of this writing the -# files compiled for version 3.9 through 3.11 are compiled by python3.11. +# files compiled for version 3.9 and later are compiled by python3.13 [WIP]. [testenv:compile] -basepython = python3.11 +basepython = python3.13 commands = python -m compileall {toxinidir}/wcwidth {toxinidir}/bin {toxinidir}/tests {toxinidir}/docs [testenv:update_requirements_update] -basepython = python3.12 +basepython = python3.13 deps = pip-tools commands = {[base]pip_compile_command} requirements-update.in -o requirements-update.txt [testenv:update_requirements_docs] -basepython = python3.11 +basepython = python3.12 deps = pip-tools commands = {[base]pip_compile_command} requirements-docs.in -o docs/requirements.txt @@ -111,13 +112,14 @@ deps = -r requirements-tests36.txt deps = -r requirements-tests36.txt [testenv:update] -basepython = python3.12 +basepython = python3.13 usedevelop = true deps = -r requirements-update.txt commands = python {toxinidir}/bin/update-tables.py {posargs:--no-check-last-modified} [testenv:autopep8] basepython = python3.11 +deps = autopep8 commands = {envbindir}/autopep8 \ --in-place \ @@ -126,54 +128,33 @@ commands = --aggressive \ wcwidth/ bin/ tests/ setup.py -[testenv:docformatter] -basepython = python3.11 -commands = - {envbindir}/docformatter \ - --in-place \ - --recursive \ - --pre-summary-newline \ - --wrap-summaries=100 \ - --wrap-descriptions=100 \ - {toxinidir}/wcwidth \ - {toxinidir}/bin \ - {toxinidir}/setup.py \ - {toxinidir}/docs/conf.py - [testenv:isort] -basepython = python3.11 +deps = isort +basepython = python3.13 commands = {envbindir}/isort --quiet --apply --recursive wcwidth tests bin [testenv:pylint] -basepython = python3.11 +basepython = python3.13 +deps = pylint commands = {envbindir}/pylint --rcfile={toxinidir}/.pylintrc \ --ignore=tests,docs,setup.py,conf.py,build,distutils,.pyenv,.git,.tox \ {posargs:{toxinidir}}/wcwidth [testenv:flake8] -basepython = python3.11 +basepython = python3.13 +deps = flake8 commands = {envbindir}/flake8 --exclude=tests setup.py docs/ wcwidth/ bin/ tests/ -[testenv:pydocstyle] -basepython = python3.11 -commands = {envbindir}/pydocstyle --source --explain {toxinidir}/wcwidth - {envbindir}/rst-lint README.rst - {envbindir}/doc8 --ignore-path docs/_build --ignore-path docs/requirements.txt --ignore D000 docs - [testenv:docs] -basepython = python3.11 +# matches .readthedocs.yaml and environment +basepython = python3.12 deps = -r {toxinidir}/docs/requirements.txt commands = sphinx-build docs/ build/sphinx [testenv:verify_tables] -basepython = python3.12 +basepython = python3.13 commands = python {toxinidir}/bin/verify-table-integrity.py -[testenv:sphinx] -basepython = python3.11 -deps = -r {toxinidir}/docs/requirements.txt -commands = {envbindir}/sphinx-build {posargs:-v -W -d {toxinidir}/docs/_build/doctrees -b html docs {toxinidir}/docs/_build/html} - [testenv:linkcheck] basepython = python3.11 deps = -r {toxinidir}/docs/requirements.txt diff --git a/wcwidth/table_wide.py b/wcwidth/table_wide.py index 879546b..5139b1f 100644 --- a/wcwidth/table_wide.py +++ b/wcwidth/table_wide.py @@ -1,7 +1,7 @@ """ Exports WIDE_EASTASIAN table keyed by supporting unicode version level. -This code generated by wcwidth/bin/update-tables.py on 2025-09-15 16:57:50 UTC. +This code generated by wcwidth/bin/update-tables.py on 2025-09-19 15:55:08 UTC. """ WIDE_EASTASIAN = { '4.1.0': ( @@ -1413,7 +1413,7 @@ (0x03105, 0x0312f,), # Bopomofo Letter B ..Bopomofo Letter Nn (0x03131, 0x0318e,), # Hangul Letter Kiyeok ..Hangul Letter Araeae (0x03190, 0x031e3,), # Ideographic Annotation L..Cjk Stroke Q - (0x031ef, 0x0321e,), # (nil) ..Parenthesized Korean Cha + (0x031ef, 0x0321e,), # Ideographic Description ..Parenthesized Korean Cha (0x03220, 0x03247,), # Parenthesized Ideograph ..Circled Ideograph Koto (0x03250, 0x04dbf,), # Partnership Sign ..Cjk Unified Ideograph-4d (0x04e00, 0x0a48c,), # Cjk Unified Ideograph-4e..Yi Syllable Yyr @@ -1541,7 +1541,7 @@ (0x03105, 0x0312f,), # Bopomofo Letter B ..Bopomofo Letter Nn (0x03131, 0x0318e,), # Hangul Letter Kiyeok ..Hangul Letter Araeae (0x03190, 0x031e5,), # Ideographic Annotation L..(nil) - (0x031ef, 0x0321e,), # (nil) ..Parenthesized Korean Cha + (0x031ef, 0x0321e,), # Ideographic Description ..Parenthesized Korean Cha (0x03220, 0x03247,), # Parenthesized Ideograph ..Circled Ideograph Koto (0x03250, 0x0a48c,), # Partnership Sign ..Yi Syllable Yyr (0x0a490, 0x0a4c6,), # Yi Radical Qot ..Yi Radical Ke @@ -1669,7 +1669,7 @@ (0x03105, 0x0312f,), # Bopomofo Letter B ..Bopomofo Letter Nn (0x03131, 0x0318e,), # Hangul Letter Kiyeok ..Hangul Letter Araeae (0x03190, 0x031e5,), # Ideographic Annotation L..(nil) - (0x031ef, 0x0321e,), # (nil) ..Parenthesized Korean Cha + (0x031ef, 0x0321e,), # Ideographic Description ..Parenthesized Korean Cha (0x03220, 0x03247,), # Parenthesized Ideograph ..Circled Ideograph Koto (0x03250, 0x0a48c,), # Partnership Sign ..Yi Syllable Yyr (0x0a490, 0x0a4c6,), # Yi Radical Qot ..Yi Radical Ke