aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-10-12 10:39:22 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-10-12 10:50:34 +0300
commitb904316f22d889171e7fe39e8c467cbea5c6cdd6 (patch)
tree84c870d76f7278ad6a8d1c020a8b950edb7d531e
parente493167a2cecbdc68258d70ddb044e7a0f56aa7f (diff)
downloadydb-b904316f22d889171e7fe39e8c467cbea5c6cdd6.tar.gz
Intermediate changes
commit_hash:3ed72e620c7eace6c8edd510ac2324e8acfcfafb
-rw-r--r--contrib/python/clickhouse-connect/.dist-info/METADATA2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/__version__.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/datatypes/base.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/ddl/custom.py4
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/dialect.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/__init__.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/ddlcompiler.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/preparer.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/common.py3
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/__init__.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/base.py28
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/container.py88
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/dynamic.py257
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/network.py8
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/numeric.py26
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/postinit.py4
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/registry.py6
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/special.py7
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/string.py16
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/datatypes/temporal.py14
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/__init__.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/asyncclient.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/binding.py199
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/client.py24
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/common.py19
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/context.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/ctypes.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/errors.py8
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/httpclient.py29
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/httputil.py61
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/insert.py7
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/parser.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/query.py165
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/tools.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/driver/transform.py2
-rw-r--r--contrib/python/clickhouse-connect/clickhouse_connect/tools/testing.py2
-rw-r--r--contrib/python/clickhouse-connect/ya.make5
-rw-r--r--contrib/python/fonttools/.dist-info/METADATA24
-rw-r--r--contrib/python/fonttools/fontTools/__init__.py2
-rw-r--r--contrib/python/fonttools/fontTools/designspaceLib/__init__.py11
-rw-r--r--contrib/python/fonttools/fontTools/merge/__init__.py10
-rw-r--r--contrib/python/fonttools/fontTools/pens/freetypePen.py32
-rw-r--r--contrib/python/fonttools/fontTools/pens/pointInsidePen.py3
-rw-r--r--contrib/python/fonttools/fontTools/pens/recordingPen.py236
-rw-r--r--contrib/python/fonttools/fontTools/pens/svgPathPen.py21
-rw-r--r--contrib/python/fonttools/fontTools/pens/transformPen.py37
-rw-r--r--contrib/python/fonttools/fontTools/subset/__init__.py7
-rw-r--r--contrib/python/fonttools/fontTools/svgLib/path/__init__.py4
-rw-r--r--contrib/python/fonttools/fontTools/svgLib/path/parser.py2
-rw-r--r--contrib/python/fonttools/fontTools/ttLib/sfnt.py5
-rw-r--r--contrib/python/fonttools/fontTools/ttLib/tables/_n_a_m_e.py27
-rw-r--r--contrib/python/fonttools/fontTools/ttLib/ttFont.py72
-rw-r--r--contrib/python/fonttools/fontTools/ufoLib/__init__.py64
-rw-r--r--contrib/python/fonttools/fontTools/unicodedata/Blocks.py75
-rw-r--r--contrib/python/fonttools/fontTools/unicodedata/ScriptExtensions.py366
-rw-r--r--contrib/python/fonttools/fontTools/unicodedata/Scripts.py313
-rw-r--r--contrib/python/fonttools/fontTools/unicodedata/__init__.py2
-rw-r--r--contrib/python/fonttools/fontTools/varLib/__init__.py10
-rw-r--r--contrib/python/fonttools/fontTools/varLib/avar.py194
-rw-r--r--contrib/python/fonttools/fontTools/varLib/cff.py2
-rw-r--r--contrib/python/fonttools/fontTools/varLib/instancer/__init__.py79
-rw-r--r--contrib/python/fonttools/fontTools/varLib/interpolatable.py26
-rw-r--r--contrib/python/fonttools/fontTools/varLib/interpolatableHelpers.py27
-rw-r--r--contrib/python/fonttools/fontTools/varLib/models.py33
-rw-r--r--contrib/python/fonttools/fontTools/varLib/mutator.py8
-rw-r--r--contrib/python/fonttools/fontTools/voltLib/voltToFea.py4
-rw-r--r--contrib/python/fonttools/ya.make2
-rw-r--r--contrib/python/prompt-toolkit/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/__init__.py2
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/fuzzy_completer.py4
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/word_completer.py4
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/contrib/regular_languages/compiler.py17
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/cursor_shapes.py17
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py22
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/patch_stdout.py2
-rw-r--r--contrib/python/prompt-toolkit/py3/ya.make2
-rw-r--r--contrib/python/tzdata/.dist-info/METADATA2
-rw-r--r--contrib/python/tzdata/tzdata/__init__.py4
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Africa/Blantyrebin131 -> 131 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Africa/Bujumburabin131 -> 131 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Africa/Gaboronebin131 -> 131 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Africa/Hararebin131 -> 131 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Africa/Kigalibin131 -> 131 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Africa/Lubumbashibin131 -> 131 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Africa/Lusakabin131 -> 131 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Africa/Maputobin131 -> 131 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Bahia_Banderasbin728 -> 700 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Cancunbin529 -> 538 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Chihuahuabin691 -> 691 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Ciudad_Juarezbin718 -> 718 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Ensenadabin1025 -> 1079 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Hermosillobin286 -> 258 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Mazatlanbin718 -> 690 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Meridabin654 -> 654 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Mexico_Citybin773 -> 773 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Monterreybin644 -> 709 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Ojinagabin718 -> 718 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Santa_Isabelbin1025 -> 1079 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/America/Tijuanabin1025 -> 1079 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Asia/Choibalsanbin619 -> 594 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Asia/Dilibin170 -> 170 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Azoresbin1453 -> 1401 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Madeirabin1453 -> 1372 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/CETbin621 -> 1103 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/CST6CDTbin951 -> 1754 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/EETbin497 -> 682 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/ESTbin111 -> 149 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/EST5EDTbin951 -> 1744 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Europe/Lisbonbin1454 -> 1463 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/HSTbin112 -> 221 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/METbin621 -> 1103 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/MSTbin111 -> 240 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/MST7MDTbin951 -> 1042 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaNortebin1025 -> 1079 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaSurbin718 -> 690 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Mexico/Generalbin773 -> 773 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/PST8PDTbin951 -> 1294 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/Portugalbin1454 -> 1463 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/WETbin494 -> 1463 bytes
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/leapseconds8
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/tzdata.zi1653
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/zone.tab3
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/zone1970.tab3
-rw-r--r--contrib/python/tzdata/tzdata/zoneinfo/zonenow.tab8
-rw-r--r--contrib/python/tzdata/tzdata/zones24
-rw-r--r--contrib/python/tzdata/ya.make2
126 files changed, 2754 insertions, 1733 deletions
diff --git a/contrib/python/clickhouse-connect/.dist-info/METADATA b/contrib/python/clickhouse-connect/.dist-info/METADATA
index e001706076..8ebbb2ace2 100644
--- a/contrib/python/clickhouse-connect/.dist-info/METADATA
+++ b/contrib/python/clickhouse-connect/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: clickhouse-connect
-Version: 0.7.19
+Version: 0.8.0
Summary: ClickHouse Database Core Driver for Python, Pandas, and Superset
Home-page: https://github.com/ClickHouse/clickhouse-connect
Author: ClickHouse Inc.
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/__version__.py b/contrib/python/clickhouse-connect/clickhouse_connect/__version__.py
index d9d76edb88..c5e4522a93 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/__version__.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/__version__.py
@@ -1 +1 @@
-version = '0.7.19'
+version = '0.8.0'
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/datatypes/base.py b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/datatypes/base.py
index 0c0d25e6b0..ce73da1481 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/datatypes/base.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/datatypes/base.py
@@ -5,7 +5,7 @@ from sqlalchemy.exc import CompileError
from clickhouse_connect.datatypes.base import ClickHouseType, TypeDef, EMPTY_TYPE_DEF
from clickhouse_connect.datatypes.registry import parse_name, type_map
-from clickhouse_connect.driver.query import str_query_value
+from clickhouse_connect.driver.binding import str_query_value
logger = logging.getLogger(__name__)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/ddl/custom.py b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/ddl/custom.py
index b7eee4ad7d..9f7c1e6401 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/ddl/custom.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/ddl/custom.py
@@ -1,7 +1,7 @@
from sqlalchemy.sql.ddl import DDL
from sqlalchemy.exc import ArgumentError
-from clickhouse_connect.driver.query import quote_identifier
+from clickhouse_connect.driver.binding import quote_identifier
# pylint: disable=too-many-ancestors,abstract-method
@@ -31,7 +31,7 @@ class CreateDatabase(DDL):
super().__init__(stmt)
-# pylint: disable=too-many-ancestors,abstract-method
+# pylint: disable=too-many-ancestors,abstract-method
class DropDatabase(DDL):
"""
Alternative DDL statement for built in SqlAlchemy DropSchema DDL class
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/dialect.py b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/dialect.py
index 6b04c7e2fe..c9bb24c95a 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/dialect.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/dialect.py
@@ -8,7 +8,7 @@ from clickhouse_connect.cc_sqlalchemy.sql import full_table
from clickhouse_connect.cc_sqlalchemy.sql.ddlcompiler import ChDDLCompiler
from clickhouse_connect.cc_sqlalchemy import ischema_names, dialect_name
from clickhouse_connect.cc_sqlalchemy.sql.preparer import ChIdentifierPreparer
-from clickhouse_connect.driver.query import quote_identifier, format_str
+from clickhouse_connect.driver.binding import quote_identifier, format_str
# pylint: disable=too-many-public-methods,no-self-use,unused-argument
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/__init__.py b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/__init__.py
index 68becd54d6..00b9bc8c13 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/__init__.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/__init__.py
@@ -2,7 +2,7 @@ from typing import Optional
from sqlalchemy import Table
-from clickhouse_connect.driver.query import quote_identifier
+from clickhouse_connect.driver.binding import quote_identifier
def full_table(table_name: str, schema: Optional[str] = None) -> str:
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/ddlcompiler.py b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/ddlcompiler.py
index 5a97254705..8a2180c466 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/ddlcompiler.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/ddlcompiler.py
@@ -2,7 +2,7 @@ from sqlalchemy import Column
from sqlalchemy.sql.compiler import DDLCompiler
from clickhouse_connect.cc_sqlalchemy.sql import format_table
-from clickhouse_connect.driver.query import quote_identifier
+from clickhouse_connect.driver.binding import quote_identifier
class ChDDLCompiler(DDLCompiler):
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/preparer.py b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/preparer.py
index a31b3e7af6..f53a2bde37 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/preparer.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/sql/preparer.py
@@ -1,6 +1,6 @@
from sqlalchemy.sql.compiler import IdentifierPreparer
-from clickhouse_connect.driver.query import quote_identifier
+from clickhouse_connect.driver.binding import quote_identifier
class ChIdentifierPreparer(IdentifierPreparer):
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/common.py b/contrib/python/clickhouse-connect/clickhouse_connect/common.py
index 1fda1ecfd7..ab960e76b7 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/common.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/common.py
@@ -81,3 +81,6 @@ _init_common('send_os_user', (True, False), True)
_init_common('use_protocol_version', (True, False), True)
_init_common('max_error_size', (), 1024)
+
+# HTTP raw data buffer for streaming queries. This should not be reduced below 64KB to ensure compatibility with LZ4 compression
+_init_common('http_buffer_size', (), 10 * 1024 * 1024)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/__init__.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/__init__.py
index aa9b8c2f5d..e4229f66c3 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/__init__.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/__init__.py
@@ -4,4 +4,6 @@ import clickhouse_connect.datatypes.numeric
import clickhouse_connect.datatypes.special
import clickhouse_connect.datatypes.string
import clickhouse_connect.datatypes.temporal
+import clickhouse_connect.datatypes.dynamic
import clickhouse_connect.datatypes.registry
+import clickhouse_connect.datatypes.postinit
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/base.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/base.py
index b1990280eb..ab43b4e1db 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/base.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/base.py
@@ -3,7 +3,7 @@ import logging
from abc import ABC
from math import log
-from typing import NamedTuple, Dict, Type, Any, Sequence, MutableSequence, Optional, Union, Collection
+from typing import NamedTuple, Dict, Type, Any, Sequence, MutableSequence, Union, Collection
from clickhouse_connect.driver.common import array_type, int_size, write_array, write_uint64, low_card_version
from clickhouse_connect.driver.context import BaseQueryContext
@@ -94,6 +94,10 @@ class ClickHouseType(ABC):
name = f'{wrapper}({name})'
return name
+ @property
+ def insert_name(self):
+ return self.name
+
def data_size(self, sample: Sequence) -> int:
if self.low_card:
values = set(sample)
@@ -104,10 +108,13 @@ class ClickHouseType(ABC):
d_size += 1
return d_size
- def _data_size(self, _sample: Collection) -> int:
+ def _data_size(self, sample: Collection) -> int:
if self.byte_size:
return self.byte_size
- return 0
+ total = 0
+ for x in sample:
+ total += len(str(x))
+ return total / len(sample) + 1
def write_column_prefix(self, dest: bytearray):
"""
@@ -119,7 +126,7 @@ class ClickHouseType(ABC):
if self.low_card:
write_uint64(low_card_version, dest)
- def read_column_prefix(self, source: ByteSource):
+ def read_column_prefix(self, source: ByteSource, _ctx: QueryContext):
"""
Read the low cardinality version. Like the write method, this has to happen immediately for container classes
:param source: The native protocol binary read buffer
@@ -139,7 +146,7 @@ class ClickHouseType(ABC):
:param ctx: QueryContext for query specific settings
:return: The decoded column data as a sequence and the updated location pointer
"""
- self.read_column_prefix(source)
+ self.read_column_prefix(source, ctx)
return self.read_column_data(source, num_rows, ctx)
def read_column_data(self, source: ByteSource, num_rows: int, ctx: QueryContext) -> Sequence:
@@ -274,18 +281,11 @@ class ClickHouseType(ABC):
write_uint64(len(index), dest)
self._write_column_binary(index, dest, ctx)
write_uint64(len(keys), dest)
- write_array(array_type(1 << ix_type, False), keys, dest)
+ write_array(array_type(1 << ix_type, False), keys, dest, ctx.column_name)
def _active_null(self, _ctx: QueryContext) -> Any:
return None
- def _first_value(self, column: Sequence) -> Optional[Any]:
- if self.nullable:
- return next((x for x in column if x is not None), None)
- if len(column):
- return column[0]
- return None
-
EMPTY_TYPE_DEF = TypeDef()
NULLABLE_TYPE_DEF = TypeDef(wrappers=('Nullable',))
@@ -338,7 +338,7 @@ class ArrayType(ClickHouseType, ABC, registered=False):
def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext):
if len(column) and self.nullable:
column = [0 if x is None else x for x in column]
- write_array(self._array_type, column, dest)
+ write_array(self._array_type, column, dest, ctx.column_name)
def _active_null(self, ctx: QueryContext):
if ctx.as_pandas and ctx.use_extended_dtypes:
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/container.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/container.py
index 445b24140d..b8244eefdb 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/container.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/container.py
@@ -3,11 +3,12 @@ import logging
from typing import Sequence, Collection
from clickhouse_connect.driver.insert import InsertContext
-from clickhouse_connect.driver.query import QueryContext, quote_identifier
+from clickhouse_connect.driver.query import QueryContext
+from clickhouse_connect.driver.binding import quote_identifier
from clickhouse_connect.driver.types import ByteSource
from clickhouse_connect.json_impl import any_to_json
from clickhouse_connect.datatypes.base import ClickHouseType, TypeDef
-from clickhouse_connect.driver.common import must_swap
+from clickhouse_connect.driver.common import must_swap, first_value
from clickhouse_connect.datatypes.registry import get_from_name
logger = logging.getLogger(__name__)
@@ -22,8 +23,8 @@ class Array(ClickHouseType):
self.element_type = get_from_name(type_def.values[0])
self._name_suffix = f'({self.element_type.name})'
- def read_column_prefix(self, source: ByteSource):
- return self.element_type.read_column_prefix(source)
+ def read_column_prefix(self, source: ByteSource, ctx:QueryContext):
+ return self.element_type.read_column_prefix(source, ctx)
def _data_size(self, sample: Sequence) -> int:
if len(sample) == 0:
@@ -102,7 +103,7 @@ class Tuple(ClickHouseType):
if len(sample) == 0:
return 0
elem_size = 0
- is_dict = self.element_names and isinstance(self._first_value(list(sample)), dict)
+ is_dict = self.element_names and isinstance(first_value(list(sample), self.nullable), dict)
for ix, e_type in enumerate(self.element_types):
if e_type.byte_size > 0:
elem_size += e_type.byte_size
@@ -112,9 +113,9 @@ class Tuple(ClickHouseType):
elem_size += e_type.data_size([x[ix] for x in sample])
return elem_size
- def read_column_prefix(self, source: ByteSource):
+ def read_column_prefix(self, source: ByteSource, ctx: QueryContext):
for e_type in self.element_types:
- e_type.read_column_prefix(source)
+ e_type.read_column_prefix(source, ctx)
def read_column_data(self, source: ByteSource, num_rows: int, ctx: QueryContext):
columns = []
@@ -138,7 +139,7 @@ class Tuple(ClickHouseType):
e_type.write_column_prefix(dest)
def write_column_data(self, column: Sequence, dest: bytearray, ctx: InsertContext):
- if self.element_names and isinstance(self._first_value(column), dict):
+ if self.element_names and isinstance(first_value(column, self.nullable), dict):
columns = self.convert_dict_insert(column)
else:
columns = list(zip(*column))
@@ -180,9 +181,9 @@ class Map(ClickHouseType):
total += self.value_type.data_size(x.values())
return total // len(sample)
- def read_column_prefix(self, source: ByteSource):
- self.key_type.read_column_prefix(source)
- self.value_type.read_column_prefix(source)
+ def read_column_prefix(self, source: ByteSource, ctx: QueryContext):
+ self.key_type.read_column_prefix(source, ctx)
+ self.value_type.read_column_prefix(source, ctx)
# pylint: disable=too-many-locals
def read_column_data(self, source: ByteSource, num_rows: int, ctx: QueryContext):
@@ -237,8 +238,8 @@ class Nested(ClickHouseType):
array_sample = [[tuple(sub_row[key] for key in keys) for sub_row in row] for row in sample]
return self.tuple_array.data_size(array_sample)
- def read_column_prefix(self, source: ByteSource):
- self.tuple_array.read_column_prefix(source)
+ def read_column_prefix(self, source: ByteSource, ctx:QueryContext):
+ self.tuple_array.read_column_prefix(source, ctx)
def read_column_data(self, source: ByteSource, num_rows: int, ctx: QueryContext):
keys = self.element_names
@@ -252,64 +253,3 @@ class Nested(ClickHouseType):
keys = self.element_names
data = [[tuple(sub_row[key] for key in keys) for sub_row in row] for row in column]
self.tuple_array.write_column_data(data, dest, ctx)
-
-
-class JSON(ClickHouseType):
- python_type = dict
- # Native is a Python type (primitive, dict, array), string is an actual JSON string
- valid_formats = 'string', 'native'
-
- def write_column_prefix(self, dest: bytearray):
- dest.append(0x01)
-
- def _data_size(self, sample: Collection) -> int:
- if len(sample) == 0:
- return 0
- total = 0
- for x in sample:
- if isinstance(x, str):
- total += len(x)
- elif x:
- total += len(any_to_json(x))
- return total // len(sample) + 1
-
- # pylint: disable=duplicate-code
- def write_column_data(self, column: Sequence, dest: bytearray, ctx: InsertContext):
- app = dest.append
- first = self._first_value(column)
- if isinstance(first, str) or self.write_format(ctx) == 'string':
- for x in column:
- v = x.encode()
- sz = len(v)
- while True:
- b = sz & 0x7f
- sz >>= 7
- if sz == 0:
- app(b)
- break
- app(0x80 | b)
- dest += v
- else:
- to_json = any_to_json
- for x in column:
- v = to_json(x)
- sz = len(v)
- while True:
- b = sz & 0x7f
- sz >>= 7
- if sz == 0:
- app(b)
- break
- app(0x80 | b)
- dest += v
-
-
-class Object(JSON):
- python_type = dict
-
- def __init__(self, type_def):
- data_type = type_def.values[0].lower().replace(' ', '')
- if data_type not in ("'json'", "nullable('json')"):
- raise NotImplementedError('Only json or Nullable(json) Object type is currently supported')
- super().__init__(type_def)
- self._name_suffix = type_def.arg_str
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/dynamic.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/dynamic.py
new file mode 100644
index 0000000000..e32145f1f8
--- /dev/null
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/dynamic.py
@@ -0,0 +1,257 @@
+from typing import List, Sequence, Collection
+
+from clickhouse_connect.datatypes.base import ClickHouseType, TypeDef
+from clickhouse_connect.datatypes.registry import get_from_name
+from clickhouse_connect.driver.common import unescape_identifier, first_value
+from clickhouse_connect.driver.ctypes import data_conv
+from clickhouse_connect.driver.errors import handle_error
+from clickhouse_connect.driver.exceptions import DataError
+from clickhouse_connect.driver.insert import InsertContext
+from clickhouse_connect.driver.query import QueryContext
+from clickhouse_connect.driver.types import ByteSource
+from clickhouse_connect.json_impl import any_to_json
+
+SHARED_DATA_TYPE: ClickHouseType
+STRING_DATA_TYPE: ClickHouseType
+
+class Variant(ClickHouseType):
+ _slots = 'element_types'
+ python_type = object
+
+ def __init__(self, type_def: TypeDef):
+ super().__init__(type_def)
+ self.element_types:List[ClickHouseType] = [get_from_name(name) for name in type_def.values]
+ self._name_suffix = f"({', '.join(ch_type.name for ch_type in self.element_types)})"
+
+ @property
+ def insert_name(self):
+ return 'String'
+
+ def read_column_prefix(self, source: ByteSource, ctx:QueryContext):
+ if source.read_uint64() != 0:
+ raise DataError(f'Unexpected discriminator format in Variant column {ctx.column_name}')
+
+ def read_column_data(self, source: ByteSource, num_rows: int, ctx: QueryContext) -> Sequence:
+ return read_variant_column(self.element_types, source, num_rows, ctx)
+
+ def write_column_data(self, column: Sequence, dest: bytearray, ctx: InsertContext):
+ write_str_values(self, column, dest, ctx)
+
+
+def read_variant_column(variant_types: List[ClickHouseType], source: ByteSource, num_rows:int, ctx: QueryContext) -> Sequence:
+ v_count = len(variant_types)
+ discriminators = source.read_array('B', num_rows)
+ # We have to count up how many of each discriminator there are in the block to read the sub columns correctly
+ disc_rows = [0] * v_count
+ for disc in discriminators:
+ if disc != 255:
+ disc_rows[disc] += 1
+ sub_columns: List[Sequence] = [[]] * v_count
+ # Read all the sub-columns
+ for ix in range(v_count):
+ if disc_rows[ix] > 0:
+ sub_columns[ix] = variant_types[ix].read_column_data(source, disc_rows[ix], ctx)
+ # Now we have to walk through each of the discriminators again to assign the correct value from
+ # the sub-column to the final result column
+ sub_indexes = [0] * v_count
+ col = []
+ app_col = col.append
+ for disc in discriminators:
+ if disc == 255:
+ app_col(None)
+ else:
+ app_col(sub_columns[disc][sub_indexes[disc]])
+ sub_indexes[disc] += 1
+ return col
+
+
+class Dynamic(ClickHouseType):
+ python_type = object
+
+ @property
+ def insert_name(self):
+ return 'String'
+
+ def __init__(self, type_def:TypeDef):
+ super().__init__(type_def)
+ if type_def.keys and type_def.keys[0] == 'max_types':
+ self._name_suffix = f'(max_types={type_def.values[0]})'
+
+ def read_column(self, source: ByteSource, num_rows:int, ctx:QueryContext):
+ variant_types = read_dynamic_prefix(source)
+ return read_variant_column(variant_types, source, num_rows, ctx)
+
+ def write_column_data(self, column: Sequence, dest: bytearray, ctx: InsertContext):
+ write_str_values(self, column, dest, ctx)
+
+
+def read_dynamic_prefix(source: ByteSource) -> List[ClickHouseType]:
+ if source.read_uint64() != 1: # dynamic structure serialization version, currently only 1 is recognized
+ raise DataError('Unrecognized dynamic structure version')
+ source.read_leb128() # max dynamic types, we ignore this value
+ num_variants = source.read_leb128()
+ variant_types = [get_from_name(source.read_leb128_str()) for _ in range(num_variants)]
+ variant_types.append(STRING_DATA_TYPE)
+ if source.read_uint64() != 0: # discriminator format, currently only 0 is recognized
+ raise DataError('Unexpected discriminator format in Variant column prefix')
+ return variant_types
+
+
+def json_sample_size(_, sample: Collection) -> int:
+ if len(sample) == 0:
+ return 0
+ total = 0
+ for x in sample:
+ if isinstance(x, str):
+ total += len(x)
+ elif x:
+ total += len(any_to_json(x))
+ return total // len(sample) + 1
+
+
+def write_json(ch_type:ClickHouseType, column: Sequence, dest: bytearray, ctx: InsertContext):
+ first = first_value(column, ch_type.nullable)
+ write_col = column
+ encoding = ctx.encoding or ch_type.encoding
+ if not isinstance(first, str) and ch_type.write_format(ctx) != 'string':
+ to_json = any_to_json
+ write_col = [to_json(v) for v in column]
+ encoding = None
+ handle_error(data_conv.write_str_col(write_col, ch_type.nullable, encoding, dest), ctx)
+
+
+def write_str_values(ch_type:ClickHouseType, column: Sequence, dest: bytearray, ctx: InsertContext):
+ encoding = ctx.encoding or ch_type.encoding
+ col = [''] * len(column)
+ for ix, v in enumerate(column):
+ if v is None:
+ col[ix] = 'NULL'
+ else:
+ col[ix] = str(v)
+ handle_error(data_conv.write_str_col(col, False, encoding, dest), ctx)
+
+
+class JSON(ClickHouseType):
+ _slots = 'typed_paths', 'typed_types'
+ python_type = dict
+ valid_formats = 'string', 'native'
+ _data_size = json_sample_size
+ write_column_data = write_json
+ shared_data_type: ClickHouseType
+ max_dynamic_paths = 0
+ max_dynamic_types = 0
+ typed_paths = []
+ typed_types = []
+ skips = []
+
+ def __init__(self, type_def:TypeDef):
+ super().__init__(type_def)
+ typed_paths = []
+ typed_types = []
+ skips = []
+ parts = []
+ for key, value in zip(type_def.keys, type_def.values):
+ if key == 'max_dynamic_paths':
+ try:
+ self.max_dynamic_paths = int(value)
+ parts.append(f'{key} = {value}')
+ continue
+ except ValueError:
+ pass
+ if key == 'max_dynamic_types':
+ try:
+ self.max_dynamic_types = int(value)
+ parts.append(f'{key} = {value}')
+ continue
+ except ValueError:
+ pass
+ if key == 'SKIP':
+ if value.startswith('REGEXP'):
+ value = 'REGEXP ' + value[6:]
+ else:
+ if not value.startswith("`"):
+ value = f'`{value}`'
+ skips.append(value)
+ else:
+ key = unescape_identifier(key)
+ typed_paths.append(key)
+ typed_types.append(get_from_name(value))
+ key = f'`{key}`'
+ parts.append(f'{key} {value}')
+ if typed_paths:
+ self.typed_paths = typed_paths
+ self.typed_types = typed_types
+ if skips:
+ self.skips = skips
+ if parts:
+ self._name_suffix = f'({", ".join(parts)})'
+
+ @property
+ def insert_name(self):
+ return 'String'
+
+ # pylint: disable=too-many-locals
+ def read_column(self, source: ByteSource, num_rows: int, ctx: QueryContext):
+ if source.read_uint64() != 0: # object serialization version, currently only 0 is recognized
+ raise DataError(f'unrecognized object serialization version, column `{ctx.column_name}`')
+ source.read_leb128() # the max number of dynamic paths. Used to preallocate storage in ClickHouse; we ignore it
+ dynamic_path_cnt = source.read_leb128()
+ dynamic_paths = [source.read_leb128_str() for _ in range(dynamic_path_cnt)]
+ for typed in self.typed_types:
+ typed.read_column_prefix(source, ctx)
+ dynamic_variants = [read_dynamic_prefix(source) for _ in range(dynamic_path_cnt)]
+ # C++ prefix read ends here
+
+ typed_columns = [ch_type.read_column_data(source, num_rows, ctx) for ch_type in self.typed_types]
+ dynamic_columns = [read_variant_column(dynamic_variants[ix], source, num_rows, ctx) for ix in range(dynamic_path_cnt)]
+ SHARED_DATA_TYPE.read_column_data(source, num_rows, ctx)
+ col = []
+ for row_num in range(num_rows):
+ top = {}
+ for ix, field in enumerate(self.typed_paths):
+ value = typed_columns[ix][row_num]
+ item = top
+ chain = field.split('.')
+ for key in chain[:-1]:
+ child = item.get(key)
+ if child is None:
+ child = {}
+ item[key] = child
+ item = child
+ item[chain[-1]] = value
+ for ix, field in enumerate(dynamic_paths):
+ value = dynamic_columns[ix][row_num]
+ if value is None:
+ continue
+ item = top
+ chain = field.split('.')
+ for key in chain[:-1]:
+ child = item.get(key)
+ if child is None:
+ child = {}
+ item[key] = child
+ item = child
+ item[chain[-1]] = value
+ col.append(top)
+ if self.read_format(ctx) == 'string':
+ return [any_to_json(v) for v in col]
+ return col
+
+
+# Note that this type is deprecated and should not be used, it included for temporary backward compatibility only
+class Object(ClickHouseType):
+ python_type = dict
+ # Native is a Python type (primitive, dict, array), string is an actual JSON string
+ valid_formats = 'string', 'native'
+ _data_size = json_sample_size
+ write_column_data = write_json
+
+ def __init__(self, type_def):
+ data_type = type_def.values[0].lower().replace(' ', '')
+ if data_type not in ("'json'", "nullable('json')"):
+ raise NotImplementedError('Only json or Nullable(json) Object type is currently supported')
+ super().__init__(type_def)
+ self._name_suffix = type_def.arg_str
+
+ def write_column_prefix(self, dest: bytearray):
+ dest.append(0x01)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/network.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/network.py
index 14b7bc3b9a..f44686367d 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/network.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/network.py
@@ -3,7 +3,7 @@ from ipaddress import IPv4Address, IPv6Address
from typing import Union, MutableSequence, Sequence
from clickhouse_connect.datatypes.base import ClickHouseType
-from clickhouse_connect.driver.common import write_array, int_size
+from clickhouse_connect.driver.common import write_array, int_size, first_value
from clickhouse_connect.driver.insert import InsertContext
from clickhouse_connect.driver.query import QueryContext
from clickhouse_connect.driver.types import ByteSource
@@ -29,7 +29,7 @@ class IPv4(ClickHouseType):
return data_conv.read_ipv4_col(source, num_rows)
def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext):
- first = self._first_value(column)
+ first = first_value(column, self.nullable)
if isinstance(first, str):
fixed = 24, 16, 8, 0
# pylint: disable=consider-using-generator
@@ -39,7 +39,7 @@ class IPv4(ClickHouseType):
column = [x._ip if x else 0 for x in column]
else:
column = [x._ip for x in column]
- write_array(self._array_type, column, dest)
+ write_array(self._array_type, column, dest, ctx.column_name)
def _active_null(self, ctx: QueryContext):
fmt = self.read_format(ctx)
@@ -103,7 +103,7 @@ class IPv6(ClickHouseType):
def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext):
v = V6_NULL
- first = self._first_value(column)
+ first = first_value(column, self.nullable)
v4mask = IPV4_V6_MASK
af6 = socket.AF_INET6
tov6 = socket.inet_pton
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/numeric.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/numeric.py
index 2cd9e5f105..0ff62b1dc2 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/numeric.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/numeric.py
@@ -4,7 +4,7 @@ from typing import Union, Type, Sequence, MutableSequence
from math import nan
from clickhouse_connect.datatypes.base import TypeDef, ArrayType, ClickHouseType
-from clickhouse_connect.driver.common import array_type, write_array, decimal_size, decimal_prec
+from clickhouse_connect.driver.common import array_type, write_array, decimal_size, decimal_prec, first_value
from clickhouse_connect.driver.ctypes import numpy_conv, data_conv
from clickhouse_connect.driver.insert import InsertContext
from clickhouse_connect.driver.options import pd, np
@@ -98,7 +98,7 @@ class BigInt(ClickHouseType, registered=False):
def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext):
if len(column) == 0:
return
- first = self._first_value(column)
+ first = first_value(column, self.nullable)
sz = self.byte_size
signed = self._signed
empty = bytes(b'\x00' * sz)
@@ -189,8 +189,8 @@ class Bool(ClickHouseType):
return np.array(column)
return column
- def _write_column_binary(self, column, dest, _ctx):
- write_array('B', [1 if x else 0 for x in column], dest)
+ def _write_column_binary(self, column, dest, ctx):
+ write_array('B', [1 if x else 0 for x in column], dest, ctx.column_name)
class Boolean(Bool):
@@ -218,15 +218,15 @@ class Enum(ClickHouseType):
lookup = self._int_map.get
return [lookup(x, None) for x in column]
- def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, _ctx):
- first = self._first_value(column)
+ def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx:InsertContext):
+ first = first_value(column, self.nullable)
if first is None or not isinstance(first, str):
if self.nullable:
column = [0 if not x else x for x in column]
- write_array(self._array_type, column, dest)
+ write_array(self._array_type, column, dest, ctx.column_name)
else:
lookup = self._name_map.get
- write_array(self._array_type, [lookup(x, 0) for x in column], dest)
+ write_array(self._array_type, [lookup(x, 0) for x in column], dest, ctx.column_name)
class Enum8(Enum):
@@ -285,15 +285,15 @@ class Decimal(ClickHouseType):
app(dec(f'-{digits[:-scale]}.{digits[-scale:]}'))
return new_col
- def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, _ctx):
- with decimal.localcontext() as ctx:
- ctx.prec = self.prec
+ def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx:InsertContext):
+ with decimal.localcontext() as dec_ctx:
+ dec_ctx.prec = self.prec
dec = decimal.Decimal
mult = self._mult
if self.nullable:
- write_array(self._array_type, [int(dec(str(x)) * mult) if x else 0 for x in column], dest)
+ write_array(self._array_type, [int(dec(str(x)) * mult) if x else 0 for x in column], dest, ctx.column_name)
else:
- write_array(self._array_type, [int(dec(str(x)) * mult) for x in column], dest)
+ write_array(self._array_type, [int(dec(str(x)) * mult) for x in column], dest, ctx.column_name)
def _active_null(self, ctx: QueryContext):
if ctx.use_none:
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/postinit.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/postinit.py
new file mode 100644
index 0000000000..3536c65195
--- /dev/null
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/postinit.py
@@ -0,0 +1,4 @@
+from clickhouse_connect.datatypes import registry, dynamic
+
+dynamic.SHARED_DATA_TYPE = registry.get_from_name('Array(String, String)')
+dynamic.STRING_DATA_TYPE = registry.get_from_name('String')
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/registry.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/registry.py
index 52d1036787..6fb20d8af6 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/registry.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/registry.py
@@ -35,6 +35,12 @@ def parse_name(name: str) -> Tuple[str, str, TypeDef]:
elif base.startswith('Tuple'):
keys, values = parse_columns(base[5:])
base = 'Tuple'
+ elif base.startswith('Variant'):
+ keys, values = parse_columns(base[7:])
+ base = 'Variant'
+ elif base.startswith('JSON') and len(base) > 4 and base[4] == '(':
+ keys, values = parse_columns(base[4:])
+ base = 'JSON'
elif base == 'Point':
values = ('Float64', 'Float64')
else:
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/special.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/special.py
index 29d28e3378..9d296d00fc 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/special.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/special.py
@@ -3,6 +3,7 @@ from uuid import UUID as PYUUID
from clickhouse_connect.datatypes.base import TypeDef, ClickHouseType, ArrayType, UnsupportedType
from clickhouse_connect.datatypes.registry import get_from_name
+from clickhouse_connect.driver.common import first_value
from clickhouse_connect.driver.ctypes import data_conv
from clickhouse_connect.driver.insert import InsertContext
from clickhouse_connect.driver.query import QueryContext
@@ -37,7 +38,7 @@ class UUID(ClickHouseType):
# pylint: disable=too-many-branches
def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext):
- first = self._first_value(column)
+ first = first_value(column, self.nullable)
empty = empty_uuid_b
if isinstance(first, str) or self.write_format(ctx) == 'string':
for v in column:
@@ -92,8 +93,8 @@ class SimpleAggregateFunction(ClickHouseType):
def _data_size(self, sample: Sequence) -> int:
return self.element_type.data_size(sample)
- def read_column_prefix(self, source: ByteSource):
- return self.element_type.read_column_prefix(source)
+ def read_column_prefix(self, source: ByteSource, ctx: QueryContext):
+ return self.element_type.read_column_prefix(source, ctx)
def write_column_prefix(self, dest: bytearray):
self.element_type.write_column_prefix(dest)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/string.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/string.py
index 3cfcd38630..4b7886510d 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/string.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/string.py
@@ -1,10 +1,10 @@
from typing import Sequence, MutableSequence, Union, Collection
+from clickhouse_connect.driver.common import first_value
from clickhouse_connect.driver.ctypes import data_conv
from clickhouse_connect.datatypes.base import ClickHouseType, TypeDef
from clickhouse_connect.driver.errors import handle_error
-from clickhouse_connect.driver.exceptions import DataError
from clickhouse_connect.driver.insert import InsertContext
from clickhouse_connect.driver.query import QueryContext
from clickhouse_connect.driver.types import ByteSource
@@ -45,9 +45,9 @@ class String(ClickHouseType):
def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext):
encoding = None
- if not isinstance(self._first_value(column), bytes):
+ if not isinstance(first_value(column, self.nullable), bytes):
encoding = ctx.encoding or self.encoding
- handle_error(data_conv.write_str_col(column, self.nullable, encoding, dest))
+ handle_error(data_conv.write_str_col(column, self.nullable, encoding, dest), ctx)
def _active_null(self, ctx):
if ctx.use_none:
@@ -92,7 +92,7 @@ class FixedString(ClickHouseType):
empty = bytes((0,) * sz)
str_enc = str.encode
enc = ctx.encoding or self.encoding
- first = self._first_value(column)
+ first = first_value(column, self.nullable)
if isinstance(first, str) or self.write_format(ctx) == 'string':
if self.nullable:
for x in column:
@@ -104,7 +104,7 @@ class FixedString(ClickHouseType):
except UnicodeEncodeError:
b = empty
if len(b) > sz:
- raise DataError(f'UTF-8 encoded FixedString value {b.hex(" ")} exceeds column size {sz}')
+ raise ctx.data_error(f'UTF-8 encoded FixedString value {b.hex(" ")} exceeds column size {sz}')
ext(b)
ext(empty[:sz - len(b)])
else:
@@ -114,7 +114,7 @@ class FixedString(ClickHouseType):
except UnicodeEncodeError:
b = empty
if len(b) > sz:
- raise DataError(f'UTF-8 encoded FixedString value {b.hex(" ")} exceeds column size {sz}')
+ raise ctx.data_error(f'UTF-8 encoded FixedString value {b.hex(" ")} exceeds column size {sz}')
ext(b)
ext(empty[:sz - len(b)])
elif self.nullable:
@@ -122,11 +122,11 @@ class FixedString(ClickHouseType):
if not b:
ext(empty)
elif len(b) != sz:
- raise DataError(f'Fixed String binary value {b.hex(" ")} does not match column size {sz}')
+ raise ctx.data_error(f'Fixed String binary value {b.hex(" ")} does not match column size {sz}')
else:
ext(b)
else:
for b in column:
if len(b) != sz:
- raise DataError(f'Fixed String binary value {b.hex(" ")} does not match column size {sz}')
+ raise ctx.data_error(f'Fixed String binary value {b.hex(" ")} does not match column size {sz}')
ext(b)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/temporal.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/temporal.py
index da672823b6..6359d5ba55 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/temporal.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/temporal.py
@@ -4,7 +4,7 @@ from datetime import date, datetime, tzinfo
from typing import Union, Sequence, MutableSequence
from clickhouse_connect.datatypes.base import TypeDef, ClickHouseType
-from clickhouse_connect.driver.common import write_array, np_date_types, int_size
+from clickhouse_connect.driver.common import write_array, np_date_types, int_size, first_value
from clickhouse_connect.driver.exceptions import ProgrammingError
from clickhouse_connect.driver.ctypes import data_conv, numpy_conv
from clickhouse_connect.driver.insert import InsertContext
@@ -32,7 +32,7 @@ class Date(ClickHouseType):
return data_conv.read_date_col(source, num_rows)
def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext):
- first = self._first_value(column)
+ first = first_value(column, self.nullable)
if isinstance(first, int) or self.write_format(ctx) == 'int':
if self.nullable:
column = [x if x else 0 for x in column]
@@ -45,7 +45,7 @@ class Date(ClickHouseType):
column = [0 if x is None else (x - esd).days for x in column]
else:
column = [(x - esd).days for x in column]
- write_array(self._array_type, column, dest)
+ write_array(self._array_type, column, dest, ctx.column_name)
def _active_null(self, ctx: QueryContext):
fmt = self.read_format(ctx)
@@ -127,7 +127,7 @@ class DateTime(DateTimeBase):
return data_conv.read_datetime_col(source, num_rows, active_tz)
def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext):
- first = self._first_value(column)
+ first = first_value(column, self.nullable)
if isinstance(first, int) or self.write_format(ctx) == 'int':
if self.nullable:
column = [x if x else 0 for x in column]
@@ -136,7 +136,7 @@ class DateTime(DateTimeBase):
column = [int(x.timestamp()) if x else 0 for x in column]
else:
column = [int(x.timestamp()) for x in column]
- write_array(self._array_type, column, dest)
+ write_array(self._array_type, column, dest, ctx.column_name)
class DateTime64(DateTimeBase):
@@ -202,7 +202,7 @@ class DateTime64(DateTimeBase):
return new_col
def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext):
- first = self._first_value(column)
+ first = first_value(column, self.nullable)
if isinstance(first, int) or self.write_format(ctx) == 'int':
if self.nullable:
column = [x if x else 0 for x in column]
@@ -213,4 +213,4 @@ class DateTime64(DateTimeBase):
for x in column]
else:
column = [((int(x.timestamp()) * 1000000 + x.microsecond) * prec) // 1000000 for x in column]
- write_array('q', column, dest)
+ write_array('q', column, dest, ctx.column_name)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/__init__.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/__init__.py
index 27e16733d8..fe3e4b3fbc 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/__init__.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/__init__.py
@@ -84,7 +84,7 @@ def create_client(*,
database = database or parsed.path
for k, v in parse_qs(parsed.query).items():
kwargs[k] = v[0]
- use_tls = str(secure).lower() == 'true' or interface == 'https' or (not interface and port in (443, 8443))
+ use_tls = str(secure).lower() == 'true' or interface == 'https' or (not interface and str(port) in ('443', '8443'))
if not host:
host = 'localhost'
if not interface:
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/asyncclient.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/asyncclient.py
index e2dc5b0118..bf56c9783f 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/asyncclient.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/asyncclient.py
@@ -13,7 +13,7 @@ from clickhouse_connect.datatypes.base import ClickHouseType
from clickhouse_connect.driver.insert import InsertContext
-# pylint: disable=too-many-public-methods, too-many-instance-attributes, too-many-arguments, too-many-locals
+# pylint: disable=too-many-public-methods,too-many-instance-attributes,too-many-arguments,too-many-positional-arguments,too-many-locals
class AsyncClient:
"""
AsyncClient is a wrapper around the ClickHouse Client object that allows for async calls to the ClickHouse server.
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/binding.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/binding.py
new file mode 100644
index 0000000000..24522b0880
--- /dev/null
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/binding.py
@@ -0,0 +1,199 @@
+import ipaddress
+import re
+import uuid
+from datetime import tzinfo, datetime, date
+from enum import Enum
+from typing import Optional, Union, Sequence, Dict, Any, Tuple
+
+import pytz
+
+from clickhouse_connect import common
+from clickhouse_connect.driver.common import dict_copy
+from clickhouse_connect.json_impl import any_to_json
+
+BS = '\\'
+must_escape = (BS, '\'', '`', '\t', '\n')
+external_bind_re = re.compile(r'{.+:.+}')
+
+
+class DT64Param:
+ def __init__(self, value: datetime):
+ self.value = value
+
+ def format(self, tz: tzinfo, top_level:bool) -> str:
+ value = self.value
+ if tz:
+ value = value.astimezone(tz)
+ s = value.strftime('%Y-%m-%d %H:%M:%S.%f')
+ if top_level:
+ return s
+ return f"'{s}'"
+
+
+def quote_identifier(identifier: str):
+ first_char = identifier[0]
+ if first_char in ('`', '"') and identifier[-1] == first_char:
+ # Identifier is already quoted, assume that it's valid
+ return identifier
+ return f'`{escape_str(identifier)}`'
+
+
+def finalize_query(query: str, parameters: Optional[Union[Sequence, Dict[str, Any]]],
+ server_tz: Optional[tzinfo] = None) -> str:
+ while query.endswith(';'):
+ query = query[:-1]
+ if not parameters:
+ return query
+ if hasattr(parameters, 'items'):
+ return query % {k: format_query_value(v, server_tz) for k, v in parameters.items()}
+ return query % tuple(format_query_value(v, server_tz) for v in parameters)
+
+
+# pylint: disable=too-many-locals,too-many-branches
+def bind_query(query: str, parameters: Optional[Union[Sequence, Dict[str, Any]]],
+ server_tz: Optional[tzinfo] = None) -> Tuple[str, Dict[str, str]]:
+ while query.endswith(';'):
+ query = query[:-1]
+ if not parameters:
+ return query, {}
+
+ binary_binds = None
+
+ if isinstance(parameters, dict):
+ params_copy = dict_copy(parameters)
+ binary_binds = {k: v for k, v in params_copy.items() if k.startswith('$') and k.endswith('$') and len(k) > 1}
+ for key in binary_binds.keys():
+ del params_copy[key]
+
+ final_params = {}
+ for k, v in params_copy.items():
+ if k.endswith('_64'):
+ if isinstance(v, datetime):
+ k = k[:-3]
+ v = DT64Param(v)
+ elif isinstance(v, list) and len(v) > 0 and isinstance(v[0], datetime):
+ k = k[:-3]
+ v = [DT64Param(x) for x in v]
+ final_params[k] = v
+ if external_bind_re.search(query) is None:
+ query, bound_params = finalize_query(query, final_params, server_tz), {}
+ else:
+ bound_params = {f'param_{k}': format_bind_value(v, server_tz) for k, v in final_params.items()}
+ else:
+ query, bound_params = finalize_query(query, parameters, server_tz), {}
+ if binary_binds:
+ binary_query = query.encode()
+ binary_indexes = {}
+ for k, v in binary_binds.items():
+ key = k.encode()
+ item_index = 0
+ while True:
+ item_index = binary_query.find(key, item_index)
+ if item_index == -1:
+ break
+ binary_indexes[item_index + len(key)] = key, v
+ item_index += len(key)
+ query = b''
+ start = 0
+ for loc in sorted(binary_indexes.keys()):
+ key, value = binary_indexes[loc]
+ query += binary_query[start:loc] + value + key
+ start = loc
+ query += binary_query[start:]
+ return query, bound_params
+
+
+def format_str(value: str):
+ return f"'{escape_str(value)}'"
+
+
+def escape_str(value: str):
+ return ''.join(f'{BS}{c}' if c in must_escape else c for c in value)
+
+
+# pylint: disable=too-many-return-statements
+def format_query_value(value: Any, server_tz: tzinfo = pytz.UTC):
+ """
+ Format Python values in a ClickHouse query
+ :param value: Python object
+ :param server_tz: Server timezone for adjusting datetime values
+ :return: Literal string for python value
+ """
+ if value is None:
+ return 'NULL'
+ if isinstance(value, str):
+ return format_str(value)
+ if isinstance(value, DT64Param):
+ return value.format(server_tz, False)
+ if isinstance(value, datetime):
+ if value.tzinfo is not None or server_tz != pytz.UTC:
+ value = value.astimezone(server_tz)
+ return f"'{value.strftime('%Y-%m-%d %H:%M:%S')}'"
+ if isinstance(value, date):
+ return f"'{value.isoformat()}'"
+ if isinstance(value, list):
+ return f"[{', '.join(str_query_value(x, server_tz) for x in value)}]"
+ if isinstance(value, tuple):
+ return f"({', '.join(str_query_value(x, server_tz) for x in value)})"
+ if isinstance(value, dict):
+ if common.get_setting('dict_parameter_format') == 'json':
+ return format_str(any_to_json(value).decode())
+ pairs = [str_query_value(k, server_tz) + ':' + str_query_value(v, server_tz)
+ for k, v in value.items()]
+ return f"{{{', '.join(pairs)}}}"
+ if isinstance(value, Enum):
+ return format_query_value(value.value, server_tz)
+ if isinstance(value, (uuid.UUID, ipaddress.IPv4Address, ipaddress.IPv6Address)):
+ return f"'{value}'"
+ return value
+
+
+def str_query_value(value: Any, server_tz: tzinfo = pytz.UTC):
+ return str(format_query_value(value, server_tz))
+
+
+# pylint: disable=too-many-branches
+def format_bind_value(value: Any, server_tz: tzinfo = pytz.UTC, top_level: bool = True):
+ """
+ Format Python values in a ClickHouse query
+ :param value: Python object
+ :param server_tz: Server timezone for adjusting datetime values
+ :param top_level: Flag for top level for nested structures
+ :return: Literal string for python value
+ """
+
+ def recurse(x):
+ return format_bind_value(x, server_tz, False)
+
+ if value is None:
+ return '\\N'
+ if isinstance(value, str):
+ if top_level:
+ # At the top levels, strings must not be surrounded by quotes
+ return escape_str(value)
+ return format_str(value)
+ if isinstance(value, DT64Param):
+ return value.format(server_tz, top_level)
+ if isinstance(value, datetime):
+ value = value.astimezone(server_tz)
+ val = value.strftime('%Y-%m-%d %H:%M:%S')
+ if top_level:
+ return val
+ return f"'{val}'"
+ if isinstance(value, date):
+ if top_level:
+ return value.isoformat()
+ return f"'{value.isoformat()}'"
+ if isinstance(value, list):
+ return f"[{', '.join(recurse(x) for x in value)}]"
+ if isinstance(value, tuple):
+ return f"({', '.join(recurse(x) for x in value)})"
+ if isinstance(value, dict):
+ if common.get_setting('dict_parameter_format') == 'json':
+ return any_to_json(value).decode()
+ pairs = [recurse(k) + ':' + recurse(v)
+ for k, v in value.items()]
+ return f"{{{', '.join(pairs)}}}"
+ if isinstance(value, Enum):
+ return recurse(value.value)
+ return str(value)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/client.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/client.py
index ba3873cbd8..fe11c27883 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/client.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/client.py
@@ -20,15 +20,15 @@ from clickhouse_connect.driver.external import ExternalData
from clickhouse_connect.driver.insert import InsertContext
from clickhouse_connect.driver.summary import QuerySummary
from clickhouse_connect.driver.models import ColumnDef, SettingDef, SettingStatus
-from clickhouse_connect.driver.query import QueryResult, to_arrow, to_arrow_batches, QueryContext, arrow_buffer, \
- quote_identifier
+from clickhouse_connect.driver.query import QueryResult, to_arrow, to_arrow_batches, QueryContext, arrow_buffer
+from clickhouse_connect.driver.binding import quote_identifier
io.DEFAULT_BUFFER_SIZE = 1024 * 256
logger = logging.getLogger(__name__)
arrow_str_setting = 'output_format_arrow_string_as_string'
-# pylint: disable=too-many-public-methods, too-many-instance-attributes
+# pylint: disable=too-many-public-methods,too-many-arguments,too-many-positional-arguments,too-many-instance-attributes
class Client(ABC):
"""
Base ClickHouse Connect client
@@ -93,6 +93,8 @@ class Client(ABC):
})
if test_data[8:16] == b'\x01\x01\x05check':
self.protocol_version = PROTOCOL_VERSION_WITH_LOW_CARD
+ if self._setting_status('date_time_input_format').is_writable:
+ self.set_client_setting('date_time_input_format', 'best_effort')
self.uri = uri
def _validate_settings(self, settings: Optional[Dict[str, Any]]) -> Dict[str, str]:
@@ -171,7 +173,7 @@ class Client(ABC):
:return: The string value of the setting, if it exists, or None
"""
- # pylint: disable=too-many-arguments,unused-argument,too-many-locals
+ # pylint: disable=unused-argument,too-many-locals
def query(self,
query: Optional[str] = None,
parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
@@ -303,7 +305,7 @@ class Client(ABC):
:return: io.IOBase stream/iterator for the result
"""
- # pylint: disable=duplicate-code,too-many-arguments,unused-argument
+ # pylint: disable=duplicate-code,unused-argument
def query_np(self,
query: Optional[str] = None,
parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
@@ -341,7 +343,7 @@ class Client(ABC):
"""
return self._context_query(locals(), use_numpy=True, streaming=True).np_stream
- # pylint: disable=duplicate-code,too-many-arguments,unused-argument
+ # pylint: disable=duplicate-code,unused-argument
def query_df(self,
query: Optional[str] = None,
parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
@@ -364,7 +366,7 @@ class Client(ABC):
"""
return self._context_query(locals(), use_numpy=True, as_pandas=True).df_result
- # pylint: disable=duplicate-code,too-many-arguments,unused-argument
+ # pylint: disable=duplicate-code,unused-argument
def query_df_stream(self,
query: Optional[str] = None,
parameters: Optional[Union[Sequence, Dict[str, Any]]] = None,
@@ -571,7 +573,6 @@ class Client(ABC):
:return: ClickHouse server is up and reachable
"""
- # pylint: disable=too-many-arguments
def insert(self,
table: Optional[str] = None,
data: Sequence[Sequence[Any]] = None,
@@ -777,11 +778,18 @@ class Client(ABC):
:param fmt: Valid clickhouse format
"""
+ @abstractmethod
def close(self):
"""
Subclass implementation to close the connection to the server/deallocate the client
"""
+ @abstractmethod
+ def close_connections(self):
+ """
+ Subclass implementation to disconnect all "re-used" client connections
+ """
+
def _context_query(self, lcls: dict, **overrides):
kwargs = lcls.copy()
kwargs.pop('self')
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/common.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/common.py
index dca0dc9317..404a09e867 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/common.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/common.py
@@ -7,6 +7,7 @@ from typing import Sequence, MutableSequence, Dict, Optional, Union, Generator
from clickhouse_connect.driver.exceptions import ProgrammingError, StreamClosedError, DataError
from clickhouse_connect.driver.types import Closable
+
# pylint: disable=invalid-name
must_swap = sys.byteorder == 'big'
int_size = array.array('i').itemsize
@@ -38,12 +39,13 @@ def array_type(size: int, signed: bool):
return code if signed else code.upper()
-def write_array(code: str, column: Sequence, dest: MutableSequence):
+def write_array(code: str, column: Sequence, dest: MutableSequence, col_name: Optional[str]=None):
"""
Write a column of native Python data matching the array.array code
:param code: Python array.array code matching the column data type
:param column: Column of native Python values
:param dest: Destination byte buffer
+ :param col_name: Optional column name for error tracking
"""
if len(column) and not isinstance(column[0], (int, float)):
if code in ('f', 'F', 'd', 'D'):
@@ -54,8 +56,11 @@ def write_array(code: str, column: Sequence, dest: MutableSequence):
buff = struct.Struct(f'<{len(column)}{code}')
dest += buff.pack(*column)
except (TypeError, OverflowError, struct.error) as ex:
- raise DataError('Unable to create Python array. This is usually caused by trying to insert None ' +
- 'values into a ClickHouse column that is not Nullable') from ex
+ col_msg = ''
+ if col_name:
+ col_msg = f' for source column `{col_name}`'
+ raise DataError(f'Unable to create Python array{col_msg}. This is usually caused by trying to insert None ' +
+ 'values into a ClickHouse column that is not Nullable') from ex
def write_uint64(value: int, dest: MutableSequence):
@@ -134,6 +139,14 @@ def coerce_bool(val: Optional[Union[str, bool]]):
return val is True or (isinstance(val, str) and val.lower() in ('true', '1', 'y', 'yes'))
+def first_value(column: Sequence, nullable:bool = True):
+ if nullable:
+ return next((x for x in column if x is not None), None)
+ if len(column):
+ return column[0]
+ return None
+
+
class SliceView(Sequence):
"""
Provides a view into a sequence rather than copying. Borrows liberally from
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/context.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/context.py
index ad2b0d38d1..00125a0bdd 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/context.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/context.py
@@ -36,6 +36,7 @@ class BaseQueryContext:
for type_name, fmt in fmt.items()}
self.query_formats = query_formats or {}
self.column_formats = column_formats or {}
+ self.column_name = None
self.encoding = encoding
self.use_numpy = use_numpy
self.use_extended_dtypes = use_extended_dtypes
@@ -43,6 +44,7 @@ class BaseQueryContext:
self._active_col_type_fmts = _empty_map
def start_column(self, name: str):
+ self.column_name = name
self._active_col_fmt = self.col_simple_formats.get(name)
self._active_col_type_fmts = self.col_type_formats.get(name, _empty_map)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/ctypes.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/ctypes.py
index e7bb607e68..39e5954c1f 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/ctypes.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/ctypes.py
@@ -46,4 +46,4 @@ def connect_numpy():
str(ex))
-connect_c_modules()
+# connect_c_modules()
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/errors.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/errors.py
index 0d37890b7e..e5b3b6466e 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/errors.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/errors.py
@@ -1,3 +1,4 @@
+from clickhouse_connect.driver.context import BaseQueryContext
from clickhouse_connect.driver.exceptions import DataError
@@ -8,6 +9,9 @@ NONE_IN_NULLABLE_COLUMN = 1
error_messages = {NONE_IN_NULLABLE_COLUMN: 'Invalid None value in non-Nullable column'}
-def handle_error(error_num: int):
+def handle_error(error_num: int, ctx: BaseQueryContext):
if error_num > 0:
- raise DataError(error_messages[error_num])
+ msg = error_messages[error_num]
+ if ctx.column_name:
+ msg = f'{msg}, column name: `{ctx.column_name}`'
+ raise DataError(msg)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/httpclient.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/httpclient.py
index bf3c0d863f..001c578b26 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/httpclient.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/httpclient.py
@@ -24,7 +24,8 @@ from clickhouse_connect.driver.external import ExternalData
from clickhouse_connect.driver.httputil import ResponseSource, get_pool_manager, get_response_data, \
default_pool_manager, get_proxy_manager, all_managers, check_env_proxy, check_conn_expiration
from clickhouse_connect.driver.insert import InsertContext
-from clickhouse_connect.driver.query import QueryResult, QueryContext, quote_identifier, bind_query
+from clickhouse_connect.driver.query import QueryResult, QueryContext
+from clickhouse_connect.driver.binding import quote_identifier, bind_query
from clickhouse_connect.driver.summary import QuerySummary
from clickhouse_connect.driver.transform import NativeTransform
@@ -44,7 +45,7 @@ class HttpClient(Client):
'enable_http_compression'}
_owns_pool_manager = False
- # pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements,unused-argument
+ # pylint: disable=too-many-positional-arguments,too-many-arguments,too-many-locals,too-many-branches,too-many-statements,unused-argument
def __init__(self,
interface: str,
host: str,
@@ -70,7 +71,8 @@ class HttpClient(Client):
server_host_name: Optional[str] = None,
apply_server_timezone: Optional[Union[str, bool]] = None,
show_clickhouse_errors: Optional[bool] = None,
- autogenerate_session_id: Optional[bool] = None):
+ autogenerate_session_id: Optional[bool] = None,
+ tls_mode: Optional[str] = None):
"""
Create an HTTP ClickHouse Connect client
See clickhouse_connect.get_client for parameters
@@ -80,20 +82,20 @@ class HttpClient(Client):
ch_settings = dict_copy(settings, self.params)
self.http = pool_mgr
if interface == 'https':
+ if isinstance(verify, str) and verify.lower() == 'proxy':
+ verify = True
+ tls_mode = tls_mode or 'proxy'
if not https_proxy:
https_proxy = check_env_proxy('https', host, port)
- if https_proxy and isinstance(verify, str) and verify.lower() == 'proxy':
- verify = 'proxy'
- else:
- verify = coerce_bool(verify)
- if client_cert and verify != 'proxy':
+ verify = coerce_bool(verify)
+ if client_cert and (tls_mode is None or tls_mode == 'mutual'):
if not username:
raise ProgrammingError('username parameter is required for Mutual TLS authentication')
self.headers['X-ClickHouse-User'] = username
self.headers['X-ClickHouse-SSL-Certificate-Auth'] = 'on'
# pylint: disable=too-many-boolean-expressions
if not self.http and (server_host_name or ca_cert or client_cert or not verify or https_proxy):
- options = {'verify': verify is not False}
+ options = {'verify': verify}
dict_add(options, 'ca_cert', ca_cert)
dict_add(options, 'client_cert', client_cert)
dict_add(options, 'client_cert_key', client_cert_key)
@@ -111,7 +113,7 @@ class HttpClient(Client):
else:
self.http = default_pool_manager()
- if (not client_cert or verify == 'proxy') and username:
+ if (not client_cert or tls_mode in ('strict', 'proxy')) and username:
self.headers['Authorization'] = 'Basic ' + b64encode(f'{username}:{password}'.encode()).decode()
self.headers['User-Agent'] = common.build_client_name(client_name)
self._read_format = self._write_format = 'Native'
@@ -157,7 +159,7 @@ class HttpClient(Client):
server_host_name=server_host_name,
apply_server_timezone=apply_server_timezone,
show_clickhouse_errors=show_clickhouse_errors)
- self.params = self._validate_settings(ch_settings)
+ self.params = dict_copy(self.params, self._validate_settings(ch_settings))
comp_setting = self._setting_status('enable_http_compression')
self._send_comp_setting = not comp_setting.is_set and comp_setting.is_writable
if comp_setting.is_set or comp_setting.is_writable:
@@ -195,7 +197,7 @@ class HttpClient(Client):
context.block_info = True
params.update(context.bind_params)
params.update(self._validate_settings(context.settings))
- if columns_only_re.search(context.uncommented_query):
+ if not context.is_insert and columns_only_re.search(context.uncommented_query):
response = self._raw_request(f'{context.final_query}\n FORMAT JSON',
params, headers, retries=self.query_retries)
json_result = json.loads(response.data)
@@ -513,6 +515,9 @@ class HttpClient(Client):
logger.debug('ping failed', exc_info=True)
return False
+ def close_connections(self):
+ self.http.clear()
+
def close(self):
if self._owns_pool_manager:
self.http.clear()
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/httputil.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/httputil.py
index 9a2b835c65..7dd73114e9 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/httputil.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/httputil.py
@@ -6,7 +6,8 @@ import os
import sys
import socket
import time
-from typing import Dict, Any, Optional
+from collections import deque
+from typing import Dict, Any, Optional, Tuple, Callable
import certifi
import lz4.frame
@@ -192,34 +193,56 @@ class ResponseSource:
def __init__(self, response: HTTPResponse, chunk_size: int = 1024 * 1024):
self.response = response
compression = response.headers.get('content-encoding')
+ decompress:Optional[Callable] = None
if compression == 'zstd':
zstd_decom = zstandard.ZstdDecompressor().decompressobj()
- def decompress():
- while True:
- chunk = response.read(chunk_size, decode_content=False)
- if not chunk:
- break
- yield zstd_decom.decompress(chunk)
+ def zstd_decompress(c: deque) -> Tuple[bytes, int]:
+ chunk = c.popleft()
+ return zstd_decom.decompress(chunk), len(chunk)
- self.gen = decompress()
+ decompress = zstd_decompress
elif compression == 'lz4':
lz4_decom = lz4.frame.LZ4FrameDecompressor()
- def decompress():
+ def lz_decompress(c: deque) -> Tuple[Optional[bytes], int]:
+ read_amt = 0
while lz4_decom.needs_input:
- data = self.response.read(chunk_size, decode_content=False)
+ data = c.popleft()
+ read_amt += len(data)
if lz4_decom.unused_data:
data = lz4_decom.unused_data + data
- if not data:
- return
- chunk = lz4_decom.decompress(data)
- if chunk:
- yield chunk
-
- self.gen = decompress()
- else:
- self.gen = response.stream(amt=chunk_size, decode_content=True)
+ return lz4_decom.decompress(data), read_amt
+ return None, 0
+
+ decompress = lz_decompress
+
+ buffer_size = common.get_setting('http_buffer_size')
+
+ def buffered():
+ chunks = deque()
+ done = False
+ current_size = 0
+ read_gen = response.read_chunked(chunk_size, decompress is None)
+ while True:
+ while not done and current_size < buffer_size:
+ chunk = next(read_gen, None)
+ if not chunk:
+ done = True
+ break
+ chunks.append(chunk)
+ current_size += len(chunk)
+ if len(chunks) == 0:
+ return
+ if decompress:
+ chunk, used = decompress(chunks)
+ current_size -= used
+ else:
+ chunk = chunks.popleft()
+ current_size -= len(chunk)
+ yield chunk
+
+ self.gen = buffered()
def close(self):
self.response.drain_conn()
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/insert.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/insert.py
index 39a306cdc4..8ca1ef9f22 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/insert.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/insert.py
@@ -2,12 +2,12 @@ import logging
from math import log
from typing import Iterable, Sequence, Optional, Any, Dict, NamedTuple, Generator, Union, TYPE_CHECKING
-from clickhouse_connect.driver.query import quote_identifier
+from clickhouse_connect.driver.binding import quote_identifier
from clickhouse_connect.driver.ctypes import data_conv
from clickhouse_connect.driver.context import BaseQueryContext
from clickhouse_connect.driver.options import np, pd, pd_time_test
-from clickhouse_connect.driver.exceptions import ProgrammingError
+from clickhouse_connect.driver.exceptions import ProgrammingError, DataError
if TYPE_CHECKING:
from clickhouse_connect.datatypes.base import ClickHouseType
@@ -198,3 +198,6 @@ class InsertContext(BaseQueryContext):
data[ix] = data[ix].tolist()
self.column_oriented = True
return data
+
+ def data_error(self, error_message: str) -> DataError:
+ return DataError(f"Failed to write column '{self.column_name}': {error_message}")
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/parser.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/parser.py
index acdf9510e0..02bdc03cd5 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/parser.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/parser.py
@@ -142,7 +142,7 @@ def parse_columns(expr: str):
pos += 1
else:
if level == 0:
- if char == ' ':
+ if char in (' ', '='):
if label and not named:
names.append(unescape_identifier(label))
label = ''
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/query.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/query.py
index c11e128ec6..54edbeff09 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/query.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/query.py
@@ -1,22 +1,18 @@
-import ipaddress
import logging
import re
-import uuid
import pytz
-from enum import Enum
from io import IOBase
from typing import Any, Tuple, Dict, Sequence, Optional, Union, Generator
-from datetime import date, datetime, tzinfo
+from datetime import tzinfo
from pytz.exceptions import UnknownTimeZoneError
-from clickhouse_connect import common
from clickhouse_connect.driver import tzutil
+from clickhouse_connect.driver.binding import bind_query
from clickhouse_connect.driver.common import dict_copy, empty_gen, StreamContext
from clickhouse_connect.driver.external import ExternalData
from clickhouse_connect.driver.types import Matrix, Closable
-from clickhouse_connect.json_impl import any_to_json
from clickhouse_connect.driver.exceptions import StreamClosedError, ProgrammingError
from clickhouse_connect.driver.options import check_arrow, pd_extended_dtypes
from clickhouse_connect.driver.context import BaseQueryContext
@@ -29,7 +25,6 @@ limit_re = re.compile(r'\s+LIMIT($|\s)', re.IGNORECASE)
select_re = re.compile(r'(^|\s)SELECT\s', re.IGNORECASE)
insert_re = re.compile(r'(^|\s)INSERT\s*INTO', re.IGNORECASE)
command_re = re.compile(r'(^\s*)(' + commands + r')\s', re.IGNORECASE)
-external_bind_re = re.compile(r'{.+:.+}')
# pylint: disable=too-many-instance-attributes
@@ -38,7 +33,7 @@ class QueryContext(BaseQueryContext):
Argument/parameter object for queries. This context is used to set thread/query specific formats
"""
- # pylint: disable=duplicate-code,too-many-arguments,too-many-locals
+ # pylint: disable=duplicate-code,too-many-arguments,too-many-positional-arguments,too-many-locals
def __init__(self,
query: Union[str, bytes] = '',
parameters: Optional[Dict[str, Any]] = None,
@@ -176,6 +171,7 @@ class QueryContext(BaseQueryContext):
return None
return active_tz
+ # pylint disable=too-many-positional-arguments
def updated_copy(self,
query: Optional[Union[str, bytes]] = None,
parameters: Optional[Dict[str, Any]] = None,
@@ -343,159 +339,6 @@ class QueryResult(Closable):
self._block_gen = None
-BS = '\\'
-must_escape = (BS, '\'', '`', '\t', '\n')
-
-
-def quote_identifier(identifier: str):
- first_char = identifier[0]
- if first_char in ('`', '"') and identifier[-1] == first_char:
- # Identifier is already quoted, assume that it's valid
- return identifier
- return f'`{escape_str(identifier)}`'
-
-
-def finalize_query(query: str, parameters: Optional[Union[Sequence, Dict[str, Any]]],
- server_tz: Optional[tzinfo] = None) -> str:
- while query.endswith(';'):
- query = query[:-1]
- if not parameters:
- return query
- if hasattr(parameters, 'items'):
- return query % {k: format_query_value(v, server_tz) for k, v in parameters.items()}
- return query % tuple(format_query_value(v) for v in parameters)
-
-
-def bind_query(query: str, parameters: Optional[Union[Sequence, Dict[str, Any]]],
- server_tz: Optional[tzinfo] = None) -> Tuple[str, Dict[str, str]]:
- while query.endswith(';'):
- query = query[:-1]
- if not parameters:
- return query, {}
-
- binary_binds = None
- if isinstance(parameters, dict):
- binary_binds = {k: v for k, v in parameters.items() if k.startswith('$') and k.endswith('$') and len(k) > 1}
- for key in binary_binds.keys():
- del parameters[key]
- if external_bind_re.search(query) is None:
- query, bound_params = finalize_query(query, parameters, server_tz), {}
- else:
- bound_params = {f'param_{k}': format_bind_value(v, server_tz) for k, v in parameters.items()}
- if binary_binds:
- binary_query = query.encode()
- binary_indexes = {}
- for k, v in binary_binds.items():
- key = k.encode()
- item_index = 0
- while True:
- item_index = binary_query.find(key, item_index)
- if item_index == -1:
- break
- binary_indexes[item_index + len(key)] = key, v
- item_index += len(key)
- query = b''
- start = 0
- for loc in sorted(binary_indexes.keys()):
- key, value = binary_indexes[loc]
- query += binary_query[start:loc] + value + key
- start = loc
- query += binary_query[start:]
- return query, bound_params
-
-
-def format_str(value: str):
- return f"'{escape_str(value)}'"
-
-
-def escape_str(value: str):
- return ''.join(f'{BS}{c}' if c in must_escape else c for c in value)
-
-
-# pylint: disable=too-many-return-statements
-def format_query_value(value: Any, server_tz: tzinfo = pytz.UTC):
- """
- Format Python values in a ClickHouse query
- :param value: Python object
- :param server_tz: Server timezone for adjusting datetime values
- :return: Literal string for python value
- """
- if value is None:
- return 'NULL'
- if isinstance(value, str):
- return format_str(value)
- if isinstance(value, datetime):
- if value.tzinfo is not None or server_tz != pytz.UTC:
- value = value.astimezone(server_tz)
- return f"'{value.strftime('%Y-%m-%d %H:%M:%S')}'"
- if isinstance(value, date):
- return f"'{value.isoformat()}'"
- if isinstance(value, list):
- return f"[{', '.join(str_query_value(x, server_tz) for x in value)}]"
- if isinstance(value, tuple):
- return f"({', '.join(str_query_value(x, server_tz) for x in value)})"
- if isinstance(value, dict):
- if common.get_setting('dict_parameter_format') == 'json':
- return format_str(any_to_json(value).decode())
- pairs = [str_query_value(k, server_tz) + ':' + str_query_value(v, server_tz)
- for k, v in value.items()]
- return f"{{{', '.join(pairs)}}}"
- if isinstance(value, Enum):
- return format_query_value(value.value, server_tz)
- if isinstance(value, (uuid.UUID, ipaddress.IPv4Address, ipaddress.IPv6Address)):
- return f"'{value}'"
- return value
-
-
-def str_query_value(value: Any, server_tz: tzinfo = pytz.UTC):
- return str(format_query_value(value, server_tz))
-
-
-# pylint: disable=too-many-branches
-def format_bind_value(value: Any, server_tz: tzinfo = pytz.UTC, top_level: bool = True):
- """
- Format Python values in a ClickHouse query
- :param value: Python object
- :param server_tz: Server timezone for adjusting datetime values
- :param top_level: Flag for top level for nested structures
- :return: Literal string for python value
- """
-
- def recurse(x):
- return format_bind_value(x, server_tz, False)
-
- if value is None:
- return '\\N'
- if isinstance(value, str):
- if top_level:
- # At the top levels, strings must not be surrounded by quotes
- return escape_str(value)
- return format_str(value)
- if isinstance(value, datetime):
- value = value.astimezone(server_tz)
- val = value.strftime('%Y-%m-%d %H:%M:%S')
- if top_level:
- return val
- return f"'{val}'"
- if isinstance(value, date):
- if top_level:
- return value.isoformat()
- return f"'{value.isoformat()}'"
- if isinstance(value, list):
- return f"[{', '.join(recurse(x) for x in value)}]"
- if isinstance(value, tuple):
- return f"({', '.join(recurse(x) for x in value)})"
- if isinstance(value, dict):
- if common.get_setting('dict_parameter_format') == 'json':
- return any_to_json(value).decode()
- pairs = [recurse(k) + ':' + recurse(v)
- for k, v in value.items()]
- return f"{{{', '.join(pairs)}}}"
- if isinstance(value, Enum):
- return recurse(value.value)
- return str(value)
-
-
comment_re = re.compile(r"(\".*?\"|\'.*?\')|(/\*.*?\*/|(--\s)[^\n]*$)", re.MULTILINE | re.DOTALL)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/tools.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/tools.py
index 54b4b45949..42480858d6 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/tools.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/tools.py
@@ -2,7 +2,7 @@ from typing import Optional, Sequence, Dict, Any
from clickhouse_connect.driver import Client
from clickhouse_connect.driver.summary import QuerySummary
-from clickhouse_connect.driver.query import quote_identifier
+from clickhouse_connect.driver.binding import quote_identifier
def insert_file(client: Client,
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/transform.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/transform.py
index 03206d0c85..1d20d9c6e7 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/transform.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/transform.py
@@ -96,7 +96,7 @@ class NativeTransform:
col_enc = col_name.encode()
write_leb128(len(col_enc), output)
output += col_enc
- col_enc = col_type.name.encode()
+ col_enc = col_type.insert_name.encode()
write_leb128(len(col_enc), output)
output += col_enc
context.start_column(col_name)
diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/tools/testing.py b/contrib/python/clickhouse-connect/clickhouse_connect/tools/testing.py
index 7084c71a40..56ced72501 100644
--- a/contrib/python/clickhouse-connect/clickhouse_connect/tools/testing.py
+++ b/contrib/python/clickhouse-connect/clickhouse_connect/tools/testing.py
@@ -1,7 +1,7 @@
from typing import Sequence, Optional, Union, Dict, Any
from clickhouse_connect.driver import Client
-from clickhouse_connect.driver.query import quote_identifier, str_query_value
+from clickhouse_connect.driver.binding import quote_identifier, str_query_value
class TableContext:
diff --git a/contrib/python/clickhouse-connect/ya.make b/contrib/python/clickhouse-connect/ya.make
index 0fe2ab62b4..467fc1f466 100644
--- a/contrib/python/clickhouse-connect/ya.make
+++ b/contrib/python/clickhouse-connect/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(0.7.19)
+VERSION(0.8.0)
LICENSE(Apache-2.0)
@@ -42,9 +42,11 @@ PY_SRCS(
clickhouse_connect/datatypes/__init__.py
clickhouse_connect/datatypes/base.py
clickhouse_connect/datatypes/container.py
+ clickhouse_connect/datatypes/dynamic.py
clickhouse_connect/datatypes/format.py
clickhouse_connect/datatypes/network.py
clickhouse_connect/datatypes/numeric.py
+ clickhouse_connect/datatypes/postinit.py
clickhouse_connect/datatypes/registry.py
clickhouse_connect/datatypes/special.py
clickhouse_connect/datatypes/string.py
@@ -54,6 +56,7 @@ PY_SRCS(
clickhouse_connect/dbapi/cursor.py
clickhouse_connect/driver/__init__.py
clickhouse_connect/driver/asyncclient.py
+ clickhouse_connect/driver/binding.py
clickhouse_connect/driver/buffer.py
clickhouse_connect/driver/client.py
clickhouse_connect/driver/common.py
diff --git a/contrib/python/fonttools/.dist-info/METADATA b/contrib/python/fonttools/.dist-info/METADATA
index 6694a8733c..419722ab40 100644
--- a/contrib/python/fonttools/.dist-info/METADATA
+++ b/contrib/python/fonttools/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: fonttools
-Version: 4.53.1
+Version: 4.54.1
Summary: Tools to manipulate font files
Home-page: http://github.com/fonttools/fonttools
Author: Just van Rossum
@@ -376,6 +376,28 @@ Have fun!
Changelog
~~~~~~~~~
+4.54.1 (released 2024-09-24)
+----------------------------
+
+- [unicodedata] Update to Unicode 16
+- [subset] Escape ``\\`` in doc string
+
+4.54.0 (released 2024-09-23)
+----------------------------
+
+- [Docs] Small docs cleanups by @n8willis (#3611)
+- [Docs] cleanup code blocks by @n8willis (#3627)
+- [Docs] fix Sphinx builds by @n8willis (#3625)
+- [merge] Minor fixes to documentation for merge by @drj11 (#3588)
+- [subset] Small tweaks to pyftsubset documentation by @RoelN (#3633)
+- [Tests] Do not require fonttools command to be available by @behdad (#3612)
+- [Tests] subset_test: add failing test to reproduce issue #3616 by @anthrotype (#3622)
+- [ttLib] NameRecordVisitor: include whole sequence of character variants' UI labels, not just the first by @anthrotype (#3617)
+- [varLib.avar] Reconstruct mappings from binary by @behdad (#3598)
+- [varLib.instancer] Fix visual artefacts with partial L2 instancing by @Hoolean (#3635)
+- [varLib.interpolatable] Support discrete axes in .designspace by @behdad (#3599)
+- [varLib.models] By default, assume OpenType-like normalized space by @behdad (#3601)
+
4.53.1 (released 2024-07-05)
----------------------------
diff --git a/contrib/python/fonttools/fontTools/__init__.py b/contrib/python/fonttools/fontTools/__init__.py
index f2c62f124b..0ec8b4ecfd 100644
--- a/contrib/python/fonttools/fontTools/__init__.py
+++ b/contrib/python/fonttools/fontTools/__init__.py
@@ -3,6 +3,6 @@ from fontTools.misc.loggingTools import configLogger
log = logging.getLogger(__name__)
-version = __version__ = "4.53.1"
+version = __version__ = "4.54.1"
__all__ = ["version", "log", "configLogger"]
diff --git a/contrib/python/fonttools/fontTools/designspaceLib/__init__.py b/contrib/python/fonttools/fontTools/designspaceLib/__init__.py
index 342f1decd5..0a1e782f57 100644
--- a/contrib/python/fonttools/fontTools/designspaceLib/__init__.py
+++ b/contrib/python/fonttools/fontTools/designspaceLib/__init__.py
@@ -1,3 +1,9 @@
+"""
+ designSpaceDocument
+
+ - Read and write designspace files
+"""
+
from __future__ import annotations
import collections
@@ -15,11 +21,6 @@ from fontTools.misc import plistlib
from fontTools.misc.loggingTools import LogMixin
from fontTools.misc.textTools import tobytes, tostr
-"""
- designSpaceDocument
-
- - read and write designspace files
-"""
__all__ = [
"AxisDescriptor",
diff --git a/contrib/python/fonttools/fontTools/merge/__init__.py b/contrib/python/fonttools/fontTools/merge/__init__.py
index 7653e4a079..3f5875c586 100644
--- a/contrib/python/fonttools/fontTools/merge/__init__.py
+++ b/contrib/python/fonttools/fontTools/merge/__init__.py
@@ -27,24 +27,24 @@ class Merger(object):
This class merges multiple files into a single OpenType font, taking into
account complexities such as OpenType layout (``GSUB``/``GPOS``) tables and
- cross-font metrics (e.g. ``hhea.ascent`` is set to the maximum value across
- all the fonts).
+ cross-font metrics (for example ``hhea.ascent`` is set to the maximum value
+ across all the fonts).
If multiple glyphs map to the same Unicode value, and the glyphs are considered
sufficiently different (that is, they differ in any of paths, widths, or
height), then subsequent glyphs are renamed and a lookup in the ``locl``
feature will be created to disambiguate them. For example, if the arguments
are an Arabic font and a Latin font and both contain a set of parentheses,
- the Latin glyphs will be renamed to ``parenleft#1`` and ``parenright#1``,
+ the Latin glyphs will be renamed to ``parenleft.1`` and ``parenright.1``,
and a lookup will be inserted into the to ``locl`` feature (creating it if
necessary) under the ``latn`` script to substitute ``parenleft`` with
- ``parenleft#1`` etc.
+ ``parenleft.1`` etc.
Restrictions:
- All fonts must have the same units per em.
- If duplicate glyph disambiguation takes place as described above then the
- fonts must have a ``GSUB`` table.
+ fonts must have a ``GSUB`` table.
Attributes:
options: Currently unused.
diff --git a/contrib/python/fonttools/fontTools/pens/freetypePen.py b/contrib/python/fonttools/fontTools/pens/freetypePen.py
index 870776bc7b..065da932a2 100644
--- a/contrib/python/fonttools/fontTools/pens/freetypePen.py
+++ b/contrib/python/fonttools/fontTools/pens/freetypePen.py
@@ -46,7 +46,7 @@ class FreeTypePen(BasePen):
glyphSet: a dictionary of drawable glyph objects keyed by name
used to resolve component references in composite glyphs.
- :Examples:
+ Examples:
If `numpy` and `matplotlib` is available, the following code will
show the glyph image of `fi` in a new window::
@@ -178,7 +178,7 @@ class FreeTypePen(BasePen):
object of the resulted bitmap and ``size`` is a 2-tuple of its
dimension.
- :Notes:
+ Notes:
The image size should always be given explicitly if you need to get
a proper glyph image. When ``width`` and ``height`` are omitted, it
forcifully fits to the bounding box and the side bearings get
@@ -188,15 +188,15 @@ class FreeTypePen(BasePen):
maintained but RSB won’t. The difference between the two becomes
more obvious when rotate or skew transformation is applied.
- :Example:
- .. code-block::
+ Example:
+ .. code-block:: pycon
+ >>>
>> pen = FreeTypePen(None)
>> glyph.draw(pen)
>> buf, size = pen.buffer(width=500, height=1000)
>> type(buf), len(buf), size
(<class 'bytes'>, 500000, (500, 1000))
-
"""
transform = transform or Transform()
if not hasattr(transform, "transformPoint"):
@@ -269,7 +269,7 @@ class FreeTypePen(BasePen):
A ``numpy.ndarray`` object with a shape of ``(height, width)``.
Each element takes a value in the range of ``[0.0, 1.0]``.
- :Notes:
+ Notes:
The image size should always be given explicitly if you need to get
a proper glyph image. When ``width`` and ``height`` are omitted, it
forcifully fits to the bounding box and the side bearings get
@@ -279,15 +279,17 @@ class FreeTypePen(BasePen):
maintained but RSB won’t. The difference between the two becomes
more obvious when rotate or skew transformation is applied.
- :Example:
- .. code-block::
+ Example:
+ .. code-block:: pycon
+ >>>
>> pen = FreeTypePen(None)
>> glyph.draw(pen)
>> arr = pen.array(width=500, height=1000)
>> type(a), a.shape
(<class 'numpy.ndarray'>, (1000, 500))
"""
+
import numpy as np
buf, size = self.buffer(
@@ -318,7 +320,7 @@ class FreeTypePen(BasePen):
rendering glyphs with negative sidebearings without clipping.
evenOdd: Pass ``True`` for even-odd fill instead of non-zero.
- :Notes:
+ Notes:
The image size should always be given explicitly if you need to get
a proper glyph image. When ``width`` and ``height`` are omitted, it
forcifully fits to the bounding box and the side bearings get
@@ -328,9 +330,10 @@ class FreeTypePen(BasePen):
maintained but RSB won’t. The difference between the two becomes
more obvious when rotate or skew transformation is applied.
- :Example:
- .. code-block::
+ Example:
+ .. code-block:: pycon
+ >>>
>> pen = FreeTypePen(None)
>> glyph.draw(pen)
>> pen.show(width=500, height=1000)
@@ -370,7 +373,7 @@ class FreeTypePen(BasePen):
A ``PIL.image`` object. The image is filled in black with alpha
channel obtained from the rendered bitmap.
- :Notes:
+ Notes:
The image size should always be given explicitly if you need to get
a proper glyph image. When ``width`` and ``height`` are omitted, it
forcifully fits to the bounding box and the side bearings get
@@ -380,9 +383,10 @@ class FreeTypePen(BasePen):
maintained but RSB won’t. The difference between the two becomes
more obvious when rotate or skew transformation is applied.
- :Example:
- .. code-block::
+ Example:
+ .. code-block:: pycon
+ >>>
>> pen = FreeTypePen(None)
>> glyph.draw(pen)
>> img = pen.image(width=500, height=1000)
diff --git a/contrib/python/fonttools/fontTools/pens/pointInsidePen.py b/contrib/python/fonttools/fontTools/pens/pointInsidePen.py
index e1fbbbcb1d..0c022d31bc 100644
--- a/contrib/python/fonttools/fontTools/pens/pointInsidePen.py
+++ b/contrib/python/fonttools/fontTools/pens/pointInsidePen.py
@@ -15,7 +15,8 @@ class PointInsidePen(BasePen):
Instances of this class can be recycled, as long as the
setTestPoint() method is used to set the new point to test.
- Typical usage:
+ :Example:
+ .. code-block::
pen = PointInsidePen(glyphSet, (100, 200))
outline.draw(pen)
diff --git a/contrib/python/fonttools/fontTools/pens/recordingPen.py b/contrib/python/fonttools/fontTools/pens/recordingPen.py
index ba165e1951..b8a817ccf4 100644
--- a/contrib/python/fonttools/fontTools/pens/recordingPen.py
+++ b/contrib/python/fonttools/fontTools/pens/recordingPen.py
@@ -33,6 +33,7 @@ class RecordingPen(AbstractPen):
pen.replay(otherPen).
:Example:
+ .. code-block::
from fontTools.ttLib import TTFont
from fontTools.pens.recordingPen import RecordingPen
@@ -91,47 +92,48 @@ class DecomposingRecordingPen(DecomposingPen, RecordingPen):
by thir name; other arguments are forwarded to the DecomposingPen's
constructor::
- >>> class SimpleGlyph(object):
- ... def draw(self, pen):
- ... pen.moveTo((0, 0))
- ... pen.curveTo((1, 1), (2, 2), (3, 3))
- ... pen.closePath()
- >>> class CompositeGlyph(object):
- ... def draw(self, pen):
- ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
- >>> class MissingComponent(object):
- ... def draw(self, pen):
- ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
- >>> class FlippedComponent(object):
- ... def draw(self, pen):
- ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
- >>> glyphSet = {
- ... 'a': SimpleGlyph(),
- ... 'b': CompositeGlyph(),
- ... 'c': MissingComponent(),
- ... 'd': FlippedComponent(),
- ... }
- >>> for name, glyph in sorted(glyphSet.items()):
- ... pen = DecomposingRecordingPen(glyphSet)
- ... try:
- ... glyph.draw(pen)
- ... except pen.MissingComponentError:
- ... pass
- ... print("{}: {}".format(name, pen.value))
- a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
- b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
- c: []
- d: [('moveTo', ((0, 0),)), ('curveTo', ((-1, 1), (-2, 2), (-3, 3))), ('closePath', ())]
- >>> for name, glyph in sorted(glyphSet.items()):
- ... pen = DecomposingRecordingPen(
- ... glyphSet, skipMissingComponents=True, reverseFlipped=True,
- ... )
- ... glyph.draw(pen)
- ... print("{}: {}".format(name, pen.value))
- a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
- b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
- c: []
- d: [('moveTo', ((0, 0),)), ('lineTo', ((-3, 3),)), ('curveTo', ((-2, 2), (-1, 1), (0, 0))), ('closePath', ())]
+ >>> class SimpleGlyph(object):
+ ... def draw(self, pen):
+ ... pen.moveTo((0, 0))
+ ... pen.curveTo((1, 1), (2, 2), (3, 3))
+ ... pen.closePath()
+ >>> class CompositeGlyph(object):
+ ... def draw(self, pen):
+ ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
+ >>> class MissingComponent(object):
+ ... def draw(self, pen):
+ ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
+ >>> class FlippedComponent(object):
+ ... def draw(self, pen):
+ ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
+ >>> glyphSet = {
+ ... 'a': SimpleGlyph(),
+ ... 'b': CompositeGlyph(),
+ ... 'c': MissingComponent(),
+ ... 'd': FlippedComponent(),
+ ... }
+ >>> for name, glyph in sorted(glyphSet.items()):
+ ... pen = DecomposingRecordingPen(glyphSet)
+ ... try:
+ ... glyph.draw(pen)
+ ... except pen.MissingComponentError:
+ ... pass
+ ... print("{}: {}".format(name, pen.value))
+ a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
+ b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
+ c: []
+ d: [('moveTo', ((0, 0),)), ('curveTo', ((-1, 1), (-2, 2), (-3, 3))), ('closePath', ())]
+
+ >>> for name, glyph in sorted(glyphSet.items()):
+ ... pen = DecomposingRecordingPen(
+ ... glyphSet, skipMissingComponents=True, reverseFlipped=True,
+ ... )
+ ... glyph.draw(pen)
+ ... print("{}: {}".format(name, pen.value))
+ a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
+ b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
+ c: []
+ d: [('moveTo', ((0, 0),)), ('lineTo', ((-3, 3),)), ('curveTo', ((-2, 2), (-1, 1), (0, 0))), ('closePath', ())]
"""
# raises MissingComponentError(KeyError) if base glyph is not found in glyphSet
@@ -145,6 +147,7 @@ class RecordingPointPen(AbstractPointPen):
pointPen.replay(otherPointPen).
:Example:
+ .. code-block::
from defcon import Font
from fontTools.pens.recordingPen import RecordingPointPen
@@ -211,81 +214,82 @@ class DecomposingRecordingPointPen(DecomposingPointPen, RecordingPointPen):
keyed by thir name; other arguments are forwarded to the DecomposingPointPen's
constructor::
- >>> from pprint import pprint
- >>> class SimpleGlyph(object):
- ... def drawPoints(self, pen):
- ... pen.beginPath()
- ... pen.addPoint((0, 0), "line")
- ... pen.addPoint((1, 1))
- ... pen.addPoint((2, 2))
- ... pen.addPoint((3, 3), "curve")
- ... pen.endPath()
- >>> class CompositeGlyph(object):
- ... def drawPoints(self, pen):
- ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
- >>> class MissingComponent(object):
- ... def drawPoints(self, pen):
- ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
- >>> class FlippedComponent(object):
- ... def drawPoints(self, pen):
- ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
- >>> glyphSet = {
- ... 'a': SimpleGlyph(),
- ... 'b': CompositeGlyph(),
- ... 'c': MissingComponent(),
- ... 'd': FlippedComponent(),
- ... }
- >>> for name, glyph in sorted(glyphSet.items()):
- ... pen = DecomposingRecordingPointPen(glyphSet)
- ... try:
- ... glyph.drawPoints(pen)
- ... except pen.MissingComponentError:
- ... pass
- ... pprint({name: pen.value})
- {'a': [('beginPath', (), {}),
- ('addPoint', ((0, 0), 'line', False, None), {}),
- ('addPoint', ((1, 1), None, False, None), {}),
- ('addPoint', ((2, 2), None, False, None), {}),
- ('addPoint', ((3, 3), 'curve', False, None), {}),
- ('endPath', (), {})]}
- {'b': [('beginPath', (), {}),
- ('addPoint', ((-1, 1), 'line', False, None), {}),
- ('addPoint', ((0, 2), None, False, None), {}),
- ('addPoint', ((1, 3), None, False, None), {}),
- ('addPoint', ((2, 4), 'curve', False, None), {}),
- ('endPath', (), {})]}
- {'c': []}
- {'d': [('beginPath', (), {}),
- ('addPoint', ((0, 0), 'line', False, None), {}),
- ('addPoint', ((-1, 1), None, False, None), {}),
- ('addPoint', ((-2, 2), None, False, None), {}),
- ('addPoint', ((-3, 3), 'curve', False, None), {}),
- ('endPath', (), {})]}
- >>> for name, glyph in sorted(glyphSet.items()):
- ... pen = DecomposingRecordingPointPen(
- ... glyphSet, skipMissingComponents=True, reverseFlipped=True,
- ... )
- ... glyph.drawPoints(pen)
- ... pprint({name: pen.value})
- {'a': [('beginPath', (), {}),
- ('addPoint', ((0, 0), 'line', False, None), {}),
- ('addPoint', ((1, 1), None, False, None), {}),
- ('addPoint', ((2, 2), None, False, None), {}),
- ('addPoint', ((3, 3), 'curve', False, None), {}),
- ('endPath', (), {})]}
- {'b': [('beginPath', (), {}),
- ('addPoint', ((-1, 1), 'line', False, None), {}),
- ('addPoint', ((0, 2), None, False, None), {}),
- ('addPoint', ((1, 3), None, False, None), {}),
- ('addPoint', ((2, 4), 'curve', False, None), {}),
- ('endPath', (), {})]}
- {'c': []}
- {'d': [('beginPath', (), {}),
- ('addPoint', ((0, 0), 'curve', False, None), {}),
- ('addPoint', ((-3, 3), 'line', False, None), {}),
- ('addPoint', ((-2, 2), None, False, None), {}),
- ('addPoint', ((-1, 1), None, False, None), {}),
- ('endPath', (), {})]}
+ >>> from pprint import pprint
+ >>> class SimpleGlyph(object):
+ ... def drawPoints(self, pen):
+ ... pen.beginPath()
+ ... pen.addPoint((0, 0), "line")
+ ... pen.addPoint((1, 1))
+ ... pen.addPoint((2, 2))
+ ... pen.addPoint((3, 3), "curve")
+ ... pen.endPath()
+ >>> class CompositeGlyph(object):
+ ... def drawPoints(self, pen):
+ ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
+ >>> class MissingComponent(object):
+ ... def drawPoints(self, pen):
+ ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
+ >>> class FlippedComponent(object):
+ ... def drawPoints(self, pen):
+ ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
+ >>> glyphSet = {
+ ... 'a': SimpleGlyph(),
+ ... 'b': CompositeGlyph(),
+ ... 'c': MissingComponent(),
+ ... 'd': FlippedComponent(),
+ ... }
+ >>> for name, glyph in sorted(glyphSet.items()):
+ ... pen = DecomposingRecordingPointPen(glyphSet)
+ ... try:
+ ... glyph.drawPoints(pen)
+ ... except pen.MissingComponentError:
+ ... pass
+ ... pprint({name: pen.value})
+ {'a': [('beginPath', (), {}),
+ ('addPoint', ((0, 0), 'line', False, None), {}),
+ ('addPoint', ((1, 1), None, False, None), {}),
+ ('addPoint', ((2, 2), None, False, None), {}),
+ ('addPoint', ((3, 3), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+ {'b': [('beginPath', (), {}),
+ ('addPoint', ((-1, 1), 'line', False, None), {}),
+ ('addPoint', ((0, 2), None, False, None), {}),
+ ('addPoint', ((1, 3), None, False, None), {}),
+ ('addPoint', ((2, 4), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+ {'c': []}
+ {'d': [('beginPath', (), {}),
+ ('addPoint', ((0, 0), 'line', False, None), {}),
+ ('addPoint', ((-1, 1), None, False, None), {}),
+ ('addPoint', ((-2, 2), None, False, None), {}),
+ ('addPoint', ((-3, 3), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+
+ >>> for name, glyph in sorted(glyphSet.items()):
+ ... pen = DecomposingRecordingPointPen(
+ ... glyphSet, skipMissingComponents=True, reverseFlipped=True,
+ ... )
+ ... glyph.drawPoints(pen)
+ ... pprint({name: pen.value})
+ {'a': [('beginPath', (), {}),
+ ('addPoint', ((0, 0), 'line', False, None), {}),
+ ('addPoint', ((1, 1), None, False, None), {}),
+ ('addPoint', ((2, 2), None, False, None), {}),
+ ('addPoint', ((3, 3), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+ {'b': [('beginPath', (), {}),
+ ('addPoint', ((-1, 1), 'line', False, None), {}),
+ ('addPoint', ((0, 2), None, False, None), {}),
+ ('addPoint', ((1, 3), None, False, None), {}),
+ ('addPoint', ((2, 4), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+ {'c': []}
+ {'d': [('beginPath', (), {}),
+ ('addPoint', ((0, 0), 'curve', False, None), {}),
+ ('addPoint', ((-3, 3), 'line', False, None), {}),
+ ('addPoint', ((-2, 2), None, False, None), {}),
+ ('addPoint', ((-1, 1), None, False, None), {}),
+ ('endPath', (), {})]}
"""
# raises MissingComponentError(KeyError) if base glyph is not found in glyphSet
diff --git a/contrib/python/fonttools/fontTools/pens/svgPathPen.py b/contrib/python/fonttools/fontTools/pens/svgPathPen.py
index 29d41a8029..29d128da36 100644
--- a/contrib/python/fonttools/fontTools/pens/svgPathPen.py
+++ b/contrib/python/fonttools/fontTools/pens/svgPathPen.py
@@ -9,27 +9,30 @@ def pointToString(pt, ntos=str):
class SVGPathPen(BasePen):
"""Pen to draw SVG path d commands.
- Example::
- >>> pen = SVGPathPen(None)
- >>> pen.moveTo((0, 0))
- >>> pen.lineTo((1, 1))
- >>> pen.curveTo((2, 2), (3, 3), (4, 4))
- >>> pen.closePath()
- >>> pen.getCommands()
- 'M0 0 1 1C2 2 3 3 4 4Z'
-
Args:
glyphSet: a dictionary of drawable glyph objects keyed by name
used to resolve component references in composite glyphs.
ntos: a callable that takes a number and returns a string, to
customize how numbers are formatted (default: str).
+ :Example:
+ .. code-block::
+
+ >>> pen = SVGPathPen(None)
+ >>> pen.moveTo((0, 0))
+ >>> pen.lineTo((1, 1))
+ >>> pen.curveTo((2, 2), (3, 3), (4, 4))
+ >>> pen.closePath()
+ >>> pen.getCommands()
+ 'M0 0 1 1C2 2 3 3 4 4Z'
+
Note:
Fonts have a coordinate system where Y grows up, whereas in SVG,
Y grows down. As such, rendering path data from this pen in
SVG typically results in upside-down glyphs. You can fix this
by wrapping the data from this pen in an SVG group element with
transform, or wrap this pen in a transform pen. For example:
+ .. code-block:: python
spen = svgPathPen.SVGPathPen(glyphset)
pen= TransformPen(spen , (1, 0, 0, -1, 0, 0))
diff --git a/contrib/python/fonttools/fontTools/pens/transformPen.py b/contrib/python/fonttools/fontTools/pens/transformPen.py
index ff98dbddb0..3db6efdf2f 100644
--- a/contrib/python/fonttools/fontTools/pens/transformPen.py
+++ b/contrib/python/fonttools/fontTools/pens/transformPen.py
@@ -58,22 +58,27 @@ class TransformPointPen(FilterPointPen):
"""PointPen that transforms all coordinates using a Affine transformation,
and passes them to another PointPen.
- >>> from fontTools.pens.recordingPen import RecordingPointPen
- >>> rec = RecordingPointPen()
- >>> pen = TransformPointPen(rec, (2, 0, 0, 2, -10, 5))
- >>> v = iter(rec.value)
- >>> pen.beginPath(identifier="contour-0")
- >>> next(v)
- ('beginPath', (), {'identifier': 'contour-0'})
- >>> pen.addPoint((100, 100), "line")
- >>> next(v)
- ('addPoint', ((190, 205), 'line', False, None), {})
- >>> pen.endPath()
- >>> next(v)
- ('endPath', (), {})
- >>> pen.addComponent("a", (1, 0, 0, 1, -10, 5), identifier="component-0")
- >>> next(v)
- ('addComponent', ('a', <Transform [2 0 0 2 -30 15]>), {'identifier': 'component-0'})
+ For example::
+
+ >>> from fontTools.pens.recordingPen import RecordingPointPen
+ >>> rec = RecordingPointPen()
+ >>> pen = TransformPointPen(rec, (2, 0, 0, 2, -10, 5))
+ >>> v = iter(rec.value)
+ >>> pen.beginPath(identifier="contour-0")
+ >>> next(v)
+ ('beginPath', (), {'identifier': 'contour-0'})
+
+ >>> pen.addPoint((100, 100), "line")
+ >>> next(v)
+ ('addPoint', ((190, 205), 'line', False, None), {})
+
+ >>> pen.endPath()
+ >>> next(v)
+ ('endPath', (), {})
+
+ >>> pen.addComponent("a", (1, 0, 0, 1, -10, 5), identifier="component-0")
+ >>> next(v)
+ ('addComponent', ('a', <Transform [2 0 0 2 -30 15]>), {'identifier': 'component-0'})
"""
def __init__(self, outPointPen, transformation):
diff --git a/contrib/python/fonttools/fontTools/subset/__init__.py b/contrib/python/fonttools/fontTools/subset/__init__.py
index 4aa60ad842..99556d49e1 100644
--- a/contrib/python/fonttools/fontTools/subset/__init__.py
+++ b/contrib/python/fonttools/fontTools/subset/__init__.py
@@ -122,15 +122,16 @@ Other options
^^^^^^^^^^^^^
For the other options listed below, to see the current value of the option,
-pass a value of '?' to it, with or without a '='.
+pass a value of '?' to it, with or without a '='. In some environments,
+you might need to escape the question mark, like this: '--glyph-names\\?'.
Examples::
$ pyftsubset --glyph-names?
Current setting for 'glyph-names' is: False
- $ ./pyftsubset --name-IDs=?
+ $ pyftsubset --name-IDs=?
Current setting for 'name-IDs' is: [0, 1, 2, 3, 4, 5, 6]
- $ ./pyftsubset --hinting? --no-hinting --hinting?
+ $ pyftsubset --hinting? --no-hinting --hinting?
Current setting for 'hinting' is: True
Current setting for 'hinting' is: False
diff --git a/contrib/python/fonttools/fontTools/svgLib/path/__init__.py b/contrib/python/fonttools/fontTools/svgLib/path/__init__.py
index 742bc64ce0..043b4dbe1d 100644
--- a/contrib/python/fonttools/fontTools/svgLib/path/__init__.py
+++ b/contrib/python/fonttools/fontTools/svgLib/path/__init__.py
@@ -14,6 +14,8 @@ class SVGPath(object):
For example, reading from an SVG file and drawing to a Defcon Glyph:
+ .. code-block::
+
import defcon
glyph = defcon.Glyph()
pen = glyph.getPen()
@@ -23,6 +25,8 @@ class SVGPath(object):
Or reading from a string containing SVG data, using the alternative
'fromstring' (a class method):
+ .. code-block::
+
data = '<?xml version="1.0" ...'
svg = SVGPath.fromstring(data)
svg.draw(pen)
diff --git a/contrib/python/fonttools/fontTools/svgLib/path/parser.py b/contrib/python/fonttools/fontTools/svgLib/path/parser.py
index fa53474558..18c8e77f7f 100644
--- a/contrib/python/fonttools/fontTools/svgLib/path/parser.py
+++ b/contrib/python/fonttools/fontTools/svgLib/path/parser.py
@@ -103,6 +103,8 @@ def parse_path(pathdef, pen, current_pos=(0, 0), arc_class=EllipticalArc):
If the pen has an "arcTo" method, it is called with the original values
of the elliptical arc curve commands:
+ .. code-block::
+
pen.arcTo(rx, ry, rotation, arc_large, arc_sweep, (x, y))
Otherwise, the arcs are approximated by series of cubic Bezier segments
diff --git a/contrib/python/fonttools/fontTools/ttLib/sfnt.py b/contrib/python/fonttools/fontTools/ttLib/sfnt.py
index b1569423c4..6cc867a4d7 100644
--- a/contrib/python/fonttools/fontTools/ttLib/sfnt.py
+++ b/contrib/python/fonttools/fontTools/ttLib/sfnt.py
@@ -1,8 +1,9 @@
"""ttLib/sfnt.py -- low-level module to deal with the sfnt file format.
Defines two public classes:
- SFNTReader
- SFNTWriter
+
+- SFNTReader
+- SFNTWriter
(Normally you don't have to use these classes explicitly; they are
used automatically by ttLib.TTFont.)
diff --git a/contrib/python/fonttools/fontTools/ttLib/tables/_n_a_m_e.py b/contrib/python/fonttools/fontTools/ttLib/tables/_n_a_m_e.py
index bbb4f5364e..e30086adb3 100644
--- a/contrib/python/fonttools/fontTools/ttLib/tables/_n_a_m_e.py
+++ b/contrib/python/fonttools/fontTools/ttLib/tables/_n_a_m_e.py
@@ -1175,17 +1175,8 @@ class NameRecordVisitor(TTVisitor):
@NameRecordVisitor.register_attrs(
(
- (otTables.FeatureParamsSize, ("SubfamilyID", "SubfamilyNameID")),
+ (otTables.FeatureParamsSize, ("SubfamilyNameID",)),
(otTables.FeatureParamsStylisticSet, ("UINameID",)),
- (
- otTables.FeatureParamsCharacterVariants,
- (
- "FeatUILabelNameID",
- "FeatUITooltipTextNameID",
- "SampleTextNameID",
- "FirstParamUILabelNameID",
- ),
- ),
(otTables.STAT, ("ElidedFallbackNameID",)),
(otTables.AxisRecord, ("AxisNameID",)),
(otTables.AxisValue, ("ValueNameID",)),
@@ -1197,6 +1188,22 @@ def visit(visitor, obj, attr, value):
visitor.seen.add(value)
+@NameRecordVisitor.register(otTables.FeatureParamsCharacterVariants)
+def visit(visitor, obj):
+ for attr in ("FeatUILabelNameID", "FeatUITooltipTextNameID", "SampleTextNameID"):
+ value = getattr(obj, attr)
+ visitor.seen.add(value)
+ # also include the sequence of UI strings for individual variants, if any
+ if obj.FirstParamUILabelNameID == 0 or obj.NumNamedParameters == 0:
+ return
+ visitor.seen.update(
+ range(
+ obj.FirstParamUILabelNameID,
+ obj.FirstParamUILabelNameID + obj.NumNamedParameters,
+ )
+ )
+
+
@NameRecordVisitor.register(ttLib.getTableClass("fvar"))
def visit(visitor, obj):
for inst in obj.instances:
diff --git a/contrib/python/fonttools/fontTools/ttLib/ttFont.py b/contrib/python/fonttools/fontTools/ttLib/ttFont.py
index f4a539678b..d7bd92bc20 100644
--- a/contrib/python/fonttools/fontTools/ttLib/ttFont.py
+++ b/contrib/python/fonttools/fontTools/ttLib/ttFont.py
@@ -26,37 +26,43 @@ class TTFont(object):
accessing tables. Tables will be only decompiled when necessary, ie. when
they're actually accessed. This means that simple operations can be extremely fast.
- Example usage::
-
- >> from fontTools import ttLib
- >> tt = ttLib.TTFont("afont.ttf") # Load an existing font file
- >> tt['maxp'].numGlyphs
- 242
- >> tt['OS/2'].achVendID
- 'B&H\000'
- >> tt['head'].unitsPerEm
- 2048
+ Example usage:
+ .. code-block:: pycon
+
+ >>>
+ >> from fontTools import ttLib
+ >> tt = ttLib.TTFont("afont.ttf") # Load an existing font file
+ >> tt['maxp'].numGlyphs
+ 242
+ >> tt['OS/2'].achVendID
+ 'B&H\000'
+ >> tt['head'].unitsPerEm
+ 2048
For details of the objects returned when accessing each table, see :ref:`tables`.
- To add a table to the font, use the :py:func:`newTable` function::
+ To add a table to the font, use the :py:func:`newTable` function:
+ .. code-block:: pycon
- >> os2 = newTable("OS/2")
- >> os2.version = 4
- >> # set other attributes
- >> font["OS/2"] = os2
+ >>>
+ >> os2 = newTable("OS/2")
+ >> os2.version = 4
+ >> # set other attributes
+ >> font["OS/2"] = os2
TrueType fonts can also be serialized to and from XML format (see also the
- :ref:`ttx` binary)::
+ :ref:`ttx` binary):
+ .. code-block:: pycon
- >> tt.saveXML("afont.ttx")
- Dumping 'LTSH' table...
- Dumping 'OS/2' table...
- [...]
+ >>
+ >> tt.saveXML("afont.ttx")
+ Dumping 'LTSH' table...
+ Dumping 'OS/2' table...
+ [...]
- >> tt2 = ttLib.TTFont() # Create a new font object
- >> tt2.importXML("afont.ttx")
- >> tt2['maxp'].numGlyphs
- 242
+ >> tt2 = ttLib.TTFont() # Create a new font object
+ >> tt2.importXML("afont.ttx")
+ >> tt2['maxp'].numGlyphs
+ 242
The TTFont object may be used as a context manager; this will cause the file
reader to be closed after the context ``with`` block is exited::
@@ -981,14 +987,16 @@ def tagToIdentifier(tag):
letters get an underscore after the letter. Trailing spaces are
trimmed. Illegal characters are escaped as two hex bytes. If the
result starts with a number (as the result of a hex escape), an
- extra underscore is prepended. Examples::
-
- >>> tagToIdentifier('glyf')
- '_g_l_y_f'
- >>> tagToIdentifier('cvt ')
- '_c_v_t'
- >>> tagToIdentifier('OS/2')
- 'O_S_2f_2'
+ extra underscore is prepended. Examples:
+ .. code-block:: pycon
+
+ >>>
+ >> tagToIdentifier('glyf')
+ '_g_l_y_f'
+ >> tagToIdentifier('cvt ')
+ '_c_v_t'
+ >> tagToIdentifier('OS/2')
+ 'O_S_2f_2'
"""
import re
diff --git a/contrib/python/fonttools/fontTools/ufoLib/__init__.py b/contrib/python/fonttools/fontTools/ufoLib/__init__.py
index c2d2b0b266..aa57beede2 100644
--- a/contrib/python/fonttools/fontTools/ufoLib/__init__.py
+++ b/contrib/python/fonttools/fontTools/ufoLib/__init__.py
@@ -1,3 +1,37 @@
+"""
+A library for importing .ufo files and their descendants.
+Refer to http://unifiedfontobject.com for the UFO specification.
+
+The UFOReader and UFOWriter classes support versions 1, 2 and 3
+of the specification.
+
+Sets that list the font info attribute names for the fontinfo.plist
+formats are available for external use. These are:
+
+- fontInfoAttributesVersion1
+- fontInfoAttributesVersion2
+- fontInfoAttributesVersion3
+
+A set listing the fontinfo.plist attributes that were deprecated
+in version 2 is available for external use:
+
+- deprecatedFontInfoAttributesVersion2
+
+Functions that do basic validation on values for fontinfo.plist
+are available for external use. These are
+
+- validateFontInfoVersion2ValueForAttribute
+- validateFontInfoVersion3ValueForAttribute
+
+Value conversion functions are available for converting
+fontinfo.plist values between the possible format versions.
+
+- convertFontInfoValueForAttributeFromVersion1ToVersion2
+- convertFontInfoValueForAttributeFromVersion2ToVersion1
+- convertFontInfoValueForAttributeFromVersion2ToVersion3
+- convertFontInfoValueForAttributeFromVersion3ToVersion2
+"""
+
import os
from copy import deepcopy
from os import fsdecode
@@ -21,36 +55,6 @@ from fontTools.ufoLib.converters import convertUFO1OrUFO2KerningToUFO3Kerning
from fontTools.ufoLib.errors import UFOLibError
from fontTools.ufoLib.utils import numberTypes, _VersionTupleEnumMixin
-"""
-A library for importing .ufo files and their descendants.
-Refer to http://unifiedfontobject.com for the UFO specification.
-
-The UFOReader and UFOWriter classes support versions 1, 2 and 3
-of the specification.
-
-Sets that list the font info attribute names for the fontinfo.plist
-formats are available for external use. These are:
- fontInfoAttributesVersion1
- fontInfoAttributesVersion2
- fontInfoAttributesVersion3
-
-A set listing the fontinfo.plist attributes that were deprecated
-in version 2 is available for external use:
- deprecatedFontInfoAttributesVersion2
-
-Functions that do basic validation on values for fontinfo.plist
-are available for external use. These are
- validateFontInfoVersion2ValueForAttribute
- validateFontInfoVersion3ValueForAttribute
-
-Value conversion functions are available for converting
-fontinfo.plist values between the possible format versions.
- convertFontInfoValueForAttributeFromVersion1ToVersion2
- convertFontInfoValueForAttributeFromVersion2ToVersion1
- convertFontInfoValueForAttributeFromVersion2ToVersion3
- convertFontInfoValueForAttributeFromVersion3ToVersion2
-"""
-
__all__ = [
"makeUFOPath",
"UFOLibError",
diff --git a/contrib/python/fonttools/fontTools/unicodedata/Blocks.py b/contrib/python/fonttools/fontTools/unicodedata/Blocks.py
index b35c93d9b6..7084d911db 100644
--- a/contrib/python/fonttools/fontTools/unicodedata/Blocks.py
+++ b/contrib/python/fonttools/fontTools/unicodedata/Blocks.py
@@ -4,10 +4,11 @@
# Source: https://unicode.org/Public/UNIDATA/Blocks.txt
# License: http://unicode.org/copyright.html#License
#
-# Blocks-15.0.0.txt
-# Date: 2022-01-28, 20:58:00 GMT [KW]
-# © 2022 Unicode®, Inc.
-# For terms of use, see https://www.unicode.org/terms_of_use.html
+# Blocks-16.0.0.txt
+# Date: 2024-02-02
+# © 2024 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use and license, see https://www.unicode.org/terms_of_use.html
#
# Unicode Character Database
# For documentation, see https://www.unicode.org/reports/tr44/
@@ -205,7 +206,7 @@ RANGES = [
0x10500, # .. 0x1052F ; Elbasan
0x10530, # .. 0x1056F ; Caucasian Albanian
0x10570, # .. 0x105BF ; Vithkuqi
- 0x105C0, # .. 0x105FF ; No_Block
+ 0x105C0, # .. 0x105FF ; Todhri
0x10600, # .. 0x1077F ; Linear A
0x10780, # .. 0x107BF ; Latin Extended-F
0x107C0, # .. 0x107FF ; No_Block
@@ -234,7 +235,8 @@ RANGES = [
0x10C50, # .. 0x10C7F ; No_Block
0x10C80, # .. 0x10CFF ; Old Hungarian
0x10D00, # .. 0x10D3F ; Hanifi Rohingya
- 0x10D40, # .. 0x10E5F ; No_Block
+ 0x10D40, # .. 0x10D8F ; Garay
+ 0x10D90, # .. 0x10E5F ; No_Block
0x10E60, # .. 0x10E7F ; Rumi Numeral Symbols
0x10E80, # .. 0x10EBF ; Yezidi
0x10EC0, # .. 0x10EFF ; Arabic Extended-C
@@ -255,7 +257,7 @@ RANGES = [
0x11280, # .. 0x112AF ; Multani
0x112B0, # .. 0x112FF ; Khudawadi
0x11300, # .. 0x1137F ; Grantha
- 0x11380, # .. 0x113FF ; No_Block
+ 0x11380, # .. 0x113FF ; Tulu-Tigalari
0x11400, # .. 0x1147F ; Newa
0x11480, # .. 0x114DF ; Tirhuta
0x114E0, # .. 0x1157F ; No_Block
@@ -263,7 +265,7 @@ RANGES = [
0x11600, # .. 0x1165F ; Modi
0x11660, # .. 0x1167F ; Mongolian Supplement
0x11680, # .. 0x116CF ; Takri
- 0x116D0, # .. 0x116FF ; No_Block
+ 0x116D0, # .. 0x116FF ; Myanmar Extended-C
0x11700, # .. 0x1174F ; Ahom
0x11750, # .. 0x117FF ; No_Block
0x11800, # .. 0x1184F ; Dogra
@@ -277,7 +279,8 @@ RANGES = [
0x11AB0, # .. 0x11ABF ; Unified Canadian Aboriginal Syllabics Extended-A
0x11AC0, # .. 0x11AFF ; Pau Cin Hau
0x11B00, # .. 0x11B5F ; Devanagari Extended-A
- 0x11B60, # .. 0x11BFF ; No_Block
+ 0x11B60, # .. 0x11BBF ; No_Block
+ 0x11BC0, # .. 0x11BFF ; Sunuwar
0x11C00, # .. 0x11C6F ; Bhaiksuki
0x11C70, # .. 0x11CBF ; Marchen
0x11CC0, # .. 0x11CFF ; No_Block
@@ -296,15 +299,19 @@ RANGES = [
0x12F90, # .. 0x12FFF ; Cypro-Minoan
0x13000, # .. 0x1342F ; Egyptian Hieroglyphs
0x13430, # .. 0x1345F ; Egyptian Hieroglyph Format Controls
- 0x13460, # .. 0x143FF ; No_Block
+ 0x13460, # .. 0x143FF ; Egyptian Hieroglyphs Extended-A
0x14400, # .. 0x1467F ; Anatolian Hieroglyphs
- 0x14680, # .. 0x167FF ; No_Block
+ 0x14680, # .. 0x160FF ; No_Block
+ 0x16100, # .. 0x1613F ; Gurung Khema
+ 0x16140, # .. 0x167FF ; No_Block
0x16800, # .. 0x16A3F ; Bamum Supplement
0x16A40, # .. 0x16A6F ; Mro
0x16A70, # .. 0x16ACF ; Tangsa
0x16AD0, # .. 0x16AFF ; Bassa Vah
0x16B00, # .. 0x16B8F ; Pahawh Hmong
- 0x16B90, # .. 0x16E3F ; No_Block
+ 0x16B90, # .. 0x16D3F ; No_Block
+ 0x16D40, # .. 0x16D7F ; Kirat Rai
+ 0x16D80, # .. 0x16E3F ; No_Block
0x16E40, # .. 0x16E9F ; Medefaidrin
0x16EA0, # .. 0x16EFF ; No_Block
0x16F00, # .. 0x16F9F ; Miao
@@ -323,7 +330,9 @@ RANGES = [
0x1B300, # .. 0x1BBFF ; No_Block
0x1BC00, # .. 0x1BC9F ; Duployan
0x1BCA0, # .. 0x1BCAF ; Shorthand Format Controls
- 0x1BCB0, # .. 0x1CEFF ; No_Block
+ 0x1BCB0, # .. 0x1CBFF ; No_Block
+ 0x1CC00, # .. 0x1CEBF ; Symbols for Legacy Computing Supplement
+ 0x1CEC0, # .. 0x1CEFF ; No_Block
0x1CF00, # .. 0x1CFCF ; Znamenny Musical Notation
0x1CFD0, # .. 0x1CFFF ; No_Block
0x1D000, # .. 0x1D0FF ; Byzantine Musical Symbols
@@ -348,7 +357,9 @@ RANGES = [
0x1E2C0, # .. 0x1E2FF ; Wancho
0x1E300, # .. 0x1E4CF ; No_Block
0x1E4D0, # .. 0x1E4FF ; Nag Mundari
- 0x1E500, # .. 0x1E7DF ; No_Block
+ 0x1E500, # .. 0x1E5CF ; No_Block
+ 0x1E5D0, # .. 0x1E5FF ; Ol Onal
+ 0x1E600, # .. 0x1E7DF ; No_Block
0x1E7E0, # .. 0x1E7FF ; Ethiopic Extended-B
0x1E800, # .. 0x1E8DF ; Mende Kikakui
0x1E8E0, # .. 0x1E8FF ; No_Block
@@ -383,7 +394,8 @@ RANGES = [
0x2B740, # .. 0x2B81F ; CJK Unified Ideographs Extension D
0x2B820, # .. 0x2CEAF ; CJK Unified Ideographs Extension E
0x2CEB0, # .. 0x2EBEF ; CJK Unified Ideographs Extension F
- 0x2EBF0, # .. 0x2F7FF ; No_Block
+ 0x2EBF0, # .. 0x2EE5F ; CJK Unified Ideographs Extension I
+ 0x2EE60, # .. 0x2F7FF ; No_Block
0x2F800, # .. 0x2FA1F ; CJK Compatibility Ideographs Supplement
0x2FA20, # .. 0x2FFFF ; No_Block
0x30000, # .. 0x3134F ; CJK Unified Ideographs Extension G
@@ -586,7 +598,7 @@ VALUES = [
"Elbasan", # 10500..1052F
"Caucasian Albanian", # 10530..1056F
"Vithkuqi", # 10570..105BF
- "No_Block", # 105C0..105FF
+ "Todhri", # 105C0..105FF
"Linear A", # 10600..1077F
"Latin Extended-F", # 10780..107BF
"No_Block", # 107C0..107FF
@@ -615,7 +627,8 @@ VALUES = [
"No_Block", # 10C50..10C7F
"Old Hungarian", # 10C80..10CFF
"Hanifi Rohingya", # 10D00..10D3F
- "No_Block", # 10D40..10E5F
+ "Garay", # 10D40..10D8F
+ "No_Block", # 10D90..10E5F
"Rumi Numeral Symbols", # 10E60..10E7F
"Yezidi", # 10E80..10EBF
"Arabic Extended-C", # 10EC0..10EFF
@@ -636,7 +649,7 @@ VALUES = [
"Multani", # 11280..112AF
"Khudawadi", # 112B0..112FF
"Grantha", # 11300..1137F
- "No_Block", # 11380..113FF
+ "Tulu-Tigalari", # 11380..113FF
"Newa", # 11400..1147F
"Tirhuta", # 11480..114DF
"No_Block", # 114E0..1157F
@@ -644,7 +657,7 @@ VALUES = [
"Modi", # 11600..1165F
"Mongolian Supplement", # 11660..1167F
"Takri", # 11680..116CF
- "No_Block", # 116D0..116FF
+ "Myanmar Extended-C", # 116D0..116FF
"Ahom", # 11700..1174F
"No_Block", # 11750..117FF
"Dogra", # 11800..1184F
@@ -658,7 +671,8 @@ VALUES = [
"Unified Canadian Aboriginal Syllabics Extended-A", # 11AB0..11ABF
"Pau Cin Hau", # 11AC0..11AFF
"Devanagari Extended-A", # 11B00..11B5F
- "No_Block", # 11B60..11BFF
+ "No_Block", # 11B60..11BBF
+ "Sunuwar", # 11BC0..11BFF
"Bhaiksuki", # 11C00..11C6F
"Marchen", # 11C70..11CBF
"No_Block", # 11CC0..11CFF
@@ -677,15 +691,19 @@ VALUES = [
"Cypro-Minoan", # 12F90..12FFF
"Egyptian Hieroglyphs", # 13000..1342F
"Egyptian Hieroglyph Format Controls", # 13430..1345F
- "No_Block", # 13460..143FF
+ "Egyptian Hieroglyphs Extended-A", # 13460..143FF
"Anatolian Hieroglyphs", # 14400..1467F
- "No_Block", # 14680..167FF
+ "No_Block", # 14680..160FF
+ "Gurung Khema", # 16100..1613F
+ "No_Block", # 16140..167FF
"Bamum Supplement", # 16800..16A3F
"Mro", # 16A40..16A6F
"Tangsa", # 16A70..16ACF
"Bassa Vah", # 16AD0..16AFF
"Pahawh Hmong", # 16B00..16B8F
- "No_Block", # 16B90..16E3F
+ "No_Block", # 16B90..16D3F
+ "Kirat Rai", # 16D40..16D7F
+ "No_Block", # 16D80..16E3F
"Medefaidrin", # 16E40..16E9F
"No_Block", # 16EA0..16EFF
"Miao", # 16F00..16F9F
@@ -704,7 +722,9 @@ VALUES = [
"No_Block", # 1B300..1BBFF
"Duployan", # 1BC00..1BC9F
"Shorthand Format Controls", # 1BCA0..1BCAF
- "No_Block", # 1BCB0..1CEFF
+ "No_Block", # 1BCB0..1CBFF
+ "Symbols for Legacy Computing Supplement", # 1CC00..1CEBF
+ "No_Block", # 1CEC0..1CEFF
"Znamenny Musical Notation", # 1CF00..1CFCF
"No_Block", # 1CFD0..1CFFF
"Byzantine Musical Symbols", # 1D000..1D0FF
@@ -729,7 +749,9 @@ VALUES = [
"Wancho", # 1E2C0..1E2FF
"No_Block", # 1E300..1E4CF
"Nag Mundari", # 1E4D0..1E4FF
- "No_Block", # 1E500..1E7DF
+ "No_Block", # 1E500..1E5CF
+ "Ol Onal", # 1E5D0..1E5FF
+ "No_Block", # 1E600..1E7DF
"Ethiopic Extended-B", # 1E7E0..1E7FF
"Mende Kikakui", # 1E800..1E8DF
"No_Block", # 1E8E0..1E8FF
@@ -764,7 +786,8 @@ VALUES = [
"CJK Unified Ideographs Extension D", # 2B740..2B81F
"CJK Unified Ideographs Extension E", # 2B820..2CEAF
"CJK Unified Ideographs Extension F", # 2CEB0..2EBEF
- "No_Block", # 2EBF0..2F7FF
+ "CJK Unified Ideographs Extension I", # 2EBF0..2EE5F
+ "No_Block", # 2EE60..2F7FF
"CJK Compatibility Ideographs Supplement", # 2F800..2FA1F
"No_Block", # 2FA20..2FFFF
"CJK Unified Ideographs Extension G", # 30000..3134F
diff --git a/contrib/python/fonttools/fontTools/unicodedata/ScriptExtensions.py b/contrib/python/fonttools/fontTools/unicodedata/ScriptExtensions.py
index 2ecc5daed8..df7be88f00 100644
--- a/contrib/python/fonttools/fontTools/unicodedata/ScriptExtensions.py
+++ b/contrib/python/fonttools/fontTools/unicodedata/ScriptExtensions.py
@@ -4,11 +4,11 @@
# Source: https://unicode.org/Public/UNIDATA/ScriptExtensions.txt
# License: http://unicode.org/copyright.html#License
#
-# ScriptExtensions-15.0.0.txt
-# Date: 2022-02-02, 00:57:11 GMT
-# © 2022 Unicode®, Inc.
+# ScriptExtensions-16.0.0.txt
+# Date: 2024-07-30, 19:38:00 GMT
+# © 2024 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
-# For terms of use, see https://www.unicode.org/terms_of_use.html
+# For terms of use and license, see https://www.unicode.org/terms_of_use.html
#
# Unicode Character Database
# For documentation, see https://www.unicode.org/reports/tr44/
@@ -27,38 +27,84 @@
# values in that set is not material, but for stability in presentation
# it is given here as alphabetical.
#
-# The Script_Extensions values are presented in sorted order in the file.
-# They are sorted first by the number of Script property values in their sets,
-# and then alphabetically by first differing Script property value.
-#
-# Following each distinct Script_Extensions value is the list of code
-# points associated with that value, listed in code point order.
-#
# All code points not explicitly listed for Script_Extensions
-# have as their value the corresponding Script property value
+# have as their value the corresponding Script property value.
#
# @missing: 0000..10FFFF; <script>
RANGES = [
- 0x0000, # .. 0x0341 ; None
+ 0x0000, # .. 0x02BB ; None
+ 0x02BC, # .. 0x02BC ; {'Beng', 'Cyrl', 'Deva', 'Latn', 'Lisu', 'Thai', 'Toto'}
+ 0x02BD, # .. 0x02C6 ; None
+ 0x02C7, # .. 0x02C7 ; {'Bopo', 'Latn'}
+ 0x02C8, # .. 0x02C8 ; None
+ 0x02C9, # .. 0x02CB ; {'Bopo', 'Latn'}
+ 0x02CC, # .. 0x02CC ; None
+ 0x02CD, # .. 0x02CD ; {'Latn', 'Lisu'}
+ 0x02CE, # .. 0x02D6 ; None
+ 0x02D7, # .. 0x02D7 ; {'Latn', 'Thai'}
+ 0x02D8, # .. 0x02D8 ; None
+ 0x02D9, # .. 0x02D9 ; {'Bopo', 'Latn'}
+ 0x02DA, # .. 0x02FF ; None
+ 0x0300, # .. 0x0300 ; {'Cher', 'Copt', 'Cyrl', 'Grek', 'Latn', 'Perm', 'Sunu', 'Tale'}
+ 0x0301, # .. 0x0301 ; {'Cher', 'Cyrl', 'Grek', 'Latn', 'Osge', 'Sunu', 'Tale', 'Todr'}
+ 0x0302, # .. 0x0302 ; {'Cher', 'Cyrl', 'Latn', 'Tfng'}
+ 0x0303, # .. 0x0303 ; {'Glag', 'Latn', 'Sunu', 'Syrc', 'Thai'}
+ 0x0304, # .. 0x0304 ; {'Aghb', 'Cher', 'Copt', 'Cyrl', 'Goth', 'Grek', 'Latn', 'Osge', 'Syrc', 'Tfng', 'Todr'}
+ 0x0305, # .. 0x0305 ; {'Copt', 'Elba', 'Glag', 'Goth', 'Kana', 'Latn'}
+ 0x0306, # .. 0x0306 ; {'Cyrl', 'Grek', 'Latn', 'Perm'}
+ 0x0307, # .. 0x0307 ; {'Copt', 'Dupl', 'Hebr', 'Latn', 'Perm', 'Syrc', 'Tale', 'Tfng', 'Todr'}
+ 0x0308, # .. 0x0308 ; {'Armn', 'Cyrl', 'Dupl', 'Goth', 'Grek', 'Hebr', 'Latn', 'Perm', 'Syrc', 'Tale'}
+ 0x0309, # .. 0x0309 ; {'Latn', 'Tfng'}
+ 0x030A, # .. 0x030A ; {'Dupl', 'Latn', 'Syrc'}
+ 0x030B, # .. 0x030B ; {'Cher', 'Cyrl', 'Latn', 'Osge'}
+ 0x030C, # .. 0x030C ; {'Cher', 'Latn', 'Tale'}
+ 0x030D, # .. 0x030D ; {'Latn', 'Sunu'}
+ 0x030E, # .. 0x030E ; {'Ethi', 'Latn'}
+ 0x030F, # .. 0x030F ; None
+ 0x0310, # .. 0x0310 ; {'Latn', 'Sunu'}
+ 0x0311, # .. 0x0311 ; {'Cyrl', 'Latn', 'Todr'}
+ 0x0312, # .. 0x0312 ; None
+ 0x0313, # .. 0x0313 ; {'Grek', 'Latn', 'Perm', 'Todr'}
+ 0x0314, # .. 0x031F ; None
+ 0x0320, # .. 0x0320 ; {'Latn', 'Syrc'}
+ 0x0321, # .. 0x0322 ; None
+ 0x0323, # .. 0x0323 ; {'Cher', 'Dupl', 'Kana', 'Latn', 'Syrc'}
+ 0x0324, # .. 0x0324 ; {'Cher', 'Dupl', 'Latn', 'Syrc'}
+ 0x0325, # .. 0x0325 ; {'Latn', 'Syrc'}
+ 0x0326, # .. 0x032C ; None
+ 0x032D, # .. 0x032D ; {'Latn', 'Sunu', 'Syrc'}
+ 0x032E, # .. 0x032E ; {'Latn', 'Syrc'}
+ 0x032F, # .. 0x032F ; None
+ 0x0330, # .. 0x0330 ; {'Cher', 'Latn', 'Syrc'}
+ 0x0331, # .. 0x0331 ; {'Aghb', 'Cher', 'Goth', 'Latn', 'Sunu', 'Thai'}
+ 0x0332, # .. 0x0341 ; None
0x0342, # .. 0x0342 ; {'Grek'}
0x0343, # .. 0x0344 ; None
0x0345, # .. 0x0345 ; {'Grek'}
- 0x0346, # .. 0x0362 ; None
+ 0x0346, # .. 0x0357 ; None
+ 0x0358, # .. 0x0358 ; {'Latn', 'Osge'}
+ 0x0359, # .. 0x035D ; None
+ 0x035E, # .. 0x035E ; {'Aghb', 'Latn', 'Todr'}
+ 0x035F, # .. 0x0362 ; None
0x0363, # .. 0x036F ; {'Latn'}
- 0x0370, # .. 0x0482 ; None
+ 0x0370, # .. 0x0373 ; None
+ 0x0374, # .. 0x0375 ; {'Copt', 'Grek'}
+ 0x0376, # .. 0x0482 ; None
0x0483, # .. 0x0483 ; {'Cyrl', 'Perm'}
0x0484, # .. 0x0484 ; {'Cyrl', 'Glag'}
0x0485, # .. 0x0486 ; {'Cyrl', 'Latn'}
0x0487, # .. 0x0487 ; {'Cyrl', 'Glag'}
- 0x0488, # .. 0x060B ; None
- 0x060C, # .. 0x060C ; {'Arab', 'Nkoo', 'Rohg', 'Syrc', 'Thaa', 'Yezi'}
+ 0x0488, # .. 0x0588 ; None
+ 0x0589, # .. 0x0589 ; {'Armn', 'Geor', 'Glag'}
+ 0x058A, # .. 0x060B ; None
+ 0x060C, # .. 0x060C ; {'Arab', 'Gara', 'Nkoo', 'Rohg', 'Syrc', 'Thaa', 'Yezi'}
0x060D, # .. 0x061A ; None
- 0x061B, # .. 0x061B ; {'Arab', 'Nkoo', 'Rohg', 'Syrc', 'Thaa', 'Yezi'}
+ 0x061B, # .. 0x061B ; {'Arab', 'Gara', 'Nkoo', 'Rohg', 'Syrc', 'Thaa', 'Yezi'}
0x061C, # .. 0x061C ; {'Arab', 'Syrc', 'Thaa'}
0x061D, # .. 0x061E ; None
- 0x061F, # .. 0x061F ; {'Adlm', 'Arab', 'Nkoo', 'Rohg', 'Syrc', 'Thaa', 'Yezi'}
+ 0x061F, # .. 0x061F ; {'Adlm', 'Arab', 'Gara', 'Nkoo', 'Rohg', 'Syrc', 'Thaa', 'Yezi'}
0x0620, # .. 0x063F ; None
0x0640, # .. 0x0640 ; {'Adlm', 'Arab', 'Mand', 'Mani', 'Ougr', 'Phlp', 'Rohg', 'Sogd', 'Syrc'}
0x0641, # .. 0x064A ; None
@@ -73,8 +119,8 @@ RANGES = [
0x0951, # .. 0x0951 ; {'Beng', 'Deva', 'Gran', 'Gujr', 'Guru', 'Knda', 'Latn', 'Mlym', 'Orya', 'Shrd', 'Taml', 'Telu', 'Tirh'}
0x0952, # .. 0x0952 ; {'Beng', 'Deva', 'Gran', 'Gujr', 'Guru', 'Knda', 'Latn', 'Mlym', 'Orya', 'Taml', 'Telu', 'Tirh'}
0x0953, # .. 0x0963 ; None
- 0x0964, # .. 0x0964 ; {'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Guru', 'Knda', 'Mahj', 'Mlym', 'Nand', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'}
- 0x0965, # .. 0x0965 ; {'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Guru', 'Knda', 'Limb', 'Mahj', 'Mlym', 'Nand', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'}
+ 0x0964, # .. 0x0964 ; {'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Guru', 'Knda', 'Mahj', 'Mlym', 'Nand', 'Onao', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'}
+ 0x0965, # .. 0x0965 ; {'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Gukh', 'Guru', 'Knda', 'Limb', 'Mahj', 'Mlym', 'Nand', 'Onao', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'}
0x0966, # .. 0x096F ; {'Deva', 'Dogr', 'Kthi', 'Mahj'}
0x0970, # .. 0x09E5 ; None
0x09E6, # .. 0x09EF ; {'Beng', 'Cakm', 'Sylo'}
@@ -85,12 +131,14 @@ RANGES = [
0x0AF0, # .. 0x0BE5 ; None
0x0BE6, # .. 0x0BF3 ; {'Gran', 'Taml'}
0x0BF4, # .. 0x0CE5 ; None
- 0x0CE6, # .. 0x0CEF ; {'Knda', 'Nand'}
+ 0x0CE6, # .. 0x0CEF ; {'Knda', 'Nand', 'Tutg'}
0x0CF0, # .. 0x103F ; None
0x1040, # .. 0x1049 ; {'Cakm', 'Mymr', 'Tale'}
0x104A, # .. 0x10FA ; None
- 0x10FB, # .. 0x10FB ; {'Geor', 'Latn'}
- 0x10FC, # .. 0x1734 ; None
+ 0x10FB, # .. 0x10FB ; {'Geor', 'Glag', 'Latn'}
+ 0x10FC, # .. 0x16EA ; None
+ 0x16EB, # .. 0x16ED ; {'Runr'}
+ 0x16EE, # .. 0x1734 ; None
0x1735, # .. 0x1736 ; {'Buhd', 'Hano', 'Tagb', 'Tglg'}
0x1737, # .. 0x1801 ; None
0x1802, # .. 0x1803 ; {'Mong', 'Phag'}
@@ -100,7 +148,7 @@ RANGES = [
0x1CD0, # .. 0x1CD0 ; {'Beng', 'Deva', 'Gran', 'Knda'}
0x1CD1, # .. 0x1CD1 ; {'Deva'}
0x1CD2, # .. 0x1CD2 ; {'Beng', 'Deva', 'Gran', 'Knda'}
- 0x1CD3, # .. 0x1CD3 ; {'Deva', 'Gran'}
+ 0x1CD3, # .. 0x1CD3 ; {'Deva', 'Gran', 'Knda'}
0x1CD4, # .. 0x1CD4 ; {'Deva'}
0x1CD5, # .. 0x1CD6 ; {'Beng', 'Deva'}
0x1CD7, # .. 0x1CD7 ; {'Deva', 'Shrd'}
@@ -118,9 +166,9 @@ RANGES = [
0x1CEB, # .. 0x1CEC ; {'Deva'}
0x1CED, # .. 0x1CED ; {'Beng', 'Deva'}
0x1CEE, # .. 0x1CF1 ; {'Deva'}
- 0x1CF2, # .. 0x1CF2 ; {'Beng', 'Deva', 'Gran', 'Knda', 'Nand', 'Orya', 'Telu', 'Tirh'}
+ 0x1CF2, # .. 0x1CF2 ; {'Beng', 'Deva', 'Gran', 'Knda', 'Mlym', 'Nand', 'Orya', 'Sinh', 'Telu', 'Tirh', 'Tutg'}
0x1CF3, # .. 0x1CF3 ; {'Deva', 'Gran'}
- 0x1CF4, # .. 0x1CF4 ; {'Deva', 'Gran', 'Knda'}
+ 0x1CF4, # .. 0x1CF4 ; {'Deva', 'Gran', 'Knda', 'Tutg'}
0x1CF5, # .. 0x1CF6 ; {'Beng', 'Deva'}
0x1CF7, # .. 0x1CF7 ; {'Beng'}
0x1CF8, # .. 0x1CF9 ; {'Deva', 'Gran'}
@@ -128,22 +176,42 @@ RANGES = [
0x1CFB, # .. 0x1DBF ; None
0x1DC0, # .. 0x1DC1 ; {'Grek'}
0x1DC2, # .. 0x1DF7 ; None
- 0x1DF8, # .. 0x1DF8 ; {'Cyrl', 'Syrc'}
+ 0x1DF8, # .. 0x1DF8 ; {'Cyrl', 'Latn', 'Syrc'}
0x1DF9, # .. 0x1DF9 ; None
0x1DFA, # .. 0x1DFA ; {'Syrc'}
0x1DFB, # .. 0x202E ; None
- 0x202F, # .. 0x202F ; {'Latn', 'Mong'}
- 0x2030, # .. 0x20EF ; None
+ 0x202F, # .. 0x202F ; {'Latn', 'Mong', 'Phag'}
+ 0x2030, # .. 0x204E ; None
+ 0x204F, # .. 0x204F ; {'Adlm', 'Arab'}
+ 0x2050, # .. 0x2059 ; None
+ 0x205A, # .. 0x205A ; {'Cari', 'Geor', 'Glag', 'Hung', 'Lyci', 'Orkh'}
+ 0x205B, # .. 0x205C ; None
+ 0x205D, # .. 0x205D ; {'Cari', 'Grek', 'Hung', 'Mero'}
+ 0x205E, # .. 0x20EF ; None
0x20F0, # .. 0x20F0 ; {'Deva', 'Gran', 'Latn'}
- 0x20F1, # .. 0x2E42 ; None
+ 0x20F1, # .. 0x2E16 ; None
+ 0x2E17, # .. 0x2E17 ; {'Copt', 'Latn'}
+ 0x2E18, # .. 0x2E2F ; None
+ 0x2E30, # .. 0x2E30 ; {'Avst', 'Orkh'}
+ 0x2E31, # .. 0x2E31 ; {'Avst', 'Cari', 'Geor', 'Hung', 'Kthi', 'Lydi', 'Samr'}
+ 0x2E32, # .. 0x2E3B ; None
+ 0x2E3C, # .. 0x2E3C ; {'Dupl'}
+ 0x2E3D, # .. 0x2E40 ; None
+ 0x2E41, # .. 0x2E41 ; {'Adlm', 'Arab', 'Hung'}
+ 0x2E42, # .. 0x2E42 ; None
0x2E43, # .. 0x2E43 ; {'Cyrl', 'Glag'}
- 0x2E44, # .. 0x3000 ; None
- 0x3001, # .. 0x3002 ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana', 'Yiii'}
+ 0x2E44, # .. 0x2FEF ; None
+ 0x2FF0, # .. 0x2FFF ; {'Hani', 'Tang'}
+ 0x3000, # .. 0x3000 ; None
+ 0x3001, # .. 0x3001 ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana', 'Mong', 'Yiii'}
+ 0x3002, # .. 0x3002 ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana', 'Mong', 'Phag', 'Yiii'}
0x3003, # .. 0x3003 ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana'}
0x3004, # .. 0x3005 ; None
0x3006, # .. 0x3006 ; {'Hani'}
0x3007, # .. 0x3007 ; None
- 0x3008, # .. 0x3011 ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana', 'Yiii'}
+ 0x3008, # .. 0x3009 ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana', 'Mong', 'Tibt', 'Yiii'}
+ 0x300A, # .. 0x300B ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana', 'Lisu', 'Mong', 'Tibt', 'Yiii'}
+ 0x300C, # .. 0x3011 ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana', 'Yiii'}
0x3012, # .. 0x3012 ; None
0x3013, # .. 0x3013 ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana'}
0x3014, # .. 0x301B ; {'Bopo', 'Hang', 'Hani', 'Hira', 'Kana', 'Yiii'}
@@ -168,8 +236,10 @@ RANGES = [
0x30FD, # .. 0x318F ; None
0x3190, # .. 0x319F ; {'Hani'}
0x31A0, # .. 0x31BF ; None
- 0x31C0, # .. 0x31E3 ; {'Hani'}
- 0x31E4, # .. 0x321F ; None
+ 0x31C0, # .. 0x31E5 ; {'Hani'}
+ 0x31E6, # .. 0x31EE ; None
+ 0x31EF, # .. 0x31EF ; {'Hani', 'Tang'}
+ 0x31F0, # .. 0x321F ; None
0x3220, # .. 0x3247 ; {'Hani'}
0x3248, # .. 0x327F ; None
0x3280, # .. 0x32B0 ; {'Hani'}
@@ -188,11 +258,13 @@ RANGES = [
0xA670, # .. 0xA6FF ; None
0xA700, # .. 0xA707 ; {'Hani', 'Latn'}
0xA708, # .. 0xA82F ; None
- 0xA830, # .. 0xA832 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Mlym', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'}
- 0xA833, # .. 0xA835 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'}
- 0xA836, # .. 0xA839 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Kthi', 'Mahj', 'Modi', 'Sind', 'Takr', 'Tirh'}
+ 0xA830, # .. 0xA832 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Mlym', 'Modi', 'Nand', 'Shrd', 'Sind', 'Takr', 'Tirh', 'Tutg'}
+ 0xA833, # .. 0xA835 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Modi', 'Nand', 'Shrd', 'Sind', 'Takr', 'Tirh', 'Tutg'}
+ 0xA836, # .. 0xA837 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Kthi', 'Mahj', 'Modi', 'Sind', 'Takr', 'Tirh'}
+ 0xA838, # .. 0xA838 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Kthi', 'Mahj', 'Modi', 'Shrd', 'Sind', 'Takr', 'Tirh'}
+ 0xA839, # .. 0xA839 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Kthi', 'Mahj', 'Modi', 'Sind', 'Takr', 'Tirh'}
0xA83A, # .. 0xA8F0 ; None
- 0xA8F1, # .. 0xA8F1 ; {'Beng', 'Deva'}
+ 0xA8F1, # .. 0xA8F1 ; {'Beng', 'Deva', 'Tutg'}
0xA8F2, # .. 0xA8F2 ; None
0xA8F3, # .. 0xA8F3 ; {'Deva', 'Taml'}
0xA8F4, # .. 0xA92D ; None
@@ -244,24 +316,110 @@ RANGES = [
]
VALUES = [
- None, # 0000..0341
+ None, # 0000..02BB
+ {"Beng", "Cyrl", "Deva", "Latn", "Lisu", "Thai", "Toto"}, # 02BC..02BC
+ None, # 02BD..02C6
+ {"Bopo", "Latn"}, # 02C7..02C7
+ None, # 02C8..02C8
+ {"Bopo", "Latn"}, # 02C9..02CB
+ None, # 02CC..02CC
+ {"Latn", "Lisu"}, # 02CD..02CD
+ None, # 02CE..02D6
+ {"Latn", "Thai"}, # 02D7..02D7
+ None, # 02D8..02D8
+ {"Bopo", "Latn"}, # 02D9..02D9
+ None, # 02DA..02FF
+ {"Cher", "Copt", "Cyrl", "Grek", "Latn", "Perm", "Sunu", "Tale"}, # 0300..0300
+ {"Cher", "Cyrl", "Grek", "Latn", "Osge", "Sunu", "Tale", "Todr"}, # 0301..0301
+ {"Cher", "Cyrl", "Latn", "Tfng"}, # 0302..0302
+ {"Glag", "Latn", "Sunu", "Syrc", "Thai"}, # 0303..0303
+ {
+ "Aghb",
+ "Cher",
+ "Copt",
+ "Cyrl",
+ "Goth",
+ "Grek",
+ "Latn",
+ "Osge",
+ "Syrc",
+ "Tfng",
+ "Todr",
+ }, # 0304..0304
+ {"Copt", "Elba", "Glag", "Goth", "Kana", "Latn"}, # 0305..0305
+ {"Cyrl", "Grek", "Latn", "Perm"}, # 0306..0306
+ {
+ "Copt",
+ "Dupl",
+ "Hebr",
+ "Latn",
+ "Perm",
+ "Syrc",
+ "Tale",
+ "Tfng",
+ "Todr",
+ }, # 0307..0307
+ {
+ "Armn",
+ "Cyrl",
+ "Dupl",
+ "Goth",
+ "Grek",
+ "Hebr",
+ "Latn",
+ "Perm",
+ "Syrc",
+ "Tale",
+ }, # 0308..0308
+ {"Latn", "Tfng"}, # 0309..0309
+ {"Dupl", "Latn", "Syrc"}, # 030A..030A
+ {"Cher", "Cyrl", "Latn", "Osge"}, # 030B..030B
+ {"Cher", "Latn", "Tale"}, # 030C..030C
+ {"Latn", "Sunu"}, # 030D..030D
+ {"Ethi", "Latn"}, # 030E..030E
+ None, # 030F..030F
+ {"Latn", "Sunu"}, # 0310..0310
+ {"Cyrl", "Latn", "Todr"}, # 0311..0311
+ None, # 0312..0312
+ {"Grek", "Latn", "Perm", "Todr"}, # 0313..0313
+ None, # 0314..031F
+ {"Latn", "Syrc"}, # 0320..0320
+ None, # 0321..0322
+ {"Cher", "Dupl", "Kana", "Latn", "Syrc"}, # 0323..0323
+ {"Cher", "Dupl", "Latn", "Syrc"}, # 0324..0324
+ {"Latn", "Syrc"}, # 0325..0325
+ None, # 0326..032C
+ {"Latn", "Sunu", "Syrc"}, # 032D..032D
+ {"Latn", "Syrc"}, # 032E..032E
+ None, # 032F..032F
+ {"Cher", "Latn", "Syrc"}, # 0330..0330
+ {"Aghb", "Cher", "Goth", "Latn", "Sunu", "Thai"}, # 0331..0331
+ None, # 0332..0341
{"Grek"}, # 0342..0342
None, # 0343..0344
{"Grek"}, # 0345..0345
- None, # 0346..0362
+ None, # 0346..0357
+ {"Latn", "Osge"}, # 0358..0358
+ None, # 0359..035D
+ {"Aghb", "Latn", "Todr"}, # 035E..035E
+ None, # 035F..0362
{"Latn"}, # 0363..036F
- None, # 0370..0482
+ None, # 0370..0373
+ {"Copt", "Grek"}, # 0374..0375
+ None, # 0376..0482
{"Cyrl", "Perm"}, # 0483..0483
{"Cyrl", "Glag"}, # 0484..0484
{"Cyrl", "Latn"}, # 0485..0486
{"Cyrl", "Glag"}, # 0487..0487
- None, # 0488..060B
- {"Arab", "Nkoo", "Rohg", "Syrc", "Thaa", "Yezi"}, # 060C..060C
+ None, # 0488..0588
+ {"Armn", "Geor", "Glag"}, # 0589..0589
+ None, # 058A..060B
+ {"Arab", "Gara", "Nkoo", "Rohg", "Syrc", "Thaa", "Yezi"}, # 060C..060C
None, # 060D..061A
- {"Arab", "Nkoo", "Rohg", "Syrc", "Thaa", "Yezi"}, # 061B..061B
+ {"Arab", "Gara", "Nkoo", "Rohg", "Syrc", "Thaa", "Yezi"}, # 061B..061B
{"Arab", "Syrc", "Thaa"}, # 061C..061C
None, # 061D..061E
- {"Adlm", "Arab", "Nkoo", "Rohg", "Syrc", "Thaa", "Yezi"}, # 061F..061F
+ {"Adlm", "Arab", "Gara", "Nkoo", "Rohg", "Syrc", "Thaa", "Yezi"}, # 061F..061F
None, # 0620..063F
{
"Adlm",
@@ -326,6 +484,7 @@ VALUES = [
"Mahj",
"Mlym",
"Nand",
+ "Onao",
"Orya",
"Sind",
"Sinh",
@@ -343,12 +502,14 @@ VALUES = [
"Gonm",
"Gran",
"Gujr",
+ "Gukh",
"Guru",
"Knda",
"Limb",
"Mahj",
"Mlym",
"Nand",
+ "Onao",
"Orya",
"Sind",
"Sinh",
@@ -368,12 +529,14 @@ VALUES = [
None, # 0AF0..0BE5
{"Gran", "Taml"}, # 0BE6..0BF3
None, # 0BF4..0CE5
- {"Knda", "Nand"}, # 0CE6..0CEF
+ {"Knda", "Nand", "Tutg"}, # 0CE6..0CEF
None, # 0CF0..103F
{"Cakm", "Mymr", "Tale"}, # 1040..1049
None, # 104A..10FA
- {"Geor", "Latn"}, # 10FB..10FB
- None, # 10FC..1734
+ {"Geor", "Glag", "Latn"}, # 10FB..10FB
+ None, # 10FC..16EA
+ {"Runr"}, # 16EB..16ED
+ None, # 16EE..1734
{"Buhd", "Hano", "Tagb", "Tglg"}, # 1735..1736
None, # 1737..1801
{"Mong", "Phag"}, # 1802..1803
@@ -383,7 +546,7 @@ VALUES = [
{"Beng", "Deva", "Gran", "Knda"}, # 1CD0..1CD0
{"Deva"}, # 1CD1..1CD1
{"Beng", "Deva", "Gran", "Knda"}, # 1CD2..1CD2
- {"Deva", "Gran"}, # 1CD3..1CD3
+ {"Deva", "Gran", "Knda"}, # 1CD3..1CD3
{"Deva"}, # 1CD4..1CD4
{"Beng", "Deva"}, # 1CD5..1CD6
{"Deva", "Shrd"}, # 1CD7..1CD7
@@ -401,9 +564,21 @@ VALUES = [
{"Deva"}, # 1CEB..1CEC
{"Beng", "Deva"}, # 1CED..1CED
{"Deva"}, # 1CEE..1CF1
- {"Beng", "Deva", "Gran", "Knda", "Nand", "Orya", "Telu", "Tirh"}, # 1CF2..1CF2
+ {
+ "Beng",
+ "Deva",
+ "Gran",
+ "Knda",
+ "Mlym",
+ "Nand",
+ "Orya",
+ "Sinh",
+ "Telu",
+ "Tirh",
+ "Tutg",
+ }, # 1CF2..1CF2
{"Deva", "Gran"}, # 1CF3..1CF3
- {"Deva", "Gran", "Knda"}, # 1CF4..1CF4
+ {"Deva", "Gran", "Knda", "Tutg"}, # 1CF4..1CF4
{"Beng", "Deva"}, # 1CF5..1CF6
{"Beng"}, # 1CF7..1CF7
{"Deva", "Gran"}, # 1CF8..1CF9
@@ -411,22 +586,52 @@ VALUES = [
None, # 1CFB..1DBF
{"Grek"}, # 1DC0..1DC1
None, # 1DC2..1DF7
- {"Cyrl", "Syrc"}, # 1DF8..1DF8
+ {"Cyrl", "Latn", "Syrc"}, # 1DF8..1DF8
None, # 1DF9..1DF9
{"Syrc"}, # 1DFA..1DFA
None, # 1DFB..202E
- {"Latn", "Mong"}, # 202F..202F
- None, # 2030..20EF
+ {"Latn", "Mong", "Phag"}, # 202F..202F
+ None, # 2030..204E
+ {"Adlm", "Arab"}, # 204F..204F
+ None, # 2050..2059
+ {"Cari", "Geor", "Glag", "Hung", "Lyci", "Orkh"}, # 205A..205A
+ None, # 205B..205C
+ {"Cari", "Grek", "Hung", "Mero"}, # 205D..205D
+ None, # 205E..20EF
{"Deva", "Gran", "Latn"}, # 20F0..20F0
- None, # 20F1..2E42
+ None, # 20F1..2E16
+ {"Copt", "Latn"}, # 2E17..2E17
+ None, # 2E18..2E2F
+ {"Avst", "Orkh"}, # 2E30..2E30
+ {"Avst", "Cari", "Geor", "Hung", "Kthi", "Lydi", "Samr"}, # 2E31..2E31
+ None, # 2E32..2E3B
+ {"Dupl"}, # 2E3C..2E3C
+ None, # 2E3D..2E40
+ {"Adlm", "Arab", "Hung"}, # 2E41..2E41
+ None, # 2E42..2E42
{"Cyrl", "Glag"}, # 2E43..2E43
- None, # 2E44..3000
- {"Bopo", "Hang", "Hani", "Hira", "Kana", "Yiii"}, # 3001..3002
+ None, # 2E44..2FEF
+ {"Hani", "Tang"}, # 2FF0..2FFF
+ None, # 3000..3000
+ {"Bopo", "Hang", "Hani", "Hira", "Kana", "Mong", "Yiii"}, # 3001..3001
+ {"Bopo", "Hang", "Hani", "Hira", "Kana", "Mong", "Phag", "Yiii"}, # 3002..3002
{"Bopo", "Hang", "Hani", "Hira", "Kana"}, # 3003..3003
None, # 3004..3005
{"Hani"}, # 3006..3006
None, # 3007..3007
- {"Bopo", "Hang", "Hani", "Hira", "Kana", "Yiii"}, # 3008..3011
+ {"Bopo", "Hang", "Hani", "Hira", "Kana", "Mong", "Tibt", "Yiii"}, # 3008..3009
+ {
+ "Bopo",
+ "Hang",
+ "Hani",
+ "Hira",
+ "Kana",
+ "Lisu",
+ "Mong",
+ "Tibt",
+ "Yiii",
+ }, # 300A..300B
+ {"Bopo", "Hang", "Hani", "Hira", "Kana", "Yiii"}, # 300C..3011
None, # 3012..3012
{"Bopo", "Hang", "Hani", "Hira", "Kana"}, # 3013..3013
{"Bopo", "Hang", "Hani", "Hira", "Kana", "Yiii"}, # 3014..301B
@@ -451,8 +656,10 @@ VALUES = [
None, # 30FD..318F
{"Hani"}, # 3190..319F
None, # 31A0..31BF
- {"Hani"}, # 31C0..31E3
- None, # 31E4..321F
+ {"Hani"}, # 31C0..31E5
+ None, # 31E6..31EE
+ {"Hani", "Tang"}, # 31EF..31EF
+ None, # 31F0..321F
{"Hani"}, # 3220..3247
None, # 3248..327F
{"Hani"}, # 3280..32B0
@@ -483,9 +690,11 @@ VALUES = [
"Mlym",
"Modi",
"Nand",
+ "Shrd",
"Sind",
"Takr",
"Tirh",
+ "Tutg",
}, # A830..A832
{
"Deva",
@@ -498,9 +707,11 @@ VALUES = [
"Mahj",
"Modi",
"Nand",
+ "Shrd",
"Sind",
"Takr",
"Tirh",
+ "Tutg",
}, # A833..A835
{
"Deva",
@@ -514,9 +725,36 @@ VALUES = [
"Sind",
"Takr",
"Tirh",
- }, # A836..A839
+ }, # A836..A837
+ {
+ "Deva",
+ "Dogr",
+ "Gujr",
+ "Guru",
+ "Khoj",
+ "Kthi",
+ "Mahj",
+ "Modi",
+ "Shrd",
+ "Sind",
+ "Takr",
+ "Tirh",
+ }, # A838..A838
+ {
+ "Deva",
+ "Dogr",
+ "Gujr",
+ "Guru",
+ "Khoj",
+ "Kthi",
+ "Mahj",
+ "Modi",
+ "Sind",
+ "Takr",
+ "Tirh",
+ }, # A839..A839
None, # A83A..A8F0
- {"Beng", "Deva"}, # A8F1..A8F1
+ {"Beng", "Deva", "Tutg"}, # A8F1..A8F1
None, # A8F2..A8F2
{"Deva", "Taml"}, # A8F3..A8F3
None, # A8F4..A92D
diff --git a/contrib/python/fonttools/fontTools/unicodedata/Scripts.py b/contrib/python/fonttools/fontTools/unicodedata/Scripts.py
index 68bb91b396..663998bade 100644
--- a/contrib/python/fonttools/fontTools/unicodedata/Scripts.py
+++ b/contrib/python/fonttools/fontTools/unicodedata/Scripts.py
@@ -4,11 +4,11 @@
# Source: https://unicode.org/Public/UNIDATA/Scripts.txt
# License: http://unicode.org/copyright.html#License
#
-# Scripts-15.0.0.txt
-# Date: 2022-04-26, 23:15:02 GMT
-# © 2022 Unicode®, Inc.
+# Scripts-16.0.0.txt
+# Date: 2024-04-30, 21:48:40 GMT
+# © 2024 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
-# For terms of use, see https://www.unicode.org/terms_of_use.html
+# For terms of use and license, see https://www.unicode.org/terms_of_use.html
#
# Unicode Character Database
# For documentation, see https://www.unicode.org/reports/tr44/
@@ -119,8 +119,8 @@ RANGES = [
0x0870, # .. 0x088E ; Arabic
0x088F, # .. 0x088F ; Unknown
0x0890, # .. 0x0891 ; Arabic
- 0x0892, # .. 0x0897 ; Unknown
- 0x0898, # .. 0x08E1 ; Arabic
+ 0x0892, # .. 0x0896 ; Unknown
+ 0x0897, # .. 0x08E1 ; Arabic
0x08E2, # .. 0x08E2 ; Common
0x08E3, # .. 0x08FF ; Arabic
0x0900, # .. 0x0950 ; Devanagari
@@ -533,9 +533,8 @@ RANGES = [
0x1AB0, # .. 0x1ACE ; Inherited
0x1ACF, # .. 0x1AFF ; Unknown
0x1B00, # .. 0x1B4C ; Balinese
- 0x1B4D, # .. 0x1B4F ; Unknown
- 0x1B50, # .. 0x1B7E ; Balinese
- 0x1B7F, # .. 0x1B7F ; Unknown
+ 0x1B4D, # .. 0x1B4D ; Unknown
+ 0x1B4E, # .. 0x1B7F ; Balinese
0x1B80, # .. 0x1BBF ; Sundanese
0x1BC0, # .. 0x1BF3 ; Batak
0x1BF4, # .. 0x1BFB ; Unknown
@@ -546,8 +545,8 @@ RANGES = [
0x1C4A, # .. 0x1C4C ; Unknown
0x1C4D, # .. 0x1C4F ; Lepcha
0x1C50, # .. 0x1C7F ; Ol_Chiki
- 0x1C80, # .. 0x1C88 ; Cyrillic
- 0x1C89, # .. 0x1C8F ; Unknown
+ 0x1C80, # .. 0x1C8A ; Cyrillic
+ 0x1C8B, # .. 0x1C8F ; Unknown
0x1C90, # .. 0x1CBA ; Georgian
0x1CBB, # .. 0x1CBC ; Unknown
0x1CBD, # .. 0x1CBF ; Georgian
@@ -640,8 +639,8 @@ RANGES = [
0x2160, # .. 0x2188 ; Latin
0x2189, # .. 0x218B ; Common
0x218C, # .. 0x218F ; Unknown
- 0x2190, # .. 0x2426 ; Common
- 0x2427, # .. 0x243F ; Unknown
+ 0x2190, # .. 0x2429 ; Common
+ 0x242A, # .. 0x243F ; Unknown
0x2440, # .. 0x244A ; Common
0x244B, # .. 0x245F ; Unknown
0x2460, # .. 0x27FF ; Common
@@ -694,9 +693,7 @@ RANGES = [
0x2EF4, # .. 0x2EFF ; Unknown
0x2F00, # .. 0x2FD5 ; Han
0x2FD6, # .. 0x2FEF ; Unknown
- 0x2FF0, # .. 0x2FFB ; Common
- 0x2FFC, # .. 0x2FFF ; Unknown
- 0x3000, # .. 0x3004 ; Common
+ 0x2FF0, # .. 0x3004 ; Common
0x3005, # .. 0x3005 ; Han
0x3006, # .. 0x3006 ; Common
0x3007, # .. 0x3007 ; Han
@@ -724,8 +721,9 @@ RANGES = [
0x318F, # .. 0x318F ; Unknown
0x3190, # .. 0x319F ; Common
0x31A0, # .. 0x31BF ; Bopomofo
- 0x31C0, # .. 0x31E3 ; Common
- 0x31E4, # .. 0x31EF ; Unknown
+ 0x31C0, # .. 0x31E5 ; Common
+ 0x31E6, # .. 0x31EE ; Unknown
+ 0x31EF, # .. 0x31EF ; Common
0x31F0, # .. 0x31FF ; Katakana
0x3200, # .. 0x321E ; Hangul
0x321F, # .. 0x321F ; Unknown
@@ -752,14 +750,14 @@ RANGES = [
0xA700, # .. 0xA721 ; Common
0xA722, # .. 0xA787 ; Latin
0xA788, # .. 0xA78A ; Common
- 0xA78B, # .. 0xA7CA ; Latin
- 0xA7CB, # .. 0xA7CF ; Unknown
+ 0xA78B, # .. 0xA7CD ; Latin
+ 0xA7CE, # .. 0xA7CF ; Unknown
0xA7D0, # .. 0xA7D1 ; Latin
0xA7D2, # .. 0xA7D2 ; Unknown
0xA7D3, # .. 0xA7D3 ; Latin
0xA7D4, # .. 0xA7D4 ; Unknown
- 0xA7D5, # .. 0xA7D9 ; Latin
- 0xA7DA, # .. 0xA7F1 ; Unknown
+ 0xA7D5, # .. 0xA7DC ; Latin
+ 0xA7DD, # .. 0xA7F1 ; Unknown
0xA7F2, # .. 0xA7FF ; Latin
0xA800, # .. 0xA82C ; Syloti_Nagri
0xA82D, # .. 0xA82F ; Unknown
@@ -980,7 +978,9 @@ RANGES = [
0x105B3, # .. 0x105B9 ; Vithkuqi
0x105BA, # .. 0x105BA ; Unknown
0x105BB, # .. 0x105BC ; Vithkuqi
- 0x105BD, # .. 0x105FF ; Unknown
+ 0x105BD, # .. 0x105BF ; Unknown
+ 0x105C0, # .. 0x105F3 ; Todhri
+ 0x105F4, # .. 0x105FF ; Unknown
0x10600, # .. 0x10736 ; Linear_A
0x10737, # .. 0x1073F ; Unknown
0x10740, # .. 0x10755 ; Linear_A
@@ -1078,7 +1078,13 @@ RANGES = [
0x10D00, # .. 0x10D27 ; Hanifi_Rohingya
0x10D28, # .. 0x10D2F ; Unknown
0x10D30, # .. 0x10D39 ; Hanifi_Rohingya
- 0x10D3A, # .. 0x10E5F ; Unknown
+ 0x10D3A, # .. 0x10D3F ; Unknown
+ 0x10D40, # .. 0x10D65 ; Garay
+ 0x10D66, # .. 0x10D68 ; Unknown
+ 0x10D69, # .. 0x10D85 ; Garay
+ 0x10D86, # .. 0x10D8D ; Unknown
+ 0x10D8E, # .. 0x10D8F ; Garay
+ 0x10D90, # .. 0x10E5F ; Unknown
0x10E60, # .. 0x10E7E ; Arabic
0x10E7F, # .. 0x10E7F ; Unknown
0x10E80, # .. 0x10EA9 ; Yezidi
@@ -1086,8 +1092,10 @@ RANGES = [
0x10EAB, # .. 0x10EAD ; Yezidi
0x10EAE, # .. 0x10EAF ; Unknown
0x10EB0, # .. 0x10EB1 ; Yezidi
- 0x10EB2, # .. 0x10EFC ; Unknown
- 0x10EFD, # .. 0x10EFF ; Arabic
+ 0x10EB2, # .. 0x10EC1 ; Unknown
+ 0x10EC2, # .. 0x10EC4 ; Arabic
+ 0x10EC5, # .. 0x10EFB ; Unknown
+ 0x10EFC, # .. 0x10EFF ; Arabic
0x10F00, # .. 0x10F27 ; Old_Sogdian
0x10F28, # .. 0x10F2F ; Unknown
0x10F30, # .. 0x10F59 ; Sogdian
@@ -1169,7 +1177,29 @@ RANGES = [
0x11366, # .. 0x1136C ; Grantha
0x1136D, # .. 0x1136F ; Unknown
0x11370, # .. 0x11374 ; Grantha
- 0x11375, # .. 0x113FF ; Unknown
+ 0x11375, # .. 0x1137F ; Unknown
+ 0x11380, # .. 0x11389 ; Tulu_Tigalari
+ 0x1138A, # .. 0x1138A ; Unknown
+ 0x1138B, # .. 0x1138B ; Tulu_Tigalari
+ 0x1138C, # .. 0x1138D ; Unknown
+ 0x1138E, # .. 0x1138E ; Tulu_Tigalari
+ 0x1138F, # .. 0x1138F ; Unknown
+ 0x11390, # .. 0x113B5 ; Tulu_Tigalari
+ 0x113B6, # .. 0x113B6 ; Unknown
+ 0x113B7, # .. 0x113C0 ; Tulu_Tigalari
+ 0x113C1, # .. 0x113C1 ; Unknown
+ 0x113C2, # .. 0x113C2 ; Tulu_Tigalari
+ 0x113C3, # .. 0x113C4 ; Unknown
+ 0x113C5, # .. 0x113C5 ; Tulu_Tigalari
+ 0x113C6, # .. 0x113C6 ; Unknown
+ 0x113C7, # .. 0x113CA ; Tulu_Tigalari
+ 0x113CB, # .. 0x113CB ; Unknown
+ 0x113CC, # .. 0x113D5 ; Tulu_Tigalari
+ 0x113D6, # .. 0x113D6 ; Unknown
+ 0x113D7, # .. 0x113D8 ; Tulu_Tigalari
+ 0x113D9, # .. 0x113E0 ; Unknown
+ 0x113E1, # .. 0x113E2 ; Tulu_Tigalari
+ 0x113E3, # .. 0x113FF ; Unknown
0x11400, # .. 0x1145B ; Newa
0x1145C, # .. 0x1145C ; Unknown
0x1145D, # .. 0x11461 ; Newa
@@ -1191,7 +1221,9 @@ RANGES = [
0x11680, # .. 0x116B9 ; Takri
0x116BA, # .. 0x116BF ; Unknown
0x116C0, # .. 0x116C9 ; Takri
- 0x116CA, # .. 0x116FF ; Unknown
+ 0x116CA, # .. 0x116CF ; Unknown
+ 0x116D0, # .. 0x116E3 ; Myanmar
+ 0x116E4, # .. 0x116FF ; Unknown
0x11700, # .. 0x1171A ; Ahom
0x1171B, # .. 0x1171C ; Unknown
0x1171D, # .. 0x1172B ; Ahom
@@ -1233,7 +1265,11 @@ RANGES = [
0x11AC0, # .. 0x11AF8 ; Pau_Cin_Hau
0x11AF9, # .. 0x11AFF ; Unknown
0x11B00, # .. 0x11B09 ; Devanagari
- 0x11B0A, # .. 0x11BFF ; Unknown
+ 0x11B0A, # .. 0x11BBF ; Unknown
+ 0x11BC0, # .. 0x11BE1 ; Sunuwar
+ 0x11BE2, # .. 0x11BEF ; Unknown
+ 0x11BF0, # .. 0x11BF9 ; Sunuwar
+ 0x11BFA, # .. 0x11BFF ; Unknown
0x11C00, # .. 0x11C08 ; Bhaiksuki
0x11C09, # .. 0x11C09 ; Unknown
0x11C0A, # .. 0x11C36 ; Bhaiksuki
@@ -1280,8 +1316,8 @@ RANGES = [
0x11F11, # .. 0x11F11 ; Unknown
0x11F12, # .. 0x11F3A ; Kawi
0x11F3B, # .. 0x11F3D ; Unknown
- 0x11F3E, # .. 0x11F59 ; Kawi
- 0x11F5A, # .. 0x11FAF ; Unknown
+ 0x11F3E, # .. 0x11F5A ; Kawi
+ 0x11F5B, # .. 0x11FAF ; Unknown
0x11FB0, # .. 0x11FB0 ; Lisu
0x11FB1, # .. 0x11FBF ; Unknown
0x11FC0, # .. 0x11FF1 ; Tamil
@@ -1298,9 +1334,13 @@ RANGES = [
0x12F90, # .. 0x12FF2 ; Cypro_Minoan
0x12FF3, # .. 0x12FFF ; Unknown
0x13000, # .. 0x13455 ; Egyptian_Hieroglyphs
- 0x13456, # .. 0x143FF ; Unknown
+ 0x13456, # .. 0x1345F ; Unknown
+ 0x13460, # .. 0x143FA ; Egyptian_Hieroglyphs
+ 0x143FB, # .. 0x143FF ; Unknown
0x14400, # .. 0x14646 ; Anatolian_Hieroglyphs
- 0x14647, # .. 0x167FF ; Unknown
+ 0x14647, # .. 0x160FF ; Unknown
+ 0x16100, # .. 0x16139 ; Gurung_Khema
+ 0x1613A, # .. 0x167FF ; Unknown
0x16800, # .. 0x16A38 ; Bamum
0x16A39, # .. 0x16A3F ; Unknown
0x16A40, # .. 0x16A5E ; Mro
@@ -1325,7 +1365,9 @@ RANGES = [
0x16B63, # .. 0x16B77 ; Pahawh_Hmong
0x16B78, # .. 0x16B7C ; Unknown
0x16B7D, # .. 0x16B8F ; Pahawh_Hmong
- 0x16B90, # .. 0x16E3F ; Unknown
+ 0x16B90, # .. 0x16D3F ; Unknown
+ 0x16D40, # .. 0x16D79 ; Kirat_Rai
+ 0x16D7A, # .. 0x16E3F ; Unknown
0x16E40, # .. 0x16E9A ; Medefaidrin
0x16E9B, # .. 0x16EFF ; Unknown
0x16F00, # .. 0x16F4A ; Miao
@@ -1345,7 +1387,8 @@ RANGES = [
0x187F8, # .. 0x187FF ; Unknown
0x18800, # .. 0x18AFF ; Tangut
0x18B00, # .. 0x18CD5 ; Khitan_Small_Script
- 0x18CD6, # .. 0x18CFF ; Unknown
+ 0x18CD6, # .. 0x18CFE ; Unknown
+ 0x18CFF, # .. 0x18CFF ; Khitan_Small_Script
0x18D00, # .. 0x18D08 ; Tangut
0x18D09, # .. 0x1AFEF ; Unknown
0x1AFF0, # .. 0x1AFF3 ; Katakana
@@ -1378,7 +1421,11 @@ RANGES = [
0x1BC9A, # .. 0x1BC9B ; Unknown
0x1BC9C, # .. 0x1BC9F ; Duployan
0x1BCA0, # .. 0x1BCA3 ; Common
- 0x1BCA4, # .. 0x1CEFF ; Unknown
+ 0x1BCA4, # .. 0x1CBFF ; Unknown
+ 0x1CC00, # .. 0x1CCF9 ; Common
+ 0x1CCFA, # .. 0x1CCFF ; Unknown
+ 0x1CD00, # .. 0x1CEB3 ; Common
+ 0x1CEB4, # .. 0x1CEFF ; Unknown
0x1CF00, # .. 0x1CF2D ; Inherited
0x1CF2E, # .. 0x1CF2F ; Unknown
0x1CF30, # .. 0x1CF46 ; Inherited
@@ -1489,7 +1536,11 @@ RANGES = [
0x1E2FF, # .. 0x1E2FF ; Wancho
0x1E300, # .. 0x1E4CF ; Unknown
0x1E4D0, # .. 0x1E4F9 ; Nag_Mundari
- 0x1E4FA, # .. 0x1E7DF ; Unknown
+ 0x1E4FA, # .. 0x1E5CF ; Unknown
+ 0x1E5D0, # .. 0x1E5FA ; Ol_Onal
+ 0x1E5FB, # .. 0x1E5FE ; Unknown
+ 0x1E5FF, # .. 0x1E5FF ; Ol_Onal
+ 0x1E600, # .. 0x1E7DF ; Unknown
0x1E7E0, # .. 0x1E7E6 ; Ethiopic
0x1E7E7, # .. 0x1E7E7 ; Unknown
0x1E7E8, # .. 0x1E7EB ; Ethiopic
@@ -1630,31 +1681,29 @@ RANGES = [
0x1F888, # .. 0x1F88F ; Unknown
0x1F890, # .. 0x1F8AD ; Common
0x1F8AE, # .. 0x1F8AF ; Unknown
- 0x1F8B0, # .. 0x1F8B1 ; Common
- 0x1F8B2, # .. 0x1F8FF ; Unknown
+ 0x1F8B0, # .. 0x1F8BB ; Common
+ 0x1F8BC, # .. 0x1F8BF ; Unknown
+ 0x1F8C0, # .. 0x1F8C1 ; Common
+ 0x1F8C2, # .. 0x1F8FF ; Unknown
0x1F900, # .. 0x1FA53 ; Common
0x1FA54, # .. 0x1FA5F ; Unknown
0x1FA60, # .. 0x1FA6D ; Common
0x1FA6E, # .. 0x1FA6F ; Unknown
0x1FA70, # .. 0x1FA7C ; Common
0x1FA7D, # .. 0x1FA7F ; Unknown
- 0x1FA80, # .. 0x1FA88 ; Common
- 0x1FA89, # .. 0x1FA8F ; Unknown
- 0x1FA90, # .. 0x1FABD ; Common
- 0x1FABE, # .. 0x1FABE ; Unknown
- 0x1FABF, # .. 0x1FAC5 ; Common
- 0x1FAC6, # .. 0x1FACD ; Unknown
- 0x1FACE, # .. 0x1FADB ; Common
- 0x1FADC, # .. 0x1FADF ; Unknown
- 0x1FAE0, # .. 0x1FAE8 ; Common
- 0x1FAE9, # .. 0x1FAEF ; Unknown
+ 0x1FA80, # .. 0x1FA89 ; Common
+ 0x1FA8A, # .. 0x1FA8E ; Unknown
+ 0x1FA8F, # .. 0x1FAC6 ; Common
+ 0x1FAC7, # .. 0x1FACD ; Unknown
+ 0x1FACE, # .. 0x1FADC ; Common
+ 0x1FADD, # .. 0x1FADE ; Unknown
+ 0x1FADF, # .. 0x1FAE9 ; Common
+ 0x1FAEA, # .. 0x1FAEF ; Unknown
0x1FAF0, # .. 0x1FAF8 ; Common
0x1FAF9, # .. 0x1FAFF ; Unknown
0x1FB00, # .. 0x1FB92 ; Common
0x1FB93, # .. 0x1FB93 ; Unknown
- 0x1FB94, # .. 0x1FBCA ; Common
- 0x1FBCB, # .. 0x1FBEF ; Unknown
- 0x1FBF0, # .. 0x1FBF9 ; Common
+ 0x1FB94, # .. 0x1FBF9 ; Common
0x1FBFA, # .. 0x1FFFF ; Unknown
0x20000, # .. 0x2A6DF ; Han
0x2A6E0, # .. 0x2A6FF ; Unknown
@@ -1665,7 +1714,9 @@ RANGES = [
0x2B820, # .. 0x2CEA1 ; Han
0x2CEA2, # .. 0x2CEAF ; Unknown
0x2CEB0, # .. 0x2EBE0 ; Han
- 0x2EBE1, # .. 0x2F7FF ; Unknown
+ 0x2EBE1, # .. 0x2EBEF ; Unknown
+ 0x2EBF0, # .. 0x2EE5D ; Han
+ 0x2EE5E, # .. 0x2F7FF ; Unknown
0x2F800, # .. 0x2FA1D ; Han
0x2FA1E, # .. 0x2FFFF ; Unknown
0x30000, # .. 0x3134A ; Han
@@ -1779,8 +1830,8 @@ VALUES = [
"Arab", # 0870..088E ; Arabic
"Zzzz", # 088F..088F ; Unknown
"Arab", # 0890..0891 ; Arabic
- "Zzzz", # 0892..0897 ; Unknown
- "Arab", # 0898..08E1 ; Arabic
+ "Zzzz", # 0892..0896 ; Unknown
+ "Arab", # 0897..08E1 ; Arabic
"Zyyy", # 08E2..08E2 ; Common
"Arab", # 08E3..08FF ; Arabic
"Deva", # 0900..0950 ; Devanagari
@@ -2193,9 +2244,8 @@ VALUES = [
"Zinh", # 1AB0..1ACE ; Inherited
"Zzzz", # 1ACF..1AFF ; Unknown
"Bali", # 1B00..1B4C ; Balinese
- "Zzzz", # 1B4D..1B4F ; Unknown
- "Bali", # 1B50..1B7E ; Balinese
- "Zzzz", # 1B7F..1B7F ; Unknown
+ "Zzzz", # 1B4D..1B4D ; Unknown
+ "Bali", # 1B4E..1B7F ; Balinese
"Sund", # 1B80..1BBF ; Sundanese
"Batk", # 1BC0..1BF3 ; Batak
"Zzzz", # 1BF4..1BFB ; Unknown
@@ -2206,8 +2256,8 @@ VALUES = [
"Zzzz", # 1C4A..1C4C ; Unknown
"Lepc", # 1C4D..1C4F ; Lepcha
"Olck", # 1C50..1C7F ; Ol_Chiki
- "Cyrl", # 1C80..1C88 ; Cyrillic
- "Zzzz", # 1C89..1C8F ; Unknown
+ "Cyrl", # 1C80..1C8A ; Cyrillic
+ "Zzzz", # 1C8B..1C8F ; Unknown
"Geor", # 1C90..1CBA ; Georgian
"Zzzz", # 1CBB..1CBC ; Unknown
"Geor", # 1CBD..1CBF ; Georgian
@@ -2300,8 +2350,8 @@ VALUES = [
"Latn", # 2160..2188 ; Latin
"Zyyy", # 2189..218B ; Common
"Zzzz", # 218C..218F ; Unknown
- "Zyyy", # 2190..2426 ; Common
- "Zzzz", # 2427..243F ; Unknown
+ "Zyyy", # 2190..2429 ; Common
+ "Zzzz", # 242A..243F ; Unknown
"Zyyy", # 2440..244A ; Common
"Zzzz", # 244B..245F ; Unknown
"Zyyy", # 2460..27FF ; Common
@@ -2354,9 +2404,7 @@ VALUES = [
"Zzzz", # 2EF4..2EFF ; Unknown
"Hani", # 2F00..2FD5 ; Han
"Zzzz", # 2FD6..2FEF ; Unknown
- "Zyyy", # 2FF0..2FFB ; Common
- "Zzzz", # 2FFC..2FFF ; Unknown
- "Zyyy", # 3000..3004 ; Common
+ "Zyyy", # 2FF0..3004 ; Common
"Hani", # 3005..3005 ; Han
"Zyyy", # 3006..3006 ; Common
"Hani", # 3007..3007 ; Han
@@ -2384,8 +2432,9 @@ VALUES = [
"Zzzz", # 318F..318F ; Unknown
"Zyyy", # 3190..319F ; Common
"Bopo", # 31A0..31BF ; Bopomofo
- "Zyyy", # 31C0..31E3 ; Common
- "Zzzz", # 31E4..31EF ; Unknown
+ "Zyyy", # 31C0..31E5 ; Common
+ "Zzzz", # 31E6..31EE ; Unknown
+ "Zyyy", # 31EF..31EF ; Common
"Kana", # 31F0..31FF ; Katakana
"Hang", # 3200..321E ; Hangul
"Zzzz", # 321F..321F ; Unknown
@@ -2412,14 +2461,14 @@ VALUES = [
"Zyyy", # A700..A721 ; Common
"Latn", # A722..A787 ; Latin
"Zyyy", # A788..A78A ; Common
- "Latn", # A78B..A7CA ; Latin
- "Zzzz", # A7CB..A7CF ; Unknown
+ "Latn", # A78B..A7CD ; Latin
+ "Zzzz", # A7CE..A7CF ; Unknown
"Latn", # A7D0..A7D1 ; Latin
"Zzzz", # A7D2..A7D2 ; Unknown
"Latn", # A7D3..A7D3 ; Latin
"Zzzz", # A7D4..A7D4 ; Unknown
- "Latn", # A7D5..A7D9 ; Latin
- "Zzzz", # A7DA..A7F1 ; Unknown
+ "Latn", # A7D5..A7DC ; Latin
+ "Zzzz", # A7DD..A7F1 ; Unknown
"Latn", # A7F2..A7FF ; Latin
"Sylo", # A800..A82C ; Syloti_Nagri
"Zzzz", # A82D..A82F ; Unknown
@@ -2640,7 +2689,9 @@ VALUES = [
"Vith", # 105B3..105B9 ; Vithkuqi
"Zzzz", # 105BA..105BA ; Unknown
"Vith", # 105BB..105BC ; Vithkuqi
- "Zzzz", # 105BD..105FF ; Unknown
+ "Zzzz", # 105BD..105BF ; Unknown
+ "Todr", # 105C0..105F3 ; Todhri
+ "Zzzz", # 105F4..105FF ; Unknown
"Lina", # 10600..10736 ; Linear_A
"Zzzz", # 10737..1073F ; Unknown
"Lina", # 10740..10755 ; Linear_A
@@ -2738,7 +2789,13 @@ VALUES = [
"Rohg", # 10D00..10D27 ; Hanifi_Rohingya
"Zzzz", # 10D28..10D2F ; Unknown
"Rohg", # 10D30..10D39 ; Hanifi_Rohingya
- "Zzzz", # 10D3A..10E5F ; Unknown
+ "Zzzz", # 10D3A..10D3F ; Unknown
+ "Gara", # 10D40..10D65 ; Garay
+ "Zzzz", # 10D66..10D68 ; Unknown
+ "Gara", # 10D69..10D85 ; Garay
+ "Zzzz", # 10D86..10D8D ; Unknown
+ "Gara", # 10D8E..10D8F ; Garay
+ "Zzzz", # 10D90..10E5F ; Unknown
"Arab", # 10E60..10E7E ; Arabic
"Zzzz", # 10E7F..10E7F ; Unknown
"Yezi", # 10E80..10EA9 ; Yezidi
@@ -2746,8 +2803,10 @@ VALUES = [
"Yezi", # 10EAB..10EAD ; Yezidi
"Zzzz", # 10EAE..10EAF ; Unknown
"Yezi", # 10EB0..10EB1 ; Yezidi
- "Zzzz", # 10EB2..10EFC ; Unknown
- "Arab", # 10EFD..10EFF ; Arabic
+ "Zzzz", # 10EB2..10EC1 ; Unknown
+ "Arab", # 10EC2..10EC4 ; Arabic
+ "Zzzz", # 10EC5..10EFB ; Unknown
+ "Arab", # 10EFC..10EFF ; Arabic
"Sogo", # 10F00..10F27 ; Old_Sogdian
"Zzzz", # 10F28..10F2F ; Unknown
"Sogd", # 10F30..10F59 ; Sogdian
@@ -2829,7 +2888,29 @@ VALUES = [
"Gran", # 11366..1136C ; Grantha
"Zzzz", # 1136D..1136F ; Unknown
"Gran", # 11370..11374 ; Grantha
- "Zzzz", # 11375..113FF ; Unknown
+ "Zzzz", # 11375..1137F ; Unknown
+ "Tutg", # 11380..11389 ; Tulu_Tigalari
+ "Zzzz", # 1138A..1138A ; Unknown
+ "Tutg", # 1138B..1138B ; Tulu_Tigalari
+ "Zzzz", # 1138C..1138D ; Unknown
+ "Tutg", # 1138E..1138E ; Tulu_Tigalari
+ "Zzzz", # 1138F..1138F ; Unknown
+ "Tutg", # 11390..113B5 ; Tulu_Tigalari
+ "Zzzz", # 113B6..113B6 ; Unknown
+ "Tutg", # 113B7..113C0 ; Tulu_Tigalari
+ "Zzzz", # 113C1..113C1 ; Unknown
+ "Tutg", # 113C2..113C2 ; Tulu_Tigalari
+ "Zzzz", # 113C3..113C4 ; Unknown
+ "Tutg", # 113C5..113C5 ; Tulu_Tigalari
+ "Zzzz", # 113C6..113C6 ; Unknown
+ "Tutg", # 113C7..113CA ; Tulu_Tigalari
+ "Zzzz", # 113CB..113CB ; Unknown
+ "Tutg", # 113CC..113D5 ; Tulu_Tigalari
+ "Zzzz", # 113D6..113D6 ; Unknown
+ "Tutg", # 113D7..113D8 ; Tulu_Tigalari
+ "Zzzz", # 113D9..113E0 ; Unknown
+ "Tutg", # 113E1..113E2 ; Tulu_Tigalari
+ "Zzzz", # 113E3..113FF ; Unknown
"Newa", # 11400..1145B ; Newa
"Zzzz", # 1145C..1145C ; Unknown
"Newa", # 1145D..11461 ; Newa
@@ -2851,7 +2932,9 @@ VALUES = [
"Takr", # 11680..116B9 ; Takri
"Zzzz", # 116BA..116BF ; Unknown
"Takr", # 116C0..116C9 ; Takri
- "Zzzz", # 116CA..116FF ; Unknown
+ "Zzzz", # 116CA..116CF ; Unknown
+ "Mymr", # 116D0..116E3 ; Myanmar
+ "Zzzz", # 116E4..116FF ; Unknown
"Ahom", # 11700..1171A ; Ahom
"Zzzz", # 1171B..1171C ; Unknown
"Ahom", # 1171D..1172B ; Ahom
@@ -2893,7 +2976,11 @@ VALUES = [
"Pauc", # 11AC0..11AF8 ; Pau_Cin_Hau
"Zzzz", # 11AF9..11AFF ; Unknown
"Deva", # 11B00..11B09 ; Devanagari
- "Zzzz", # 11B0A..11BFF ; Unknown
+ "Zzzz", # 11B0A..11BBF ; Unknown
+ "Sunu", # 11BC0..11BE1 ; Sunuwar
+ "Zzzz", # 11BE2..11BEF ; Unknown
+ "Sunu", # 11BF0..11BF9 ; Sunuwar
+ "Zzzz", # 11BFA..11BFF ; Unknown
"Bhks", # 11C00..11C08 ; Bhaiksuki
"Zzzz", # 11C09..11C09 ; Unknown
"Bhks", # 11C0A..11C36 ; Bhaiksuki
@@ -2940,8 +3027,8 @@ VALUES = [
"Zzzz", # 11F11..11F11 ; Unknown
"Kawi", # 11F12..11F3A ; Kawi
"Zzzz", # 11F3B..11F3D ; Unknown
- "Kawi", # 11F3E..11F59 ; Kawi
- "Zzzz", # 11F5A..11FAF ; Unknown
+ "Kawi", # 11F3E..11F5A ; Kawi
+ "Zzzz", # 11F5B..11FAF ; Unknown
"Lisu", # 11FB0..11FB0 ; Lisu
"Zzzz", # 11FB1..11FBF ; Unknown
"Taml", # 11FC0..11FF1 ; Tamil
@@ -2958,9 +3045,13 @@ VALUES = [
"Cpmn", # 12F90..12FF2 ; Cypro_Minoan
"Zzzz", # 12FF3..12FFF ; Unknown
"Egyp", # 13000..13455 ; Egyptian_Hieroglyphs
- "Zzzz", # 13456..143FF ; Unknown
+ "Zzzz", # 13456..1345F ; Unknown
+ "Egyp", # 13460..143FA ; Egyptian_Hieroglyphs
+ "Zzzz", # 143FB..143FF ; Unknown
"Hluw", # 14400..14646 ; Anatolian_Hieroglyphs
- "Zzzz", # 14647..167FF ; Unknown
+ "Zzzz", # 14647..160FF ; Unknown
+ "Gukh", # 16100..16139 ; Gurung_Khema
+ "Zzzz", # 1613A..167FF ; Unknown
"Bamu", # 16800..16A38 ; Bamum
"Zzzz", # 16A39..16A3F ; Unknown
"Mroo", # 16A40..16A5E ; Mro
@@ -2985,7 +3076,9 @@ VALUES = [
"Hmng", # 16B63..16B77 ; Pahawh_Hmong
"Zzzz", # 16B78..16B7C ; Unknown
"Hmng", # 16B7D..16B8F ; Pahawh_Hmong
- "Zzzz", # 16B90..16E3F ; Unknown
+ "Zzzz", # 16B90..16D3F ; Unknown
+ "Krai", # 16D40..16D79 ; Kirat_Rai
+ "Zzzz", # 16D7A..16E3F ; Unknown
"Medf", # 16E40..16E9A ; Medefaidrin
"Zzzz", # 16E9B..16EFF ; Unknown
"Plrd", # 16F00..16F4A ; Miao
@@ -3005,7 +3098,8 @@ VALUES = [
"Zzzz", # 187F8..187FF ; Unknown
"Tang", # 18800..18AFF ; Tangut
"Kits", # 18B00..18CD5 ; Khitan_Small_Script
- "Zzzz", # 18CD6..18CFF ; Unknown
+ "Zzzz", # 18CD6..18CFE ; Unknown
+ "Kits", # 18CFF..18CFF ; Khitan_Small_Script
"Tang", # 18D00..18D08 ; Tangut
"Zzzz", # 18D09..1AFEF ; Unknown
"Kana", # 1AFF0..1AFF3 ; Katakana
@@ -3038,7 +3132,11 @@ VALUES = [
"Zzzz", # 1BC9A..1BC9B ; Unknown
"Dupl", # 1BC9C..1BC9F ; Duployan
"Zyyy", # 1BCA0..1BCA3 ; Common
- "Zzzz", # 1BCA4..1CEFF ; Unknown
+ "Zzzz", # 1BCA4..1CBFF ; Unknown
+ "Zyyy", # 1CC00..1CCF9 ; Common
+ "Zzzz", # 1CCFA..1CCFF ; Unknown
+ "Zyyy", # 1CD00..1CEB3 ; Common
+ "Zzzz", # 1CEB4..1CEFF ; Unknown
"Zinh", # 1CF00..1CF2D ; Inherited
"Zzzz", # 1CF2E..1CF2F ; Unknown
"Zinh", # 1CF30..1CF46 ; Inherited
@@ -3149,7 +3247,11 @@ VALUES = [
"Wcho", # 1E2FF..1E2FF ; Wancho
"Zzzz", # 1E300..1E4CF ; Unknown
"Nagm", # 1E4D0..1E4F9 ; Nag_Mundari
- "Zzzz", # 1E4FA..1E7DF ; Unknown
+ "Zzzz", # 1E4FA..1E5CF ; Unknown
+ "Onao", # 1E5D0..1E5FA ; Ol_Onal
+ "Zzzz", # 1E5FB..1E5FE ; Unknown
+ "Onao", # 1E5FF..1E5FF ; Ol_Onal
+ "Zzzz", # 1E600..1E7DF ; Unknown
"Ethi", # 1E7E0..1E7E6 ; Ethiopic
"Zzzz", # 1E7E7..1E7E7 ; Unknown
"Ethi", # 1E7E8..1E7EB ; Ethiopic
@@ -3290,31 +3392,29 @@ VALUES = [
"Zzzz", # 1F888..1F88F ; Unknown
"Zyyy", # 1F890..1F8AD ; Common
"Zzzz", # 1F8AE..1F8AF ; Unknown
- "Zyyy", # 1F8B0..1F8B1 ; Common
- "Zzzz", # 1F8B2..1F8FF ; Unknown
+ "Zyyy", # 1F8B0..1F8BB ; Common
+ "Zzzz", # 1F8BC..1F8BF ; Unknown
+ "Zyyy", # 1F8C0..1F8C1 ; Common
+ "Zzzz", # 1F8C2..1F8FF ; Unknown
"Zyyy", # 1F900..1FA53 ; Common
"Zzzz", # 1FA54..1FA5F ; Unknown
"Zyyy", # 1FA60..1FA6D ; Common
"Zzzz", # 1FA6E..1FA6F ; Unknown
"Zyyy", # 1FA70..1FA7C ; Common
"Zzzz", # 1FA7D..1FA7F ; Unknown
- "Zyyy", # 1FA80..1FA88 ; Common
- "Zzzz", # 1FA89..1FA8F ; Unknown
- "Zyyy", # 1FA90..1FABD ; Common
- "Zzzz", # 1FABE..1FABE ; Unknown
- "Zyyy", # 1FABF..1FAC5 ; Common
- "Zzzz", # 1FAC6..1FACD ; Unknown
- "Zyyy", # 1FACE..1FADB ; Common
- "Zzzz", # 1FADC..1FADF ; Unknown
- "Zyyy", # 1FAE0..1FAE8 ; Common
- "Zzzz", # 1FAE9..1FAEF ; Unknown
+ "Zyyy", # 1FA80..1FA89 ; Common
+ "Zzzz", # 1FA8A..1FA8E ; Unknown
+ "Zyyy", # 1FA8F..1FAC6 ; Common
+ "Zzzz", # 1FAC7..1FACD ; Unknown
+ "Zyyy", # 1FACE..1FADC ; Common
+ "Zzzz", # 1FADD..1FADE ; Unknown
+ "Zyyy", # 1FADF..1FAE9 ; Common
+ "Zzzz", # 1FAEA..1FAEF ; Unknown
"Zyyy", # 1FAF0..1FAF8 ; Common
"Zzzz", # 1FAF9..1FAFF ; Unknown
"Zyyy", # 1FB00..1FB92 ; Common
"Zzzz", # 1FB93..1FB93 ; Unknown
- "Zyyy", # 1FB94..1FBCA ; Common
- "Zzzz", # 1FBCB..1FBEF ; Unknown
- "Zyyy", # 1FBF0..1FBF9 ; Common
+ "Zyyy", # 1FB94..1FBF9 ; Common
"Zzzz", # 1FBFA..1FFFF ; Unknown
"Hani", # 20000..2A6DF ; Han
"Zzzz", # 2A6E0..2A6FF ; Unknown
@@ -3325,7 +3425,9 @@ VALUES = [
"Hani", # 2B820..2CEA1 ; Han
"Zzzz", # 2CEA2..2CEAF ; Unknown
"Hani", # 2CEB0..2EBE0 ; Han
- "Zzzz", # 2EBE1..2F7FF ; Unknown
+ "Zzzz", # 2EBE1..2EBEF ; Unknown
+ "Hani", # 2EBF0..2EE5D ; Han
+ "Zzzz", # 2EE5E..2F7FF ; Unknown
"Hani", # 2F800..2FA1D ; Han
"Zzzz", # 2FA1E..2FFFF ; Unknown
"Hani", # 30000..3134A ; Han
@@ -3378,6 +3480,7 @@ NAMES = {
"Elba": "Elbasan",
"Elym": "Elymaic",
"Ethi": "Ethiopic",
+ "Gara": "Garay",
"Geor": "Georgian",
"Glag": "Glagolitic",
"Gong": "Gunjala_Gondi",
@@ -3386,6 +3489,7 @@ NAMES = {
"Gran": "Grantha",
"Grek": "Greek",
"Gujr": "Gujarati",
+ "Gukh": "Gurung_Khema",
"Guru": "Gurmukhi",
"Hang": "Hangul",
"Hani": "Han",
@@ -3408,6 +3512,7 @@ NAMES = {
"Khoj": "Khojki",
"Kits": "Khitan_Small_Script",
"Knda": "Kannada",
+ "Krai": "Kirat_Rai",
"Kthi": "Kaithi",
"Lana": "Tai_Tham",
"Laoo": "Lao",
@@ -3444,6 +3549,7 @@ NAMES = {
"Nshu": "Nushu",
"Ogam": "Ogham",
"Olck": "Ol_Chiki",
+ "Onao": "Ol_Onal",
"Orkh": "Old_Turkic",
"Orya": "Oriya",
"Osge": "Osage",
@@ -3475,6 +3581,7 @@ NAMES = {
"Sora": "Sora_Sompeng",
"Soyo": "Soyombo",
"Sund": "Sundanese",
+ "Sunu": "Sunuwar",
"Sylo": "Syloti_Nagri",
"Syrc": "Syriac",
"Tagb": "Tagbanwa",
@@ -3492,7 +3599,9 @@ NAMES = {
"Tibt": "Tibetan",
"Tirh": "Tirhuta",
"Tnsa": "Tangsa",
+ "Todr": "Todhri",
"Toto": "Toto",
+ "Tutg": "Tulu_Tigalari",
"Ugar": "Ugaritic",
"Vaii": "Vai",
"Vith": "Vithkuqi",
diff --git a/contrib/python/fonttools/fontTools/unicodedata/__init__.py b/contrib/python/fonttools/fontTools/unicodedata/__init__.py
index 06eb4619a9..edae44ec71 100644
--- a/contrib/python/fonttools/fontTools/unicodedata/__init__.py
+++ b/contrib/python/fonttools/fontTools/unicodedata/__init__.py
@@ -77,7 +77,7 @@ def script_extension(char):
>>> script_extension("a") == {'Latn'}
True
- >>> script_extension(chr(0x060C)) == {'Rohg', 'Syrc', 'Yezi', 'Arab', 'Thaa', 'Nkoo'}
+ >>> script_extension(chr(0x060C)) == {'Nkoo', 'Arab', 'Rohg', 'Thaa', 'Syrc', 'Gara', 'Yezi'}
True
>>> script_extension(chr(0x10FFFF)) == {'Zzzz'}
True
diff --git a/contrib/python/fonttools/fontTools/varLib/__init__.py b/contrib/python/fonttools/fontTools/varLib/__init__.py
index 6d0e00ee10..36b1851cba 100644
--- a/contrib/python/fonttools/fontTools/varLib/__init__.py
+++ b/contrib/python/fonttools/fontTools/varLib/__init__.py
@@ -10,10 +10,14 @@ ttf-interpolatable files for the masters and build a variable-font from
them. Such ttf-interpolatable and designspace files can be generated from
a Glyphs source, eg., using noto-source as an example:
+ .. code-block:: sh
+
$ fontmake -o ttf-interpolatable -g NotoSansArabic-MM.glyphs
Then you can make a variable-font this way:
+ .. code-block:: sh
+
$ fonttools varLib master_ufo/NotoSansArabic.designspace
API *will* change in near future.
@@ -869,7 +873,7 @@ def _add_COLR(font, model, master_fonts, axisTags, colr_layer_reuse=True):
colr.VarIndexMap = builder.buildDeltaSetIndexMap(varIdxes)
-def load_designspace(designspace, log_enabled=True):
+def load_designspace(designspace, log_enabled=True, *, require_sources=True):
# TODO: remove this and always assume 'designspace' is a DesignSpaceDocument,
# never a file path, as that's already handled by caller
if hasattr(designspace, "sources"): # Assume a DesignspaceDocument
@@ -878,7 +882,7 @@ def load_designspace(designspace, log_enabled=True):
ds = DesignSpaceDocument.fromfile(designspace)
masters = ds.sources
- if not masters:
+ if require_sources and not masters:
raise VarLibValidationError("Designspace must have at least one source.")
instances = ds.instances
@@ -978,7 +982,7 @@ def load_designspace(designspace, log_enabled=True):
"More than one base master found in Designspace."
)
base_idx = i
- if base_idx is None:
+ if require_sources and base_idx is None:
raise VarLibValidationError(
"Base master not found; no master at default location?"
)
diff --git a/contrib/python/fonttools/fontTools/varLib/avar.py b/contrib/python/fonttools/fontTools/varLib/avar.py
index 60f0d7e701..164a4a8058 100644
--- a/contrib/python/fonttools/fontTools/varLib/avar.py
+++ b/contrib/python/fonttools/fontTools/varLib/avar.py
@@ -1,10 +1,187 @@
from fontTools.varLib import _add_avar, load_designspace
+from fontTools.varLib.models import VariationModel
+from fontTools.varLib.varStore import VarStoreInstancer
+from fontTools.misc.fixedTools import fixedToFloat as fi2fl
from fontTools.misc.cliTools import makeOutputFileName
+from itertools import product
import logging
log = logging.getLogger("fontTools.varLib.avar")
+def _denormalize(v, axis):
+ if v >= 0:
+ return axis.defaultValue + v * (axis.maxValue - axis.defaultValue)
+ else:
+ return axis.defaultValue + v * (axis.defaultValue - axis.minValue)
+
+
+def _pruneLocations(locations, poles, axisTags):
+ # Now we have all the input locations, find which ones are
+ # not needed and remove them.
+
+ # Note: This algorithm is heavily tied to how VariationModel
+ # is implemented. It assumes that input was extracted from
+ # VariationModel-generated object, like an ItemVariationStore
+ # created by fontmake using varLib.models.VariationModel.
+ # Some CoPilot blabbering:
+ # I *think* I can prove that this algorithm is correct, but
+ # I'm not 100% sure. It's possible that there are edge cases
+ # where this algorithm will fail. I'm not sure how to prove
+ # that it's correct, but I'm also not sure how to prove that
+ # it's incorrect. I'm not sure how to write a test case that
+ # would prove that it's incorrect. I'm not sure how to write
+ # a test case that would prove that it's correct.
+
+ model = VariationModel(locations, axisTags)
+ modelMapping = model.mapping
+ modelSupports = model.supports
+ pins = {tuple(k.items()): None for k in poles}
+ for location in poles:
+ i = locations.index(location)
+ i = modelMapping[i]
+ support = modelSupports[i]
+ supportAxes = set(support.keys())
+ for axisTag, (minV, _, maxV) in support.items():
+ for v in (minV, maxV):
+ if v in (-1, 0, 1):
+ continue
+ for pin in pins.keys():
+ pinLocation = dict(pin)
+ pinAxes = set(pinLocation.keys())
+ if pinAxes != supportAxes:
+ continue
+ if axisTag not in pinAxes:
+ continue
+ if pinLocation[axisTag] == v:
+ break
+ else:
+ # No pin found. Go through the previous masters
+ # and find a suitable pin. Going backwards is
+ # better because it can find a pin that is close
+ # to the pole in more dimensions, and reducing
+ # the total number of pins needed.
+ for candidateIdx in range(i - 1, -1, -1):
+ candidate = modelSupports[candidateIdx]
+ candidateAxes = set(candidate.keys())
+ if candidateAxes != supportAxes:
+ continue
+ if axisTag not in candidateAxes:
+ continue
+ candidate = {
+ k: defaultV for k, (_, defaultV, _) in candidate.items()
+ }
+ if candidate[axisTag] == v:
+ pins[tuple(candidate.items())] = None
+ break
+ else:
+ assert False, "No pin found"
+ return [dict(t) for t in pins.keys()]
+
+
+def mappings_from_avar(font, denormalize=True):
+ fvarAxes = font["fvar"].axes
+ axisMap = {a.axisTag: a for a in fvarAxes}
+ axisTags = [a.axisTag for a in fvarAxes]
+ axisIndexes = {a.axisTag: i for i, a in enumerate(fvarAxes)}
+ if "avar" not in font:
+ return {}, {}
+ avar = font["avar"]
+ axisMaps = {
+ tag: seg
+ for tag, seg in avar.segments.items()
+ if seg and seg != {-1: -1, 0: 0, 1: 1}
+ }
+ mappings = []
+
+ if getattr(avar, "majorVersion", 1) == 2:
+ varStore = avar.table.VarStore
+ regions = varStore.VarRegionList.Region
+
+ # Find all the input locations; this finds "poles", that are
+ # locations of the peaks, and "corners", that are locations
+ # of the corners of the regions. These two sets of locations
+ # together constitute inputLocations to consider.
+
+ poles = {(): None} # Just using it as an ordered set
+ inputLocations = set({()})
+ for varData in varStore.VarData:
+ regionIndices = varData.VarRegionIndex
+ for regionIndex in regionIndices:
+ peakLocation = []
+ corners = []
+ region = regions[regionIndex]
+ for axisIndex, axis in enumerate(region.VarRegionAxis):
+ if axis.PeakCoord == 0:
+ continue
+ axisTag = axisTags[axisIndex]
+ peakLocation.append((axisTag, axis.PeakCoord))
+ corner = []
+ if axis.StartCoord != 0:
+ corner.append((axisTag, axis.StartCoord))
+ if axis.EndCoord != 0:
+ corner.append((axisTag, axis.EndCoord))
+ corners.append(corner)
+ corners = set(product(*corners))
+ peakLocation = tuple(peakLocation)
+ poles[peakLocation] = None
+ inputLocations.add(peakLocation)
+ inputLocations.update(corners)
+
+ # Sort them by number of axes, then by axis order
+ inputLocations = [
+ dict(t)
+ for t in sorted(
+ inputLocations,
+ key=lambda t: (len(t), tuple(axisIndexes[tag] for tag, _ in t)),
+ )
+ ]
+ poles = [dict(t) for t in poles.keys()]
+ inputLocations = _pruneLocations(inputLocations, list(poles), axisTags)
+
+ # Find the output locations, at input locations
+ varIdxMap = avar.table.VarIdxMap
+ instancer = VarStoreInstancer(varStore, fvarAxes)
+ for location in inputLocations:
+ instancer.setLocation(location)
+ outputLocation = {}
+ for axisIndex, axisTag in enumerate(axisTags):
+ varIdx = axisIndex
+ if varIdxMap is not None:
+ varIdx = varIdxMap[varIdx]
+ delta = instancer[varIdx]
+ if delta != 0:
+ v = location.get(axisTag, 0)
+ v = v + fi2fl(delta, 14)
+ # See https://github.com/fonttools/fonttools/pull/3598#issuecomment-2266082009
+ # v = max(-1, min(1, v))
+ outputLocation[axisTag] = v
+ mappings.append((location, outputLocation))
+
+ # Remove base master we added, if it maps to the default location
+ assert mappings[0][0] == {}
+ if mappings[0][1] == {}:
+ mappings.pop(0)
+
+ if denormalize:
+ for tag, seg in axisMaps.items():
+ if tag not in axisMap:
+ raise ValueError(f"Unknown axis tag {tag}")
+ denorm = lambda v: _denormalize(v, axisMap[tag])
+ axisMaps[tag] = {denorm(k): denorm(v) for k, v in seg.items()}
+
+ for i, (inputLoc, outputLoc) in enumerate(mappings):
+ inputLoc = {
+ tag: _denormalize(val, axisMap[tag]) for tag, val in inputLoc.items()
+ }
+ outputLoc = {
+ tag: _denormalize(val, axisMap[tag]) for tag, val in outputLoc.items()
+ }
+ mappings[i] = (inputLoc, outputLoc)
+
+ return axisMaps, mappings
+
+
def main(args=None):
"""Add `avar` table from designspace file to variable font."""
@@ -24,7 +201,11 @@ def main(args=None):
)
parser.add_argument("font", metavar="varfont.ttf", help="Variable-font file.")
parser.add_argument(
- "designspace", metavar="family.designspace", help="Designspace file."
+ "designspace",
+ metavar="family.designspace",
+ help="Designspace file.",
+ nargs="?",
+ default=None,
)
parser.add_argument(
"-o",
@@ -45,9 +226,18 @@ def main(args=None):
log.error("Not a variable font.")
return 1
+ if options.designspace is None:
+ from pprint import pprint
+
+ segments, mappings = mappings_from_avar(font)
+ pprint(segments)
+ pprint(mappings)
+ print(len(mappings), "mappings")
+ return
+
axisTags = [a.axisTag for a in font["fvar"].axes]
- ds = load_designspace(options.designspace)
+ ds = load_designspace(options.designspace, require_sources=False)
if "avar" in font:
log.warning("avar table already present, overwriting.")
diff --git a/contrib/python/fonttools/fontTools/varLib/cff.py b/contrib/python/fonttools/fontTools/varLib/cff.py
index 59ac5c6f7a..155429ab51 100644
--- a/contrib/python/fonttools/fontTools/varLib/cff.py
+++ b/contrib/python/fonttools/fontTools/varLib/cff.py
@@ -96,7 +96,7 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
* step through each key in FontDict.Private.
* For each key, step through each relevant source font Private dict, and
- build a list of values to blend.
+ build a list of values to blend.
The 'relevant' source fonts are selected by first getting the right
submodel using ``vsindex_dict[vsindex]``. The indices of the
diff --git a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
index 82676d4190..f6df65e96d 100644
--- a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
+++ b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
@@ -5,7 +5,9 @@ create full instances (i.e. static fonts) from variable fonts, as well as "parti
variable fonts that only contain a subset of the original variation space.
For example, if you wish to pin the width axis to a given location while also
-restricting the weight axis to 400..700 range, you can do::
+restricting the weight axis to 400..700 range, you can do:
+
+.. code-block:: sh
$ fonttools varLib.instancer ./NotoSans-VF.ttf wdth=85 wght=400:700
@@ -17,32 +19,38 @@ and returns a new TTFont representing either a partial VF, or full instance if a
the VF axes were given an explicit coordinate.
E.g. here's how to pin the wght axis at a given location in a wght+wdth variable
-font, keeping only the deltas associated with the wdth axis::
-
-| >>> from fontTools import ttLib
-| >>> from fontTools.varLib import instancer
-| >>> varfont = ttLib.TTFont("path/to/MyVariableFont.ttf")
-| >>> [a.axisTag for a in varfont["fvar"].axes] # the varfont's current axes
-| ['wght', 'wdth']
-| >>> partial = instancer.instantiateVariableFont(varfont, {"wght": 300})
-| >>> [a.axisTag for a in partial["fvar"].axes] # axes left after pinning 'wght'
-| ['wdth']
+font, keeping only the deltas associated with the wdth axis:
+.. code-block:: pycon
+
+ >>>
+ >> from fontTools import ttLib
+ >> from fontTools.varLib import instancer
+ >> varfont = ttLib.TTFont("path/to/MyVariableFont.ttf")
+ >> [a.axisTag for a in varfont["fvar"].axes] # the varfont's current axes
+ ['wght', 'wdth']
+ >> partial = instancer.instantiateVariableFont(varfont, {"wght": 300})
+ >> [a.axisTag for a in partial["fvar"].axes] # axes left after pinning 'wght'
+ ['wdth']
If the input location specifies all the axes, the resulting instance is no longer
'variable' (same as using fontools varLib.mutator):
+.. code-block:: pycon
-| >>> instance = instancer.instantiateVariableFont(
-| ... varfont, {"wght": 700, "wdth": 67.5}
-| ... )
-| >>> "fvar" not in instance
-| True
+ >>>
+ >> instance = instancer.instantiateVariableFont(
+ ... varfont, {"wght": 700, "wdth": 67.5}
+ ... )
+ >> "fvar" not in instance
+ True
If one just want to drop an axis at the default location, without knowing in
advance what the default value for that axis is, one can pass a `None` value:
+.. code-block:: pycon
-| >>> instance = instancer.instantiateVariableFont(varfont, {"wght": None})
-| >>> len(varfont["fvar"].axes)
-| 1
+ >>>
+ >> instance = instancer.instantiateVariableFont(varfont, {"wght": None})
+ >> len(varfont["fvar"].axes)
+ 1
From the console script, this is equivalent to passing `wght=drop` as input.
@@ -56,25 +64,33 @@ course be combined:
L1
dropping one or more axes while leaving the default tables unmodified;
+ .. code-block:: pycon
- | >>> font = instancer.instantiateVariableFont(varfont, {"wght": None})
+ >>>
+ >> font = instancer.instantiateVariableFont(varfont, {"wght": None})
L2
dropping one or more axes while pinning them at non-default locations;
-
- | >>> font = instancer.instantiateVariableFont(varfont, {"wght": 700})
+ .. code-block:: pycon
+
+ >>>
+ >> font = instancer.instantiateVariableFont(varfont, {"wght": 700})
L3
restricting the range of variation of one or more axes, by setting either
a new minimum or maximum, potentially -- though not necessarily -- dropping
entire regions of variations that fall completely outside this new range.
-
- | >>> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300)})
+ .. code-block:: pycon
+
+ >>>
+ >> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300)})
L4
moving the default location of an axis, by specifying (min,defalt,max) values:
-
- | >>> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300, 700)})
+ .. code-block:: pycon
+
+ >>>
+ >> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300, 700)})
Currently only TrueType-flavored variable fonts (i.e. containing 'glyf' table)
are supported, but support for CFF2 variable fonts will be added soon.
@@ -897,7 +913,18 @@ def _instantiateGvarGlyph(
return
if optimize:
+ # IUP semantics depend on point equality, and so round prior to
+ # optimization to ensure that comparisons that happen now will be the
+ # same as those that happen at render time. This is especially needed
+ # when floating point deltas have been applied to the default position.
+ # See https://github.com/fonttools/fonttools/issues/3634
+ # Rounding must happen only after calculating glyf metrics above, to
+ # preserve backwards compatibility.
+ # See 0010a3cd9aa25f84a3a6250dafb119743d32aa40
+ coordinates.toInt()
+
isComposite = glyf[glyphname].isComposite()
+
for var in tupleVarStore:
var.optimize(coordinates, endPts, isComposite=isComposite)
diff --git a/contrib/python/fonttools/fontTools/varLib/interpolatable.py b/contrib/python/fonttools/fontTools/varLib/interpolatable.py
index e212ecf8d1..60dbfeb7fc 100644
--- a/contrib/python/fonttools/fontTools/varLib/interpolatable.py
+++ b/contrib/python/fonttools/fontTools/varLib/interpolatable.py
@@ -135,6 +135,7 @@ def test_gen(
kinkiness=DEFAULT_KINKINESS,
upem=DEFAULT_UPEM,
show_all=False,
+ discrete_axes=[],
):
if tolerance >= 10:
tolerance *= 0.01
@@ -150,7 +151,9 @@ def test_gen(
# ... risks the sparse master being the first one, and only processing a subset of the glyphs
glyphs = {g for glyphset in glyphsets for g in glyphset.keys()}
- parents, order = find_parents_and_order(glyphsets, locations)
+ parents, order = find_parents_and_order(
+ glyphsets, locations, discrete_axes=discrete_axes
+ )
def grand_parent(i, glyphname):
if i is None:
@@ -701,6 +704,7 @@ def main(args=None):
fonts = []
names = []
locations = []
+ discrete_axes = set()
upem = DEFAULT_UPEM
original_args_inputs = tuple(args.inputs)
@@ -713,8 +717,13 @@ def main(args=None):
designspace = DesignSpaceDocument.fromfile(args.inputs[0])
args.inputs = [master.path for master in designspace.sources]
locations = [master.location for master in designspace.sources]
+ discrete_axes = {
+ a.name for a in designspace.axes if not hasattr(a, "minimum")
+ }
axis_triples = {
- a.name: (a.minimum, a.default, a.maximum) for a in designspace.axes
+ a.name: (a.minimum, a.default, a.maximum)
+ for a in designspace.axes
+ if a.name not in discrete_axes
}
axis_mappings = {a.name: a.map for a in designspace.axes}
axis_triples = {
@@ -879,7 +888,13 @@ def main(args=None):
glyphset[gn] = None
# Normalize locations
- locations = [normalizeLocation(loc, axis_triples) for loc in locations]
+ locations = [
+ {
+ **normalizeLocation(loc, axis_triples),
+ **{k: v for k, v in loc.items() if k in discrete_axes},
+ }
+ for loc in locations
+ ]
tolerance = args.tolerance or DEFAULT_TOLERANCE
kinkiness = args.kinkiness if args.kinkiness is not None else DEFAULT_KINKINESS
@@ -896,6 +911,7 @@ def main(args=None):
tolerance=tolerance,
kinkiness=kinkiness,
show_all=args.show_all,
+ discrete_axes=discrete_axes,
)
problems = defaultdict(list)
@@ -924,13 +940,13 @@ def main(args=None):
last_master_idxs = None
master_idxs = (
- (p["master_idx"])
+ (p["master_idx"],)
if "master_idx" in p
else (p["master_1_idx"], p["master_2_idx"])
)
if master_idxs != last_master_idxs:
master_names = (
- (p["master"])
+ (p["master"],)
if "master" in p
else (p["master_1"], p["master_2"])
)
diff --git a/contrib/python/fonttools/fontTools/varLib/interpolatableHelpers.py b/contrib/python/fonttools/fontTools/varLib/interpolatableHelpers.py
index f71b32afd1..5cf22cf879 100644
--- a/contrib/python/fonttools/fontTools/varLib/interpolatableHelpers.py
+++ b/contrib/python/fonttools/fontTools/varLib/interpolatableHelpers.py
@@ -293,17 +293,19 @@ def add_isomorphisms(points, isomorphisms, reverse):
)
-def find_parents_and_order(glyphsets, locations):
+def find_parents_and_order(glyphsets, locations, *, discrete_axes=set()):
parents = [None] + list(range(len(glyphsets) - 1))
order = list(range(len(glyphsets)))
if locations:
# Order base master first
- bases = (i for i, l in enumerate(locations) if all(v == 0 for v in l.values()))
+ bases = [
+ i
+ for i, l in enumerate(locations)
+ if all(v == 0 for k, v in l.items() if k not in discrete_axes)
+ ]
if bases:
- base = next(bases)
- logging.info("Base master index %s, location %s", base, locations[base])
+ logging.info("Found %s base masters: %s", len(bases), bases)
else:
- base = 0
logging.warning("No base master location found")
# Form a minimum spanning tree of the locations
@@ -317,9 +319,17 @@ def find_parents_and_order(glyphsets, locations):
axes = sorted(axes)
vectors = [tuple(l.get(k, 0) for k in axes) for l in locations]
for i, j in itertools.combinations(range(len(locations)), 2):
+ i_discrete_location = {
+ k: v for k, v in zip(axes, vectors[i]) if k in discrete_axes
+ }
+ j_discrete_location = {
+ k: v for k, v in zip(axes, vectors[j]) if k in discrete_axes
+ }
+ if i_discrete_location != j_discrete_location:
+ continue
graph[i][j] = vdiff_hypot2(vectors[i], vectors[j])
- tree = minimum_spanning_tree(graph)
+ tree = minimum_spanning_tree(graph, overwrite=True)
rows, cols = tree.nonzero()
graph = defaultdict(set)
for row, col in zip(rows, cols):
@@ -330,7 +340,7 @@ def find_parents_and_order(glyphsets, locations):
parents = [None] * len(locations)
order = []
visited = set()
- queue = deque([base])
+ queue = deque(bases)
while queue:
i = queue.popleft()
visited.add(i)
@@ -339,6 +349,9 @@ def find_parents_and_order(glyphsets, locations):
if j not in visited:
parents[j] = i
queue.append(j)
+ assert len(order) == len(
+ parents
+ ), "Not all masters are reachable; report an issue"
except ImportError:
pass
diff --git a/contrib/python/fonttools/fontTools/varLib/models.py b/contrib/python/fonttools/fontTools/varLib/models.py
index 819596991f..52433a66a8 100644
--- a/contrib/python/fonttools/fontTools/varLib/models.py
+++ b/contrib/python/fonttools/fontTools/varLib/models.py
@@ -209,10 +209,14 @@ def supportScalar(location, support, ot=True, extrapolate=False, axisRanges=None
class VariationModel(object):
"""Locations must have the base master at the origin (ie. 0).
+ If axis-ranges are not provided, values are assumed to be normalized to
+ the range [-1, 1].
+
If the extrapolate argument is set to True, then values are extrapolated
outside the axis range.
>>> from pprint import pprint
+ >>> axisRanges = {'wght': (-180, +180), 'wdth': (-1, +1)}
>>> locations = [ \
{'wght':100}, \
{'wght':-100}, \
@@ -224,7 +228,7 @@ class VariationModel(object):
{'wght':+180,'wdth':.3}, \
{'wght':+180}, \
]
- >>> model = VariationModel(locations, axisOrder=['wght'])
+ >>> model = VariationModel(locations, axisOrder=['wght'], axisRanges=axisRanges)
>>> pprint(model.locations)
[{},
{'wght': -100},
@@ -252,14 +256,22 @@ class VariationModel(object):
7: 0.6666666666666667}]
"""
- def __init__(self, locations, axisOrder=None, extrapolate=False):
+ def __init__(
+ self, locations, axisOrder=None, extrapolate=False, *, axisRanges=None
+ ):
if len(set(tuple(sorted(l.items())) for l in locations)) != len(locations):
raise VariationModelError("Locations must be unique.")
self.origLocations = locations
self.axisOrder = axisOrder if axisOrder is not None else []
self.extrapolate = extrapolate
- self.axisRanges = self.computeAxisRanges(locations) if extrapolate else None
+ if axisRanges is None:
+ if extrapolate:
+ axisRanges = self.computeAxisRanges(locations)
+ else:
+ allAxes = {axis for loc in locations for axis in loc.keys()}
+ axisRanges = {axis: (-1, 1) for axis in allAxes}
+ self.axisRanges = axisRanges
locations = [{k: v for k, v in loc.items() if v != 0.0} for loc in locations]
keyFunc = self.getMasterLocationsSortKeyFunc(
@@ -374,7 +386,7 @@ class VariationModel(object):
locAxes = set(region.keys())
# Walk over previous masters now
for prev_region in regions[:i]:
- # Master with extra axes do not participte
+ # Master with different axes do not participte
if set(prev_region.keys()) != locAxes:
continue
# If it's NOT in the current box, it does not participate
@@ -425,23 +437,16 @@ class VariationModel(object):
def _locationsToRegions(self):
locations = self.locations
- # Compute min/max across each axis, use it as total range.
- # TODO Take this as input from outside?
- minV = {}
- maxV = {}
- for l in locations:
- for k, v in l.items():
- minV[k] = min(v, minV.get(k, v))
- maxV[k] = max(v, maxV.get(k, v))
+ axisRanges = self.axisRanges
regions = []
for loc in locations:
region = {}
for axis, locV in loc.items():
if locV > 0:
- region[axis] = (0, locV, maxV[axis])
+ region[axis] = (0, locV, axisRanges[axis][1])
else:
- region[axis] = (minV[axis], locV, 0)
+ region[axis] = (axisRanges[axis][0], locV, 0)
regions.append(region)
return regions
diff --git a/contrib/python/fonttools/fontTools/varLib/mutator.py b/contrib/python/fonttools/fontTools/varLib/mutator.py
index 6c327f9454..80e46bb244 100644
--- a/contrib/python/fonttools/fontTools/varLib/mutator.py
+++ b/contrib/python/fonttools/fontTools/varLib/mutator.py
@@ -1,7 +1,9 @@
"""
Instantiate a variation font. Run, eg:
-$ fonttools varLib.mutator ./NotoSansArabic-VF.ttf wght=140 wdth=85
+.. code-block:: sh
+
+ $ fonttools varLib.mutator ./NotoSansArabic-VF.ttf wght=140 wdth=85
"""
from fontTools.misc.fixedTools import floatToFixedToFloat, floatToFixed
@@ -162,7 +164,9 @@ def instantiateVariableFont(varfont, location, inplace=False, overlap=True):
defining the desired location along the variable font's axes.
The location values must be specified as user-space coordinates, e.g.:
- {'wght': 400, 'wdth': 100}
+ .. code-block::
+
+ {'wght': 400, 'wdth': 100}
By default, a new TTFont object is returned. If ``inplace`` is True, the
input varfont is modified and reduced to a static font.
diff --git a/contrib/python/fonttools/fontTools/voltLib/voltToFea.py b/contrib/python/fonttools/fontTools/voltLib/voltToFea.py
index 2265d50295..c77d5ad111 100644
--- a/contrib/python/fonttools/fontTools/voltLib/voltToFea.py
+++ b/contrib/python/fonttools/fontTools/voltLib/voltToFea.py
@@ -7,12 +7,16 @@ Usage
To convert a VTP project file:
+.. code-block:: sh
+
$ fonttools voltLib.voltToFea input.vtp output.fea
It is also possible convert font files with `TSIV` table (as saved from Volt),
in this case the glyph names used in the Volt project will be mapped to the
actual glyph names in the font files when written to the feature file:
+.. code-block:: sh
+
$ fonttools voltLib.voltToFea input.ttf output.fea
The ``--quiet`` option can be used to suppress warnings.
diff --git a/contrib/python/fonttools/ya.make b/contrib/python/fonttools/ya.make
index 82ed3d848e..402baf8a09 100644
--- a/contrib/python/fonttools/ya.make
+++ b/contrib/python/fonttools/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(4.53.1)
+VERSION(4.54.1)
LICENSE(MIT)
diff --git a/contrib/python/prompt-toolkit/py3/.dist-info/METADATA b/contrib/python/prompt-toolkit/py3/.dist-info/METADATA
index c4f9a4a3ff..eae81f9c1d 100644
--- a/contrib/python/prompt-toolkit/py3/.dist-info/METADATA
+++ b/contrib/python/prompt-toolkit/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: prompt_toolkit
-Version: 3.0.47
+Version: 3.0.48
Summary: Library for building powerful interactive command lines in Python
Home-page: https://github.com/prompt-toolkit/python-prompt-toolkit
Author: Jonathan Slenders
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/__init__.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/__init__.py
index 7f6f30251c..80da72d1ec 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/__init__.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/__init__.py
@@ -28,7 +28,7 @@ from .formatted_text import ANSI, HTML
from .shortcuts import PromptSession, print_formatted_text, prompt
# Don't forget to update in `docs/conf.py`!
-__version__ = "3.0.47"
+__version__ = "3.0.48"
assert pep440.match(__version__)
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/fuzzy_completer.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/fuzzy_completer.py
index 25ea8923a3..82625ab63f 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/fuzzy_completer.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/fuzzy_completer.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import re
-from typing import Callable, Iterable, NamedTuple
+from typing import Callable, Iterable, NamedTuple, Sequence
from prompt_toolkit.document import Document
from prompt_toolkit.filters import FilterOrBool, to_filter
@@ -187,7 +187,7 @@ class FuzzyWordCompleter(Completer):
def __init__(
self,
- words: list[str] | Callable[[], list[str]],
+ words: Sequence[str] | Callable[[], Sequence[str]],
meta_dict: dict[str, str] | None = None,
WORD: bool = False,
) -> None:
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/word_completer.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/word_completer.py
index 6ef4031fab..2e124056ba 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/word_completer.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/completion/word_completer.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import Callable, Iterable, Mapping, Pattern
+from typing import Callable, Iterable, Mapping, Pattern, Sequence
from prompt_toolkit.completion import CompleteEvent, Completer, Completion
from prompt_toolkit.document import Document
@@ -33,7 +33,7 @@ class WordCompleter(Completer):
def __init__(
self,
- words: list[str] | Callable[[], list[str]],
+ words: Sequence[str] | Callable[[], Sequence[str]],
ignore_case: bool = False,
display_dict: Mapping[str, AnyFormattedText] | None = None,
meta_dict: Mapping[str, AnyFormattedText] | None = None,
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/contrib/regular_languages/compiler.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/contrib/regular_languages/compiler.py
index dd558a68a2..4009d54f2d 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/contrib/regular_languages/compiler.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/contrib/regular_languages/compiler.py
@@ -42,7 +42,7 @@ Partial matches are possible::
from __future__ import annotations
import re
-from typing import Callable, Dict, Iterable, Iterator, Pattern
+from typing import Callable, Dict, Iterable, Iterator, Pattern, TypeVar, overload
from typing import Match as RegexMatch
from .regex_parser import (
@@ -57,9 +57,7 @@ from .regex_parser import (
tokenize_regex,
)
-__all__ = [
- "compile",
-]
+__all__ = ["compile", "Match", "Variables"]
# Name of the named group in the regex, matching trailing input.
@@ -491,6 +489,9 @@ class Match:
yield MatchVariable(varname, value, (reg[0], reg[1]))
+_T = TypeVar("_T")
+
+
class Variables:
def __init__(self, tuples: list[tuple[str, str, tuple[int, int]]]) -> None:
#: List of (varname, value, slice) tuples.
@@ -502,7 +503,13 @@ class Variables:
", ".join(f"{k}={v!r}" for k, v, _ in self._tuples),
)
- def get(self, key: str, default: str | None = None) -> str | None:
+ @overload
+ def get(self, key: str) -> str | None: ...
+
+ @overload
+ def get(self, key: str, default: str | _T) -> str | _T: ...
+
+ def get(self, key: str, default: str | _T | None = None) -> str | _T | None:
items = self.getall(key)
return items[0] if items else default
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/cursor_shapes.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/cursor_shapes.py
index 453b72c3cb..01d10926a2 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/cursor_shapes.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/cursor_shapes.py
@@ -69,10 +69,23 @@ class ModalCursorShapeConfig(CursorShapeConfig):
def get_cursor_shape(self, application: Application[Any]) -> CursorShape:
if application.editing_mode == EditingMode.VI:
- if application.vi_state.input_mode == InputMode.INSERT:
+ if application.vi_state.input_mode in {
+ InputMode.NAVIGATION,
+ }:
+ return CursorShape.BLOCK
+ if application.vi_state.input_mode in {
+ InputMode.INSERT,
+ InputMode.INSERT_MULTIPLE,
+ }:
return CursorShape.BEAM
- if application.vi_state.input_mode == InputMode.REPLACE:
+ if application.vi_state.input_mode in {
+ InputMode.REPLACE,
+ InputMode.REPLACE_SINGLE,
+ }:
return CursorShape.UNDERLINE
+ elif application.editing_mode == EditingMode.EMACS:
+ # like vi's INSERT
+ return CursorShape.BEAM
# Default
return CursorShape.BLOCK
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py
index ed114e32af..6b06ed43c8 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/defaults.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import sys
-from typing import TextIO, cast
+from typing import TYPE_CHECKING, TextIO, cast
from prompt_toolkit.utils import (
get_bell_environment_variable,
@@ -13,13 +13,17 @@ from .base import DummyOutput, Output
from .color_depth import ColorDepth
from .plain_text import PlainTextOutput
+if TYPE_CHECKING:
+ from prompt_toolkit.patch_stdout import StdoutProxy
+
+
__all__ = [
"create_output",
]
def create_output(
- stdout: TextIO | None = None, always_prefer_tty: bool = False
+ stdout: TextIO | StdoutProxy | None = None, always_prefer_tty: bool = False
) -> Output:
"""
Return an :class:`~prompt_toolkit.output.Output` instance for the command
@@ -54,13 +58,6 @@ def create_output(
stdout = io
break
- # If the output is still `None`, use a DummyOutput.
- # This happens for instance on Windows, when running the application under
- # `pythonw.exe`. In that case, there won't be a terminal Window, and
- # stdin/stdout/stderr are `None`.
- if stdout is None:
- return DummyOutput()
-
# If the patch_stdout context manager has been used, then sys.stdout is
# replaced by this proxy. For prompt_toolkit applications, we want to use
# the real stdout.
@@ -69,6 +66,13 @@ def create_output(
while isinstance(stdout, StdoutProxy):
stdout = stdout.original_stdout
+ # If the output is still `None`, use a DummyOutput.
+ # This happens for instance on Windows, when running the application under
+ # `pythonw.exe`. In that case, there won't be a terminal Window, and
+ # stdin/stdout/stderr are `None`.
+ if stdout is None:
+ return DummyOutput()
+
if sys.platform == "win32":
from .conemu import ConEmuOutput
from .win32 import Win32Output
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/patch_stdout.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/patch_stdout.py
index 4958e9d2e4..e1f2a7a2c3 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/patch_stdout.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/patch_stdout.py
@@ -273,7 +273,7 @@ class StdoutProxy:
self._flush()
@property
- def original_stdout(self) -> TextIO:
+ def original_stdout(self) -> TextIO | None:
return self._output.stdout or sys.__stdout__
# Attributes for compatibility with sys.__stdout__:
diff --git a/contrib/python/prompt-toolkit/py3/ya.make b/contrib/python/prompt-toolkit/py3/ya.make
index cdfd5cd4ca..b1cb3e19b0 100644
--- a/contrib/python/prompt-toolkit/py3/ya.make
+++ b/contrib/python/prompt-toolkit/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(3.0.47)
+VERSION(3.0.48)
LICENSE(BSD-3-Clause)
diff --git a/contrib/python/tzdata/.dist-info/METADATA b/contrib/python/tzdata/.dist-info/METADATA
index 5ca4be3198..4feec22ac4 100644
--- a/contrib/python/tzdata/.dist-info/METADATA
+++ b/contrib/python/tzdata/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: tzdata
-Version: 2024.1
+Version: 2024.2
Summary: Provider of IANA time zone data
Home-page: https://github.com/python/tzdata
Author: Python Software Foundation
diff --git a/contrib/python/tzdata/tzdata/__init__.py b/contrib/python/tzdata/tzdata/__init__.py
index b319ed5558..e558a8a536 100644
--- a/contrib/python/tzdata/tzdata/__init__.py
+++ b/contrib/python/tzdata/tzdata/__init__.py
@@ -1,6 +1,6 @@
# IANA versions like 2020a are not valid PEP 440 identifiers; the recommended
# way to translate the version is to use YYYY.n where `n` is a 0-based index.
-__version__ = "2024.1"
+__version__ = "2024.2"
# This exposes the original IANA version number.
-IANA_VERSION = "2024a"
+IANA_VERSION = "2024b"
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Blantyre b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Blantyre
index 651e5cf67a..581bb0e08b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Blantyre
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Blantyre
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Bujumbura b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Bujumbura
index 651e5cf67a..581bb0e08b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Bujumbura
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Bujumbura
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Gaborone b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Gaborone
index 651e5cf67a..581bb0e08b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Gaborone
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Gaborone
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Harare b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Harare
index 651e5cf67a..581bb0e08b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Harare
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Harare
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Kigali b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Kigali
index 651e5cf67a..581bb0e08b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Kigali
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Kigali
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Lubumbashi b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Lubumbashi
index 651e5cf67a..581bb0e08b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Lubumbashi
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Lubumbashi
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Lusaka b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Lusaka
index 651e5cf67a..581bb0e08b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Lusaka
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Lusaka
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Maputo b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Maputo
index 651e5cf67a..581bb0e08b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Africa/Maputo
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Africa/Maputo
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Bahia_Banderas b/contrib/python/tzdata/tzdata/zoneinfo/America/Bahia_Banderas
index 48faea2ece..882400bd33 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Bahia_Banderas
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Bahia_Banderas
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Cancun b/contrib/python/tzdata/tzdata/zoneinfo/America/Cancun
index 640b259fd0..3110cdfd6e 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Cancun
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Cancun
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Chihuahua b/contrib/python/tzdata/tzdata/zoneinfo/America/Chihuahua
index 5e0a54f004..f65bb1c931 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Chihuahua
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Chihuahua
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Ciudad_Juarez b/contrib/python/tzdata/tzdata/zoneinfo/America/Ciudad_Juarez
index f636ee643f..5f865ea808 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Ciudad_Juarez
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Ciudad_Juarez
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Ensenada b/contrib/python/tzdata/tzdata/zoneinfo/America/Ensenada
index 42087af4cc..18d0d14afc 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Ensenada
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Ensenada
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Hermosillo b/contrib/python/tzdata/tzdata/zoneinfo/America/Hermosillo
index 5c92e2967e..ba7b14760d 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Hermosillo
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Hermosillo
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Mazatlan b/contrib/python/tzdata/tzdata/zoneinfo/America/Mazatlan
index 97d4d36c13..5aa6039ea4 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Mazatlan
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Mazatlan
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Merida b/contrib/python/tzdata/tzdata/zoneinfo/America/Merida
index e5de1131dc..e5c7d8cc2d 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Merida
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Merida
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Mexico_City b/contrib/python/tzdata/tzdata/zoneinfo/America/Mexico_City
index 80a415c70c..1811234612 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Mexico_City
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Mexico_City
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Monterrey b/contrib/python/tzdata/tzdata/zoneinfo/America/Monterrey
index a5822e2c62..c1e0546451 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Monterrey
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Monterrey
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Ojinaga b/contrib/python/tzdata/tzdata/zoneinfo/America/Ojinaga
index f7e40c0818..1dd08b1caf 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Ojinaga
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Ojinaga
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Santa_Isabel b/contrib/python/tzdata/tzdata/zoneinfo/America/Santa_Isabel
index 42087af4cc..18d0d14afc 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Santa_Isabel
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Santa_Isabel
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/America/Tijuana b/contrib/python/tzdata/tzdata/zoneinfo/America/Tijuana
index 42087af4cc..18d0d14afc 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/America/Tijuana
+++ b/contrib/python/tzdata/tzdata/zoneinfo/America/Tijuana
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Asia/Choibalsan b/contrib/python/tzdata/tzdata/zoneinfo/Asia/Choibalsan
index 0a948c2eac..6f5d3a15ab 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Asia/Choibalsan
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Asia/Choibalsan
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Asia/Dili b/contrib/python/tzdata/tzdata/zoneinfo/Asia/Dili
index bb7be9f3a4..22e705ca1a 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Asia/Dili
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Asia/Dili
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Azores b/contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Azores
index e6e2616e98..cda1c1d225 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Azores
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Azores
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Madeira b/contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Madeira
index cf965c3f92..21e84571ee 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Madeira
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Atlantic/Madeira
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/CET b/contrib/python/tzdata/tzdata/zoneinfo/CET
index 546748d6ea..31973271d2 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/CET
+++ b/contrib/python/tzdata/tzdata/zoneinfo/CET
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/CST6CDT b/contrib/python/tzdata/tzdata/zoneinfo/CST6CDT
index d931558058..b016880653 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/CST6CDT
+++ b/contrib/python/tzdata/tzdata/zoneinfo/CST6CDT
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/EET b/contrib/python/tzdata/tzdata/zoneinfo/EET
index 378919ea11..231bf9c3b7 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/EET
+++ b/contrib/python/tzdata/tzdata/zoneinfo/EET
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/EST b/contrib/python/tzdata/tzdata/zoneinfo/EST
index 3ae9691145..9154643f4c 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/EST
+++ b/contrib/python/tzdata/tzdata/zoneinfo/EST
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/EST5EDT b/contrib/python/tzdata/tzdata/zoneinfo/EST5EDT
index 50c95e0cb0..2b6c2eea14 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/EST5EDT
+++ b/contrib/python/tzdata/tzdata/zoneinfo/EST5EDT
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Europe/Lisbon b/contrib/python/tzdata/tzdata/zoneinfo/Europe/Lisbon
index f0c70b6906..7e9aae727b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Europe/Lisbon
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Europe/Lisbon
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/HST b/contrib/python/tzdata/tzdata/zoneinfo/HST
index 160a53e045..40e3d492e6 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/HST
+++ b/contrib/python/tzdata/tzdata/zoneinfo/HST
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/MET b/contrib/python/tzdata/tzdata/zoneinfo/MET
index 6f0558c3b6..31973271d2 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/MET
+++ b/contrib/python/tzdata/tzdata/zoneinfo/MET
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/MST b/contrib/python/tzdata/tzdata/zoneinfo/MST
index a0953d1e79..c2bd2f949b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/MST
+++ b/contrib/python/tzdata/tzdata/zoneinfo/MST
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/MST7MDT b/contrib/python/tzdata/tzdata/zoneinfo/MST7MDT
index 137867c8bf..09e54e5c7c 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/MST7MDT
+++ b/contrib/python/tzdata/tzdata/zoneinfo/MST7MDT
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaNorte b/contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaNorte
index 42087af4cc..18d0d14afc 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaNorte
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaNorte
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaSur b/contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaSur
index 97d4d36c13..5aa6039ea4 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaSur
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Mexico/BajaSur
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Mexico/General b/contrib/python/tzdata/tzdata/zoneinfo/Mexico/General
index 80a415c70c..1811234612 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Mexico/General
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Mexico/General
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/PST8PDT b/contrib/python/tzdata/tzdata/zoneinfo/PST8PDT
index fde4833f6b..aaf07787ad 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/PST8PDT
+++ b/contrib/python/tzdata/tzdata/zoneinfo/PST8PDT
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/Portugal b/contrib/python/tzdata/tzdata/zoneinfo/Portugal
index f0c70b6906..7e9aae727b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/Portugal
+++ b/contrib/python/tzdata/tzdata/zoneinfo/Portugal
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/WET b/contrib/python/tzdata/tzdata/zoneinfo/WET
index 423c6c203a..7e9aae727b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/WET
+++ b/contrib/python/tzdata/tzdata/zoneinfo/WET
Binary files differ
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/leapseconds b/contrib/python/tzdata/tzdata/zoneinfo/leapseconds
index ce150bfe0d..6c715cb20b 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/leapseconds
+++ b/contrib/python/tzdata/tzdata/zoneinfo/leapseconds
@@ -69,11 +69,11 @@ Leap 2016 Dec 31 23:59:60 + S
# Any additional leap seconds will come after this.
# This Expires line is commented out for now,
# so that pre-2020a zic implementations do not reject this file.
-#Expires 2024 Dec 28 00:00:00
+#Expires 2025 Jun 28 00:00:00
# POSIX timestamps for the data in this file:
-#updated 1704708379 (2024-01-08 10:06:19 UTC)
-#expires 1735344000 (2024-12-28 00:00:00 UTC)
+#updated 1720104763 (2024-07-04 14:52:43 UTC)
+#expires 1751068800 (2025-06-28 00:00:00 UTC)
# Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat)
-# File expires on 28 December 2024
+# File expires on 28 June 2025
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/tzdata.zi b/contrib/python/tzdata/tzdata/zoneinfo/tzdata.zi
index be1c408592..62e78bb826 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/tzdata.zi
+++ b/contrib/python/tzdata/tzdata/zoneinfo/tzdata.zi
@@ -1,4 +1,4 @@
-# version 2024a
+# version 2024b
# This zic input file is in the public domain.
R d 1916 o - Jun 14 23s 1 S
R d 1916 1919 - O Su>=1 23s 0 -
@@ -1324,14 +1324,10 @@ R O 1961 1964 - May lastSu 1s 1 S
R O 1962 1964 - S lastSu 1s 0 -
R p 1916 o - Jun 17 23 1 S
R p 1916 o - N 1 1 0 -
-R p 1917 o - F 28 23s 1 S
-R p 1917 1921 - O 14 23s 0 -
-R p 1918 o - Mar 1 23s 1 S
-R p 1919 o - F 28 23s 1 S
-R p 1920 o - F 29 23s 1 S
-R p 1921 o - F 28 23s 1 S
+R p 1917 1921 - Mar 1 0 1 S
+R p 1917 1921 - O 14 24 0 -
R p 1924 o - Ap 16 23s 1 S
-R p 1924 o - O 14 23s 0 -
+R p 1924 o - O 4 23s 0 -
R p 1926 o - Ap 17 23s 1 S
R p 1926 1929 - O Sa>=1 23s 0 -
R p 1927 o - Ap 9 23s 1 S
@@ -1349,8 +1345,9 @@ R p 1938 o - Mar 26 23s 1 S
R p 1939 o - Ap 15 23s 1 S
R p 1939 o - N 18 23s 0 -
R p 1940 o - F 24 23s 1 S
-R p 1940 1941 - O 5 23s 0 -
+R p 1940 o - O 7 23s 0 -
R p 1941 o - Ap 5 23s 1 S
+R p 1941 o - O 5 23s 0 -
R p 1942 1945 - Mar Sa>=8 23s 1 S
R p 1942 o - Ap 25 22s 2 M
R p 1942 o - Au 15 22s 1 S
@@ -1360,16 +1357,16 @@ R p 1943 1945 - Au Sa>=25 22s 1 S
R p 1944 1945 - Ap Sa>=21 22s 2 M
R p 1946 o - Ap Sa>=1 23s 1 S
R p 1946 o - O Sa>=1 23s 0 -
-R p 1947 1965 - Ap Su>=1 2s 1 S
+R p 1947 1966 - Ap Su>=1 2s 1 S
R p 1947 1965 - O Su>=1 2s 0 -
-R p 1977 o - Mar 27 0s 1 S
-R p 1977 o - S 25 0s 0 -
-R p 1978 1979 - Ap Su>=1 0s 1 S
-R p 1978 o - O 1 0s 0 -
-R p 1979 1982 - S lastSu 1s 0 -
-R p 1980 o - Mar lastSu 0s 1 S
-R p 1981 1982 - Mar lastSu 1s 1 S
-R p 1983 o - Mar lastSu 2s 1 S
+R p 1976 o - S lastSu 1 0 -
+R p 1977 o - Mar lastSu 0s 1 S
+R p 1977 o - S lastSu 0s 0 -
+R p 1978 1980 - Ap Su>=1 1s 1 S
+R p 1978 o - O 1 1s 0 -
+R p 1979 1980 - S lastSu 1s 0 -
+R p 1981 1986 - Mar lastSu 0s 1 S
+R p 1981 1985 - S lastSu 0s 0 -
R z 1932 o - May 21 0s 1 S
R z 1932 1939 - O Su>=1 0s 0 -
R z 1933 1939 - Ap Su>=2 0s 1 S
@@ -1728,7 +1725,7 @@ R Y 1972 2006 - O lastSu 2 0 S
R Y 1987 2006 - Ap Su>=1 2 1 D
R Yu 1965 o - Ap lastSu 0 2 DD
R Yu 1965 o - O lastSu 2 0 S
-R m 1931 o - May 1 23 1 D
+R m 1931 o - April 30 0 1 D
R m 1931 o - O 1 0 0 S
R m 1939 o - F 5 0 1 D
R m 1939 o - Jun 25 0 0 S
@@ -2096,15 +2093,15 @@ Z Africa/Algiers 0:12:12 - LMT 1891 Mar 16
0 d WE%sT 1981 May
1 - CET
Z Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u
--1 - -01 1975
+-1 - %z 1975
0 - GMT
Z Africa/Cairo 2:5:9 - LMT 1900 O
2 K EE%sT
Z Africa/Casablanca -0:30:20 - LMT 1913 O 26
-0 M +00/+01 1984 Mar 16
-1 - +01 1986
-0 M +00/+01 2018 O 28 3
-1 M +01/+00
+0 M %z 1984 Mar 16
+1 - %z 1986
+0 M %z 2018 O 28 3
+1 M %z
Z Africa/Ceuta -0:21:16 - LMT 1901 Ja 1 0u
0 - WET 1918 May 6 23
0 1 WEST 1918 O 7 23
@@ -2115,9 +2112,9 @@ Z Africa/Ceuta -0:21:16 - LMT 1901 Ja 1 0u
1 - CET 1986
1 E CE%sT
Z Africa/El_Aaiun -0:52:48 - LMT 1934
--1 - -01 1976 Ap 14
-0 M +00/+01 2018 O 28 3
-1 M +01/+00
+-1 - %z 1976 Ap 14
+0 M %z 2018 O 28 3
+1 M %z
Z Africa/Johannesburg 1:52 - LMT 1892 F 8
1:30 - SAST 1903 Mar
2 SA SAST
@@ -2132,19 +2129,19 @@ Z Africa/Khartoum 2:10:8 - LMT 1931
Z Africa/Lagos 0:13:35 - LMT 1905 Jul
0 - GMT 1908 Jul
0:13:35 - LMT 1914
-0:30 - +0030 1919 S
+0:30 - %z 1919 S
1 - WAT
-Z Africa/Maputo 2:10:20 - LMT 1903 Mar
+Z Africa/Maputo 2:10:18 - LMT 1909
2 - CAT
Z Africa/Monrovia -0:43:8 - LMT 1882
-0:43:8 - MMT 1919 Mar
-0:44:30 - MMT 1972 Ja 7
0 - GMT
Z Africa/Nairobi 2:27:16 - LMT 1908 May
-2:30 - +0230 1928 Jun 30 24
+2:30 - %z 1928 Jun 30 24
3 - EAT 1930 Ja 4 24
-2:30 - +0230 1936 D 31 24
-2:45 - +0245 1942 Jul 31 24
+2:30 - %z 1936 D 31 24
+2:45 - %z 1942 Jul 31 24
3 - EAT
Z Africa/Ndjamena 1:0:12 - LMT 1912
1 - WAT 1979 O 14
@@ -2168,7 +2165,7 @@ Z Africa/Tunis 0:40:44 - LMT 1881 May 12
0:9:21 - PMT 1911 Mar 11
1 n CE%sT
Z Africa/Windhoek 1:8:24 - LMT 1892 F 8
-1:30 - +0130 1903 Mar
+1:30 - %z 1903 Mar
2 - SAST 1942 S 20 2
2 1 SAST 1943 Mar 21 2
2 - SAST 1990 Mar 21
@@ -2191,167 +2188,166 @@ Z America/Anchorage 14:0:24 - LMT 1867 O 19 14:31:37
-9 u Y%sT 1983 N 30
-9 u AK%sT
Z America/Araguaina -3:12:48 - LMT 1914
--3 B -03/-02 1990 S 17
--3 - -03 1995 S 14
--3 B -03/-02 2003 S 24
--3 - -03 2012 O 21
--3 B -03/-02 2013 S
--3 - -03
+-3 B %z 1990 S 17
+-3 - %z 1995 S 14
+-3 B %z 2003 S 24
+-3 - %z 2012 O 21
+-3 B %z 2013 S
+-3 - %z
Z America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 A -03/-02
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 A %z
Z America/Argentina/Catamarca -4:23:8 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1991 Mar 3
--4 - -04 1991 O 20
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 - -03 2004 Jun
--4 - -04 2004 Jun 20
--3 A -03/-02 2008 O 18
--3 - -03
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1991 Mar 3
+-4 - %z 1991 O 20
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 - %z 2004 Jun
+-4 - %z 2004 Jun 20
+-3 A %z 2008 O 18
+-3 - %z
Z America/Argentina/Cordoba -4:16:48 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1991 Mar 3
--4 - -04 1991 O 20
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 A -03/-02
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1991 Mar 3
+-4 - %z 1991 O 20
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 A %z
Z America/Argentina/Jujuy -4:21:12 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1990 Mar 4
--4 - -04 1990 O 28
--4 1 -03 1991 Mar 17
--4 - -04 1991 O 6
--3 1 -02 1992
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 A -03/-02 2008 O 18
--3 - -03
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1990 Mar 4
+-4 - %z 1990 O 28
+-4 1 %z 1991 Mar 17
+-4 - %z 1991 O 6
+-3 1 %z 1992
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 A %z 2008 O 18
+-3 - %z
Z America/Argentina/La_Rioja -4:27:24 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1991 Mar
--4 - -04 1991 May 7
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 - -03 2004 Jun
--4 - -04 2004 Jun 20
--3 A -03/-02 2008 O 18
--3 - -03
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1991 Mar
+-4 - %z 1991 May 7
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 - %z 2004 Jun
+-4 - %z 2004 Jun 20
+-3 A %z 2008 O 18
+-3 - %z
Z America/Argentina/Mendoza -4:35:16 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1990 Mar 4
--4 - -04 1990 O 15
--4 1 -03 1991 Mar
--4 - -04 1991 O 15
--4 1 -03 1992 Mar
--4 - -04 1992 O 18
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 - -03 2004 May 23
--4 - -04 2004 S 26
--3 A -03/-02 2008 O 18
--3 - -03
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1990 Mar 4
+-4 - %z 1990 O 15
+-4 1 %z 1991 Mar
+-4 - %z 1991 O 15
+-4 1 %z 1992 Mar
+-4 - %z 1992 O 18
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 - %z 2004 May 23
+-4 - %z 2004 S 26
+-3 A %z 2008 O 18
+-3 - %z
Z America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 - -03 2004 Jun
--4 - -04 2004 Jun 20
--3 A -03/-02 2008 O 18
--3 - -03
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 - %z 2004 Jun
+-4 - %z 2004 Jun 20
+-3 A %z 2008 O 18
+-3 - %z
Z America/Argentina/Salta -4:21:40 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1991 Mar 3
--4 - -04 1991 O 20
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 A -03/-02 2008 O 18
--3 - -03
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1991 Mar 3
+-4 - %z 1991 O 20
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 A %z 2008 O 18
+-3 - %z
Z America/Argentina/San_Juan -4:34:4 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1991 Mar
--4 - -04 1991 May 7
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 - -03 2004 May 31
--4 - -04 2004 Jul 25
--3 A -03/-02 2008 O 18
--3 - -03
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1991 Mar
+-4 - %z 1991 May 7
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 - %z 2004 May 31
+-4 - %z 2004 Jul 25
+-3 A %z 2008 O 18
+-3 - %z
Z America/Argentina/San_Luis -4:25:24 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1990
--3 1 -02 1990 Mar 14
--4 - -04 1990 O 15
--4 1 -03 1991 Mar
--4 - -04 1991 Jun
--3 - -03 1999 O 3
--4 1 -03 2000 Mar 3
--3 - -03 2004 May 31
--4 - -04 2004 Jul 25
--3 A -03/-02 2008 Ja 21
--4 Sa -04/-03 2009 O 11
--3 - -03
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1990
+-3 1 %z 1990 Mar 14
+-4 - %z 1990 O 15
+-4 1 %z 1991 Mar
+-4 - %z 1991 Jun
+-3 - %z 1999 O 3
+-4 1 %z 2000 Mar 3
+-3 - %z 2004 May 31
+-4 - %z 2004 Jul 25
+-3 A %z 2008 Ja 21
+-4 Sa %z 2009 O 11
+-3 - %z
Z America/Argentina/Tucuman -4:20:52 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1991 Mar 3
--4 - -04 1991 O 20
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 - -03 2004 Jun
--4 - -04 2004 Jun 13
--3 A -03/-02
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1991 Mar 3
+-4 - %z 1991 O 20
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 - %z 2004 Jun
+-4 - %z 2004 Jun 13
+-3 A %z
Z America/Argentina/Ushuaia -4:33:12 - LMT 1894 O 31
-4:16:48 - CMT 1920 May
--4 - -04 1930 D
--4 A -04/-03 1969 O 5
--3 A -03/-02 1999 O 3
--4 A -04/-03 2000 Mar 3
--3 - -03 2004 May 30
--4 - -04 2004 Jun 20
--3 A -03/-02 2008 O 18
--3 - -03
+-4 - %z 1930 D
+-4 A %z 1969 O 5
+-3 A %z 1999 O 3
+-4 A %z 2000 Mar 3
+-3 - %z 2004 May 30
+-4 - %z 2004 Jun 20
+-3 A %z 2008 O 18
+-3 - %z
Z America/Asuncion -3:50:40 - LMT 1890
-3:50:40 - AMT 1931 O 10
--4 - -04 1972 O
--3 - -03 1974 Ap
--4 y -04/-03
+-4 - %z 1972 O
+-3 - %z 1974 Ap
+-4 y %z
Z America/Bahia -2:34:4 - LMT 1914
--3 B -03/-02 2003 S 24
--3 - -03 2011 O 16
--3 B -03/-02 2012 O 21
--3 - -03
+-3 B %z 2003 S 24
+-3 - %z 2011 O 16
+-3 B %z 2012 O 21
+-3 - %z
Z America/Bahia_Banderas -7:1 - LMT 1922 Ja 1 7u
--7 - MST 1927 Jun 10 23
+-7 - MST 1927 Jun 10
-6 - CST 1930 N 15
-7 m M%sT 1932 Ap
-6 - CST 1942 Ap 24
--7 - MST 1949 Ja 14
--8 - PST 1970
+-7 - MST 1970
-7 m M%sT 2010 Ap 4 2
-6 m C%sT
Z America/Barbados -3:58:29 - LMT 1911 Au 28
@@ -2359,18 +2355,18 @@ Z America/Barbados -3:58:29 - LMT 1911 Au 28
-4 BB AST/-0330 1945
-4 BB A%sT
Z America/Belem -3:13:56 - LMT 1914
--3 B -03/-02 1988 S 12
--3 - -03
+-3 B %z 1988 S 12
+-3 - %z
Z America/Belize -5:52:48 - LMT 1912 Ap
-6 BZ %s
Z America/Boa_Vista -4:2:40 - LMT 1914
--4 B -04/-03 1988 S 12
--4 - -04 1999 S 30
--4 B -04/-03 2000 O 15
--4 - -04
+-4 B %z 1988 S 12
+-4 - %z 1999 S 30
+-4 B %z 2000 O 15
+-4 - %z
Z America/Bogota -4:56:16 - LMT 1884 Mar 13
-4:56:16 - BMT 1914 N 23
--5 CO -05/-04
+-5 CO %z
Z America/Boise -7:44:49 - LMT 1883 N 18 20u
-8 u P%sT 1923 May 13 2
-7 u M%sT 1974
@@ -2383,21 +2379,23 @@ Z America/Cambridge_Bay 0 - -00 1920
-6 - CST 2001 Ap 1 3
-7 C M%sT
Z America/Campo_Grande -3:38:28 - LMT 1914
--4 B -04/-03
+-4 B %z
Z America/Cancun -5:47:4 - LMT 1922 Ja 1 6u
--6 - CST 1981 D 23
+-6 - CST 1981 D 26 2
+-5 - EST 1983 Ja 4
+-6 m C%sT 1997 O 26 2
-5 m E%sT 1998 Au 2 2
-6 m C%sT 2015 F 1 2
-5 - EST
Z America/Caracas -4:27:44 - LMT 1890
-4:27:40 - CMT 1912 F 12
--4:30 - -0430 1965
--4 - -04 2007 D 9 3
--4:30 - -0430 2016 May 1 2:30
--4 - -04
+-4:30 - %z 1965
+-4 - %z 2007 D 9 3
+-4:30 - %z 2016 May 1 2:30
+-4 - %z
Z America/Cayenne -3:29:20 - LMT 1911 Jul
--4 - -04 1967 O
--3 - -03
+-4 - %z 1967 O
+-3 - %z
Z America/Chicago -5:50:36 - LMT 1883 N 18 18u
-6 u C%sT 1920
-6 Ch C%sT 1936 Mar 1 2
@@ -2407,7 +2405,7 @@ Z America/Chicago -5:50:36 - LMT 1883 N 18 18u
-6 Ch C%sT 1967
-6 u C%sT
Z America/Chihuahua -7:4:20 - LMT 1922 Ja 1 7u
--7 - MST 1927 Jun 10 23
+-7 - MST 1927 Jun 10
-6 - CST 1930 N 15
-7 m M%sT 1932 Ap
-6 - CST 1996
@@ -2416,7 +2414,7 @@ Z America/Chihuahua -7:4:20 - LMT 1922 Ja 1 7u
-7 m M%sT 2022 O 30 2
-6 - CST
Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u
--7 - MST 1927 Jun 10 23
+-7 - MST 1927 Jun 10
-6 - CST 1930 N 15
-7 m M%sT 1932 Ap
-6 - CST 1996
@@ -2430,12 +2428,12 @@ Z America/Costa_Rica -5:36:13 - LMT 1890
-5:36:13 - SJMT 1921 Ja 15
-6 CR C%sT
Z America/Cuiaba -3:44:20 - LMT 1914
--4 B -04/-03 2003 S 24
--4 - -04 2004 O
--4 B -04/-03
+-4 B %z 2003 S 24
+-4 - %z 2004 O
+-4 B %z
Z America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28
--3 - -03 1980 Ap 6 2
--3 E -03/-02 1996
+-3 - %z 1980 Ap 6 2
+-3 E %z 1996
0 - GMT
Z America/Dawson -9:17:40 - LMT 1900 Au 20
-9 Y Y%sT 1965
@@ -2467,12 +2465,12 @@ Z America/Edmonton -7:33:52 - LMT 1906 S
-7 Ed M%sT 1987
-7 C M%sT
Z America/Eirunepe -4:39:28 - LMT 1914
--5 B -05/-04 1988 S 12
--5 - -05 1993 S 28
--5 B -05/-04 1994 S 22
--5 - -05 2008 Jun 24
--4 - -04 2013 N 10
--5 - -05
+-5 B %z 1988 S 12
+-5 - %z 1993 S 28
+-5 B %z 1994 S 22
+-5 - %z 2008 Jun 24
+-4 - %z 2013 N 10
+-5 - %z
Z America/El_Salvador -5:56:48 - LMT 1921
-6 SV C%sT
Z America/Fort_Nelson -8:10:47 - LMT 1884
@@ -2482,12 +2480,12 @@ Z America/Fort_Nelson -8:10:47 - LMT 1884
-8 C P%sT 2015 Mar 8 2
-7 - MST
Z America/Fortaleza -2:34 - LMT 1914
--3 B -03/-02 1990 S 17
--3 - -03 1999 S 30
--3 B -03/-02 2000 O 22
--3 - -03 2001 S 13
--3 B -03/-02 2002 O
--3 - -03
+-3 B %z 1990 S 17
+-3 - %z 1999 S 30
+-3 B %z 2000 O 22
+-3 - %z 2001 S 13
+-3 B %z 2002 O
+-3 - %z
Z America/Glace_Bay -3:59:48 - LMT 1902 Jun 15
-4 C A%sT 1953
-4 H A%sT 1954
@@ -2514,12 +2512,12 @@ Z America/Guatemala -6:2:4 - LMT 1918 O 5
-6 GT C%sT
Z America/Guayaquil -5:19:20 - LMT 1890
-5:14 - QMT 1931
--5 EC -05/-04
+-5 EC %z
Z America/Guyana -3:52:39 - LMT 1911 Au
--4 - -04 1915 Mar
--3:45 - -0345 1975 Au
--3 - -03 1992 Mar 29 1
--4 - -04
+-4 - %z 1915 Mar
+-3:45 - %z 1975 Au
+-3 - %z 1992 Mar 29 1
+-4 - %z
Z America/Halifax -4:14:24 - LMT 1902 Jun 15
-4 H A%sT 1918
-4 C A%sT 1919
@@ -2531,12 +2529,11 @@ Z America/Havana -5:29:28 - LMT 1890
-5:29:36 - HMT 1925 Jul 19 12
-5 Q C%sT
Z America/Hermosillo -7:23:52 - LMT 1922 Ja 1 7u
--7 - MST 1927 Jun 10 23
+-7 - MST 1927 Jun 10
-6 - CST 1930 N 15
-7 m M%sT 1932 Ap
-6 - CST 1942 Ap 24
--7 - MST 1949 Ja 14
--8 - PST 1970
+-7 - MST 1996
-7 m M%sT 1999
-7 - MST
Z America/Indiana/Indianapolis -5:44:38 - LMT 1883 N 18 18u
@@ -2644,23 +2641,23 @@ Z America/Kentucky/Monticello -5:39:24 - LMT 1883 N 18 18u
Z America/La_Paz -4:32:36 - LMT 1890
-4:32:36 - CMT 1931 O 15
-4:32:36 1 BST 1932 Mar 21
--4 - -04
+-4 - %z
Z America/Lima -5:8:12 - LMT 1890
-5:8:36 - LMT 1908 Jul 28
--5 PE -05/-04
+-5 PE %z
Z America/Los_Angeles -7:52:58 - LMT 1883 N 18 20u
-8 u P%sT 1946
-8 CA P%sT 1967
-8 u P%sT
Z America/Maceio -2:22:52 - LMT 1914
--3 B -03/-02 1990 S 17
--3 - -03 1995 O 13
--3 B -03/-02 1996 S 4
--3 - -03 1999 S 30
--3 B -03/-02 2000 O 22
--3 - -03 2001 S 13
--3 B -03/-02 2002 O
--3 - -03
+-3 B %z 1990 S 17
+-3 - %z 1995 O 13
+-3 B %z 1996 S 4
+-3 - %z 1999 S 30
+-3 B %z 2000 O 22
+-3 - %z 2001 S 13
+-3 B %z 2002 O
+-3 - %z
Z America/Managua -5:45:8 - LMT 1890
-5:45:12 - MMT 1934 Jun 23
-6 - CST 1973 May
@@ -2671,10 +2668,10 @@ Z America/Managua -5:45:8 - LMT 1890
-5 - EST 1997
-6 NI C%sT
Z America/Manaus -4:0:4 - LMT 1914
--4 B -04/-03 1988 S 12
--4 - -04 1993 S 28
--4 B -04/-03 1994 S 22
--4 - -04
+-4 B %z 1988 S 12
+-4 - %z 1993 S 28
+-4 B %z 1994 S 22
+-4 - %z
Z America/Martinique -4:4:20 - LMT 1890
-4:4:20 - FFMT 1911 May
-4 - AST 1980 Ap 6
@@ -2686,12 +2683,11 @@ Z America/Matamoros -6:30 - LMT 1922 Ja 1 6u
-6 m C%sT 2010
-6 u C%sT
Z America/Mazatlan -7:5:40 - LMT 1922 Ja 1 7u
--7 - MST 1927 Jun 10 23
+-7 - MST 1927 Jun 10
-6 - CST 1930 N 15
-7 m M%sT 1932 Ap
-6 - CST 1942 Ap 24
--7 - MST 1949 Ja 14
--8 - PST 1970
+-7 - MST 1970
-7 m M%sT
Z America/Menominee -5:50:27 - LMT 1885 S 18 12
-6 u C%sT 1946
@@ -2699,8 +2695,8 @@ Z America/Menominee -5:50:27 - LMT 1885 S 18 12
-5 - EST 1973 Ap 29 2
-6 u C%sT
Z America/Merida -5:58:28 - LMT 1922 Ja 1 6u
--6 - CST 1981 D 23
--5 - EST 1982 D 2
+-6 - CST 1981 D 26 2
+-5 - EST 1982 N 2 2
-6 m C%sT
Z America/Metlakatla 15:13:42 - LMT 1867 O 19 15:44:55
-8:46:18 - LMT 1900 Au 20 12
@@ -2713,7 +2709,7 @@ Z America/Metlakatla 15:13:42 - LMT 1867 O 19 15:44:55
-8 - PST 2019 Ja 20 2
-9 u AK%sT
Z America/Mexico_City -6:36:36 - LMT 1922 Ja 1 7u
--7 - MST 1927 Jun 10 23
+-7 - MST 1927 Jun 10
-6 - CST 1930 N 15
-7 m M%sT 1932 Ap
-6 m C%sT 2001 S 30 2
@@ -2721,8 +2717,8 @@ Z America/Mexico_City -6:36:36 - LMT 1922 Ja 1 7u
-6 m C%sT
Z America/Miquelon -3:44:40 - LMT 1911 Jun 15
-4 - AST 1980 May
--3 - -03 1987
--3 C -03/-02
+-3 - %z 1987
+-3 C %z
Z America/Moncton -4:19:8 - LMT 1883 D 9
-5 - EST 1902 Jun 15
-4 C A%sT 1933
@@ -2733,20 +2729,23 @@ Z America/Moncton -4:19:8 - LMT 1883 D 9
-4 o A%sT 2007
-4 C A%sT
Z America/Monterrey -6:41:16 - LMT 1922 Ja 1 6u
+-7 - MST 1927 Jun 10
+-6 - CST 1930 N 15
+-7 m M%sT 1932 Ap
-6 - CST 1988
-6 u C%sT 1989
-6 m C%sT
Z America/Montevideo -3:44:51 - LMT 1908 Jun 10
-3:44:51 - MMT 1920 May
--4 - -04 1923 O
--3:30 U -0330/-03 1942 D 14
--3 U -03/-0230 1960
--3 U -03/-02 1968
--3 U -03/-0230 1970
--3 U -03/-02 1974
--3 U -03/-0130 1974 Mar 10
--3 U -03/-0230 1974 D 22
--3 U -03/-02
+-4 - %z 1923 O
+-3:30 U %z 1942 D 14
+-3 U %z 1960
+-3 U %z 1968
+-3 U %z 1970
+-3 U %z 1974
+-3 U %z 1974 Mar 10
+-3 U %z 1974 D 22
+-3 U %z
Z America/New_York -4:56:2 - LMT 1883 N 18 17u
-5 u E%sT 1920
-5 NY E%sT 1942
@@ -2763,12 +2762,12 @@ Z America/Nome 12:58:22 - LMT 1867 O 19 13:29:35
-9 u Y%sT 1983 N 30
-9 u AK%sT
Z America/Noronha -2:9:40 - LMT 1914
--2 B -02/-01 1990 S 17
--2 - -02 1999 S 30
--2 B -02/-01 2000 O 15
--2 - -02 2001 S 13
--2 B -02/-01 2002 O
--2 - -02
+-2 B %z 1990 S 17
+-2 - %z 1999 S 30
+-2 B %z 2000 O 15
+-2 - %z 2001 S 13
+-2 B %z 2002 O
+-2 - %z
Z America/North_Dakota/Beulah -6:47:7 - LMT 1883 N 18 19u
-7 u M%sT 2010 N 7 2
-6 u C%sT
@@ -2779,12 +2778,12 @@ Z America/North_Dakota/New_Salem -6:45:39 - LMT 1883 N 18 19u
-7 u M%sT 2003 O 26 2
-6 u C%sT
Z America/Nuuk -3:26:56 - LMT 1916 Jul 28
--3 - -03 1980 Ap 6 2
--3 E -03/-02 2023 Mar 26 1u
--2 - -02 2023 O 29 1u
--2 E -02/-01
+-3 - %z 1980 Ap 6 2
+-3 E %z 2023 Mar 26 1u
+-2 - %z 2023 O 29 1u
+-2 E %z
Z America/Ojinaga -6:57:40 - LMT 1922 Ja 1 7u
--7 - MST 1927 Jun 10 23
+-7 - MST 1927 Jun 10
-6 - CST 1930 N 15
-7 m M%sT 1932 Ap
-6 - CST 1996
@@ -2800,8 +2799,8 @@ Z America/Panama -5:18:8 - LMT 1890
Z America/Paramaribo -3:40:40 - LMT 1911
-3:40:52 - PMT 1935
-3:40:36 - PMT 1945 O
--3:30 - -0330 1984 O
--3 - -03
+-3:30 - %z 1984 O
+-3 - %z
Z America/Phoenix -7:28:18 - LMT 1883 N 18 19u
-7 u M%sT 1944 Ja 1 0:1
-7 - MST 1944 Ap 1 0:1
@@ -2813,37 +2812,37 @@ Z America/Port-au-Prince -4:49:20 - LMT 1890
-4:49 - PPMT 1917 Ja 24 12
-5 HT E%sT
Z America/Porto_Velho -4:15:36 - LMT 1914
--4 B -04/-03 1988 S 12
--4 - -04
+-4 B %z 1988 S 12
+-4 - %z
Z America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12
-4 - AST 1942 May 3
-4 u A%sT 1946
-4 - AST
Z America/Punta_Arenas -4:43:40 - LMT 1890
-4:42:45 - SMT 1910 Ja 10
--5 - -05 1916 Jul
+-5 - %z 1916 Jul
-4:42:45 - SMT 1918 S 10
--4 - -04 1919 Jul
+-4 - %z 1919 Jul
-4:42:45 - SMT 1927 S
--5 x -05/-04 1932 S
--4 - -04 1942 Jun
--5 - -05 1942 Au
--4 - -04 1946 Au 28 24
--5 1 -04 1947 Mar 31 24
--5 - -05 1947 May 21 23
--4 x -04/-03 2016 D 4
--3 - -03
+-5 x %z 1932 S
+-4 - %z 1942 Jun
+-5 - %z 1942 Au
+-4 - %z 1946 Au 28 24
+-5 1 %z 1947 Mar 31 24
+-5 - %z 1947 May 21 23
+-4 x %z 2016 D 4
+-3 - %z
Z America/Rankin_Inlet 0 - -00 1957
-6 Y C%sT 2000 O 29 2
-5 - EST 2001 Ap 1 3
-6 C C%sT
Z America/Recife -2:19:36 - LMT 1914
--3 B -03/-02 1990 S 17
--3 - -03 1999 S 30
--3 B -03/-02 2000 O 15
--3 - -03 2001 S 13
--3 B -03/-02 2002 O
--3 - -03
+-3 B %z 1990 S 17
+-3 - %z 1999 S 30
+-3 B %z 2000 O 15
+-3 - %z 2001 S 13
+-3 B %z 2002 O
+-3 - %z
Z America/Regina -6:58:36 - LMT 1905 S
-7 r M%sT 1960 Ap lastSu 2
-6 - CST
@@ -2854,28 +2853,28 @@ Z America/Resolute 0 - -00 1947 Au 31
-5 - EST 2007 Mar 11 3
-6 C C%sT
Z America/Rio_Branco -4:31:12 - LMT 1914
--5 B -05/-04 1988 S 12
--5 - -05 2008 Jun 24
--4 - -04 2013 N 10
--5 - -05
+-5 B %z 1988 S 12
+-5 - %z 2008 Jun 24
+-4 - %z 2013 N 10
+-5 - %z
Z America/Santarem -3:38:48 - LMT 1914
--4 B -04/-03 1988 S 12
--4 - -04 2008 Jun 24
--3 - -03
+-4 B %z 1988 S 12
+-4 - %z 2008 Jun 24
+-3 - %z
Z America/Santiago -4:42:45 - LMT 1890
-4:42:45 - SMT 1910 Ja 10
--5 - -05 1916 Jul
+-5 - %z 1916 Jul
-4:42:45 - SMT 1918 S 10
--4 - -04 1919 Jul
+-4 - %z 1919 Jul
-4:42:45 - SMT 1927 S
--5 x -05/-04 1932 S
--4 - -04 1942 Jun
--5 - -05 1942 Au
--4 - -04 1946 Jul 14 24
--4 1 -03 1946 Au 28 24
--5 1 -04 1947 Mar 31 24
--5 - -05 1947 May 21 23
--4 x -04/-03
+-5 x %z 1932 S
+-4 - %z 1942 Jun
+-5 - %z 1942 Au
+-4 - %z 1946 Jul 14 24
+-4 1 %z 1946 Au 28 24
+-5 1 %z 1947 Mar 31 24
+-5 - %z 1947 May 21 23
+-4 x %z
Z America/Santo_Domingo -4:39:36 - LMT 1890
-4:40 - SDMT 1933 Ap 1 12
-5 DO %s 1974 O 27
@@ -2883,14 +2882,14 @@ Z America/Santo_Domingo -4:39:36 - LMT 1890
-5 u E%sT 2000 D 3 1
-4 - AST
Z America/Sao_Paulo -3:6:28 - LMT 1914
--3 B -03/-02 1963 O 23
--3 1 -02 1964
--3 B -03/-02
+-3 B %z 1963 O 23
+-3 1 %z 1964
+-3 B %z
Z America/Scoresbysund -1:27:52 - LMT 1916 Jul 28
--2 - -02 1980 Ap 6 2
--2 c -02/-01 1981 Mar 29
--1 E -01/+00 2024 Mar 31
--2 E -02/-01
+-2 - %z 1980 Ap 6 2
+-2 c %z 1981 Mar 29
+-1 E %z 2024 Mar 31
+-2 E %z
Z America/Sitka 14:58:47 - LMT 1867 O 19 15:30
-9:1:13 - LMT 1900 Au 20 12
-8 - PST 1942
@@ -2918,15 +2917,21 @@ Z America/Thule -4:35:8 - LMT 1916 Jul 28
-4 Th A%sT
Z America/Tijuana -7:48:4 - LMT 1922 Ja 1 7u
-7 - MST 1924
--8 - PST 1927 Jun 10 23
+-8 - PST 1927 Jun 10
-7 - MST 1930 N 15
-8 - PST 1931 Ap
-8 1 PDT 1931 S 30
-8 - PST 1942 Ap 24
-8 1 PWT 1945 Au 14 23u
--8 1 PPT 1945 N 12
+-8 1 PPT 1945 N 15
-8 - PST 1948 Ap 5
-8 1 PDT 1949 Ja 14
+-8 - PST 1950 May
+-8 1 PDT 1950 S 24
+-8 - PST 1951 Ap 29 2
+-8 1 PDT 1951 S 30 2
+-8 - PST 1952 Ap 27 2
+-8 1 PDT 1952 S 28 2
-8 - PST 1954
-8 CA P%sT 1961
-8 - PST 1976
@@ -2961,31 +2966,31 @@ Z America/Yakutat 14:41:5 - LMT 1867 O 19 15:12:18
-9 u Y%sT 1983 N 30
-9 u AK%sT
Z Antarctica/Casey 0 - -00 1969
-8 - +08 2009 O 18 2
-11 - +11 2010 Mar 5 2
-8 - +08 2011 O 28 2
-11 - +11 2012 F 21 17u
-8 - +08 2016 O 22
-11 - +11 2018 Mar 11 4
-8 - +08 2018 O 7 4
-11 - +11 2019 Mar 17 3
-8 - +08 2019 O 4 3
-11 - +11 2020 Mar 8 3
-8 - +08 2020 O 4 0:1
-11 - +11 2021 Mar 14
-8 - +08 2021 O 3 0:1
-11 - +11 2022 Mar 13
-8 - +08 2022 O 2 0:1
-11 - +11 2023 Mar 9 3
-8 - +08
+8 - %z 2009 O 18 2
+11 - %z 2010 Mar 5 2
+8 - %z 2011 O 28 2
+11 - %z 2012 F 21 17u
+8 - %z 2016 O 22
+11 - %z 2018 Mar 11 4
+8 - %z 2018 O 7 4
+11 - %z 2019 Mar 17 3
+8 - %z 2019 O 4 3
+11 - %z 2020 Mar 8 3
+8 - %z 2020 O 4 0:1
+11 - %z 2021 Mar 14
+8 - %z 2021 O 3 0:1
+11 - %z 2022 Mar 13
+8 - %z 2022 O 2 0:1
+11 - %z 2023 Mar 9 3
+8 - %z
Z Antarctica/Davis 0 - -00 1957 Ja 13
-7 - +07 1964 N
+7 - %z 1964 N
0 - -00 1969 F
-7 - +07 2009 O 18 2
-5 - +05 2010 Mar 10 20u
-7 - +07 2011 O 28 2
-5 - +05 2012 F 21 20u
-7 - +07
+7 - %z 2009 O 18 2
+5 - %z 2010 Mar 10 20u
+7 - %z 2011 O 28 2
+5 - %z 2012 F 21 20u
+7 - %z
Z Antarctica/Macquarie 0 - -00 1899 N
10 - AEST 1916 O 1 2
10 1 AEDT 1917 F
@@ -2996,151 +3001,146 @@ Z Antarctica/Macquarie 0 - -00 1899 N
10 1 AEDT 2011
10 AT AE%sT
Z Antarctica/Mawson 0 - -00 1954 F 13
-6 - +06 2009 O 18 2
-5 - +05
+6 - %z 2009 O 18 2
+5 - %z
Z Antarctica/Palmer 0 - -00 1965
--4 A -04/-03 1969 O 5
--3 A -03/-02 1982 May
--4 x -04/-03 2016 D 4
--3 - -03
+-4 A %z 1969 O 5
+-3 A %z 1982 May
+-4 x %z 2016 D 4
+-3 - %z
Z Antarctica/Rothera 0 - -00 1976 D
--3 - -03
+-3 - %z
Z Antarctica/Troll 0 - -00 2005 F 12
0 Tr %s
Z Antarctica/Vostok 0 - -00 1957 D 16
-7 - +07 1994 F
+7 - %z 1994 F
0 - -00 1994 N
-7 - +07 2023 D 18 2
-5 - +05
+7 - %z 2023 D 18 2
+5 - %z
Z Asia/Almaty 5:7:48 - LMT 1924 May 2
-5 - +05 1930 Jun 21
-6 R +06/+07 1991 Mar 31 2s
-5 R +05/+06 1992 Ja 19 2s
-6 R +06/+07 2004 O 31 2s
-6 - +06 2024 Mar
-5 - +05
+5 - %z 1930 Jun 21
+6 R %z 1991 Mar 31 2s
+5 R %z 1992 Ja 19 2s
+6 R %z 2004 O 31 2s
+6 - %z 2024 Mar
+5 - %z
Z Asia/Amman 2:23:44 - LMT 1931
2 J EE%sT 2022 O 28 0s
-3 - +03
+3 - %z
Z Asia/Anadyr 11:49:56 - LMT 1924 May 2
-12 - +12 1930 Jun 21
-13 R +13/+14 1982 Ap 1 0s
-12 R +12/+13 1991 Mar 31 2s
-11 R +11/+12 1992 Ja 19 2s
-12 R +12/+13 2010 Mar 28 2s
-11 R +11/+12 2011 Mar 27 2s
-12 - +12
+12 - %z 1930 Jun 21
+13 R %z 1982 Ap 1 0s
+12 R %z 1991 Mar 31 2s
+11 R %z 1992 Ja 19 2s
+12 R %z 2010 Mar 28 2s
+11 R %z 2011 Mar 27 2s
+12 - %z
Z Asia/Aqtau 3:21:4 - LMT 1924 May 2
-4 - +04 1930 Jun 21
-5 - +05 1981 O
-6 - +06 1982 Ap
-5 R +05/+06 1991 Mar 31 2s
-4 R +04/+05 1992 Ja 19 2s
-5 R +05/+06 1994 S 25 2s
-4 R +04/+05 2004 O 31 2s
-5 - +05
+4 - %z 1930 Jun 21
+5 - %z 1981 O
+6 - %z 1982 Ap
+5 R %z 1991 Mar 31 2s
+4 R %z 1992 Ja 19 2s
+5 R %z 1994 S 25 2s
+4 R %z 2004 O 31 2s
+5 - %z
Z Asia/Aqtobe 3:48:40 - LMT 1924 May 2
-4 - +04 1930 Jun 21
-5 - +05 1981 Ap
-5 1 +06 1981 O
-6 - +06 1982 Ap
-5 R +05/+06 1991 Mar 31 2s
-4 R +04/+05 1992 Ja 19 2s
-5 R +05/+06 2004 O 31 2s
-5 - +05
+4 - %z 1930 Jun 21
+5 - %z 1981 Ap
+5 1 %z 1981 O
+6 - %z 1982 Ap
+5 R %z 1991 Mar 31 2s
+4 R %z 1992 Ja 19 2s
+5 R %z 2004 O 31 2s
+5 - %z
Z Asia/Ashgabat 3:53:32 - LMT 1924 May 2
-4 - +04 1930 Jun 21
-5 R +05/+06 1991 Mar 31 2
-4 R +04/+05 1992 Ja 19 2
-5 - +05
+4 - %z 1930 Jun 21
+5 R %z 1991 Mar 31 2
+4 R %z 1992 Ja 19 2
+5 - %z
Z Asia/Atyrau 3:27:44 - LMT 1924 May 2
-3 - +03 1930 Jun 21
-5 - +05 1981 O
-6 - +06 1982 Ap
-5 R +05/+06 1991 Mar 31 2s
-4 R +04/+05 1992 Ja 19 2s
-5 R +05/+06 1999 Mar 28 2s
-4 R +04/+05 2004 O 31 2s
-5 - +05
+3 - %z 1930 Jun 21
+5 - %z 1981 O
+6 - %z 1982 Ap
+5 R %z 1991 Mar 31 2s
+4 R %z 1992 Ja 19 2s
+5 R %z 1999 Mar 28 2s
+4 R %z 2004 O 31 2s
+5 - %z
Z Asia/Baghdad 2:57:40 - LMT 1890
2:57:36 - BMT 1918
-3 - +03 1982 May
-3 IQ +03/+04
+3 - %z 1982 May
+3 IQ %z
Z Asia/Baku 3:19:24 - LMT 1924 May 2
-3 - +03 1957 Mar
-4 R +04/+05 1991 Mar 31 2s
-3 R +03/+04 1992 S lastSu 2s
-4 - +04 1996
-4 E +04/+05 1997
-4 AZ +04/+05
+3 - %z 1957 Mar
+4 R %z 1991 Mar 31 2s
+3 R %z 1992 S lastSu 2s
+4 - %z 1996
+4 E %z 1997
+4 AZ %z
Z Asia/Bangkok 6:42:4 - LMT 1880
6:42:4 - BMT 1920 Ap
-7 - +07
+7 - %z
Z Asia/Barnaul 5:35 - LMT 1919 D 10
-6 - +06 1930 Jun 21
-7 R +07/+08 1991 Mar 31 2s
-6 R +06/+07 1992 Ja 19 2s
-7 R +07/+08 1995 May 28
-6 R +06/+07 2011 Mar 27 2s
-7 - +07 2014 O 26 2s
-6 - +06 2016 Mar 27 2s
-7 - +07
+6 - %z 1930 Jun 21
+7 R %z 1991 Mar 31 2s
+6 R %z 1992 Ja 19 2s
+7 R %z 1995 May 28
+6 R %z 2011 Mar 27 2s
+7 - %z 2014 O 26 2s
+6 - %z 2016 Mar 27 2s
+7 - %z
Z Asia/Beirut 2:22 - LMT 1880
2 l EE%sT
Z Asia/Bishkek 4:58:24 - LMT 1924 May 2
-5 - +05 1930 Jun 21
-6 R +06/+07 1991 Mar 31 2s
-5 R +05/+06 1991 Au 31 2
-5 KG +05/+06 2005 Au 12
-6 - +06
+5 - %z 1930 Jun 21
+6 R %z 1991 Mar 31 2s
+5 R %z 1991 Au 31 2
+5 KG %z 2005 Au 12
+6 - %z
Z Asia/Chita 7:33:52 - LMT 1919 D 15
-8 - +08 1930 Jun 21
-9 R +09/+10 1991 Mar 31 2s
-8 R +08/+09 1992 Ja 19 2s
-9 R +09/+10 2011 Mar 27 2s
-10 - +10 2014 O 26 2s
-8 - +08 2016 Mar 27 2
-9 - +09
-Z Asia/Choibalsan 7:38 - LMT 1905 Au
-7 - +07 1978
-8 - +08 1983 Ap
-9 X +09/+10 2008 Mar 31
-8 X +08/+09
+8 - %z 1930 Jun 21
+9 R %z 1991 Mar 31 2s
+8 R %z 1992 Ja 19 2s
+9 R %z 2011 Mar 27 2s
+10 - %z 2014 O 26 2s
+8 - %z 2016 Mar 27 2
+9 - %z
Z Asia/Colombo 5:19:24 - LMT 1880
5:19:32 - MMT 1906
-5:30 - +0530 1942 Ja 5
-5:30 0:30 +06 1942 S
-5:30 1 +0630 1945 O 16 2
-5:30 - +0530 1996 May 25
-6:30 - +0630 1996 O 26 0:30
-6 - +06 2006 Ap 15 0:30
-5:30 - +0530
+5:30 - %z 1942 Ja 5
+5:30 0:30 %z 1942 S
+5:30 1 %z 1945 O 16 2
+5:30 - %z 1996 May 25
+6:30 - %z 1996 O 26 0:30
+6 - %z 2006 Ap 15 0:30
+5:30 - %z
Z Asia/Damascus 2:25:12 - LMT 1920
2 S EE%sT 2022 O 28
-3 - +03
+3 - %z
Z Asia/Dhaka 6:1:40 - LMT 1890
5:53:20 - HMT 1941 O
-6:30 - +0630 1942 May 15
-5:30 - +0530 1942 S
-6:30 - +0630 1951 S 30
-6 - +06 2009
-6 BD +06/+07
-Z Asia/Dili 8:22:20 - LMT 1912
-8 - +08 1942 F 21 23
-9 - +09 1976 May 3
-8 - +08 2000 S 17
-9 - +09
+6:30 - %z 1942 May 15
+5:30 - %z 1942 S
+6:30 - %z 1951 S 30
+6 - %z 2009
+6 BD %z
+Z Asia/Dili 8:22:20 - LMT 1911 D 31 16u
+8 - %z 1942 F 21 23
+9 - %z 1976 May 3
+8 - %z 2000 S 17
+9 - %z
Z Asia/Dubai 3:41:12 - LMT 1920
-4 - +04
+4 - %z
Z Asia/Dushanbe 4:35:12 - LMT 1924 May 2
-5 - +05 1930 Jun 21
-6 R +06/+07 1991 Mar 31 2s
-5 1 +06 1991 S 9 2s
-5 - +05
+5 - %z 1930 Jun 21
+6 R %z 1991 Mar 31 2s
+5 1 %z 1991 S 9 2s
+5 - %z
Z Asia/Famagusta 2:15:48 - LMT 1921 N 14
2 CY EE%sT 1998 S
2 E EE%sT 2016 S 8
-3 - +03 2017 O 29 1u
+3 - %z 2017 O 29 1u
2 E EE%sT
Z Asia/Gaza 2:17:52 - LMT 1900 O
2 Z EET/EEST 1948 May 15
@@ -3162,14 +3162,14 @@ Z Asia/Hebron 2:20:23 - LMT 1900 O
2 P EE%sT
Z Asia/Ho_Chi_Minh 7:6:30 - LMT 1906 Jul
7:6:30 - PLMT 1911 May
-7 - +07 1942 D 31 23
-8 - +08 1945 Mar 14 23
-9 - +09 1945 S 1 24
-7 - +07 1947 Ap
-8 - +08 1955 Jul 1 1
-7 - +07 1959 D 31 23
-8 - +08 1975 Jun 13
-7 - +07
+7 - %z 1942 D 31 23
+8 - %z 1945 Mar 14 23
+9 - %z 1945 S 1 24
+7 - %z 1947 Ap
+8 - %z 1955 Jul 1 1
+7 - %z 1959 D 31 23
+8 - %z 1975 Jun 13
+7 - %z
Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 29 17u
8 - HKT 1941 Jun 15 3
8 1 HKST 1941 O 1 4
@@ -3177,96 +3177,96 @@ Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 29 17u
9 - JST 1945 N 18 2
8 HK HK%sT
Z Asia/Hovd 6:6:36 - LMT 1905 Au
-6 - +06 1978
-7 X +07/+08
+6 - %z 1978
+7 X %z
Z Asia/Irkutsk 6:57:5 - LMT 1880
6:57:5 - IMT 1920 Ja 25
-7 - +07 1930 Jun 21
-8 R +08/+09 1991 Mar 31 2s
-7 R +07/+08 1992 Ja 19 2s
-8 R +08/+09 2011 Mar 27 2s
-9 - +09 2014 O 26 2s
-8 - +08
+7 - %z 1930 Jun 21
+8 R %z 1991 Mar 31 2s
+7 R %z 1992 Ja 19 2s
+8 R %z 2011 Mar 27 2s
+9 - %z 2014 O 26 2s
+8 - %z
Z Asia/Jakarta 7:7:12 - LMT 1867 Au 10
7:7:12 - BMT 1923 D 31 16:40u
-7:20 - +0720 1932 N
-7:30 - +0730 1942 Mar 23
-9 - +09 1945 S 23
-7:30 - +0730 1948 May
-8 - +08 1950 May
-7:30 - +0730 1964
+7:20 - %z 1932 N
+7:30 - %z 1942 Mar 23
+9 - %z 1945 S 23
+7:30 - %z 1948 May
+8 - %z 1950 May
+7:30 - %z 1964
7 - WIB
Z Asia/Jayapura 9:22:48 - LMT 1932 N
-9 - +09 1944 S
-9:30 - +0930 1964
+9 - %z 1944 S
+9:30 - %z 1964
9 - WIT
Z Asia/Jerusalem 2:20:54 - LMT 1880
2:20:40 - JMT 1918
2 Z I%sT
Z Asia/Kabul 4:36:48 - LMT 1890
-4 - +04 1945
-4:30 - +0430
+4 - %z 1945
+4:30 - %z
Z Asia/Kamchatka 10:34:36 - LMT 1922 N 10
-11 - +11 1930 Jun 21
-12 R +12/+13 1991 Mar 31 2s
-11 R +11/+12 1992 Ja 19 2s
-12 R +12/+13 2010 Mar 28 2s
-11 R +11/+12 2011 Mar 27 2s
-12 - +12
+11 - %z 1930 Jun 21
+12 R %z 1991 Mar 31 2s
+11 R %z 1992 Ja 19 2s
+12 R %z 2010 Mar 28 2s
+11 R %z 2011 Mar 27 2s
+12 - %z
Z Asia/Karachi 4:28:12 - LMT 1907
-5:30 - +0530 1942 S
-5:30 1 +0630 1945 O 15
-5:30 - +0530 1951 S 30
-5 - +05 1971 Mar 26
+5:30 - %z 1942 S
+5:30 1 %z 1945 O 15
+5:30 - %z 1951 S 30
+5 - %z 1971 Mar 26
5 PK PK%sT
Z Asia/Kathmandu 5:41:16 - LMT 1920
-5:30 - +0530 1986
-5:45 - +0545
+5:30 - %z 1986
+5:45 - %z
Z Asia/Khandyga 9:2:13 - LMT 1919 D 15
-8 - +08 1930 Jun 21
-9 R +09/+10 1991 Mar 31 2s
-8 R +08/+09 1992 Ja 19 2s
-9 R +09/+10 2004
-10 R +10/+11 2011 Mar 27 2s
-11 - +11 2011 S 13 0s
-10 - +10 2014 O 26 2s
-9 - +09
+8 - %z 1930 Jun 21
+9 R %z 1991 Mar 31 2s
+8 R %z 1992 Ja 19 2s
+9 R %z 2004
+10 R %z 2011 Mar 27 2s
+11 - %z 2011 S 13 0s
+10 - %z 2014 O 26 2s
+9 - %z
Z Asia/Kolkata 5:53:28 - LMT 1854 Jun 28
5:53:20 - HMT 1870
5:21:10 - MMT 1906
5:30 - IST 1941 O
-5:30 1 +0630 1942 May 15
+5:30 1 %z 1942 May 15
5:30 - IST 1942 S
-5:30 1 +0630 1945 O 15
+5:30 1 %z 1945 O 15
5:30 - IST
Z Asia/Krasnoyarsk 6:11:26 - LMT 1920 Ja 6
-6 - +06 1930 Jun 21
-7 R +07/+08 1991 Mar 31 2s
-6 R +06/+07 1992 Ja 19 2s
-7 R +07/+08 2011 Mar 27 2s
-8 - +08 2014 O 26 2s
-7 - +07
+6 - %z 1930 Jun 21
+7 R %z 1991 Mar 31 2s
+6 R %z 1992 Ja 19 2s
+7 R %z 2011 Mar 27 2s
+8 - %z 2014 O 26 2s
+7 - %z
Z Asia/Kuching 7:21:20 - LMT 1926 Mar
-7:30 - +0730 1933
-8 NB +08/+0820 1942 F 16
-9 - +09 1945 S 12
-8 - +08
+7:30 - %z 1933
+8 NB %z 1942 F 16
+9 - %z 1945 S 12
+8 - %z
Z Asia/Macau 7:34:10 - LMT 1904 O 30
8 - CST 1941 D 21 23
-9 _ +09/+10 1945 S 30 24
+9 _ %z 1945 S 30 24
8 _ C%sT
Z Asia/Magadan 10:3:12 - LMT 1924 May 2
-10 - +10 1930 Jun 21
-11 R +11/+12 1991 Mar 31 2s
-10 R +10/+11 1992 Ja 19 2s
-11 R +11/+12 2011 Mar 27 2s
-12 - +12 2014 O 26 2s
-10 - +10 2016 Ap 24 2s
-11 - +11
+10 - %z 1930 Jun 21
+11 R %z 1991 Mar 31 2s
+10 R %z 1992 Ja 19 2s
+11 R %z 2011 Mar 27 2s
+12 - %z 2014 O 26 2s
+10 - %z 2016 Ap 24 2s
+11 - %z
Z Asia/Makassar 7:57:36 - LMT 1920
7:57:36 - MMT 1932 N
-8 - +08 1942 F 9
-9 - +09 1945 S 23
+8 - %z 1942 F 9
+9 - %z 1945 S 23
8 - WITA
Z Asia/Manila -15:56 - LMT 1844 D 31
8:4 - LMT 1899 May 11
@@ -3277,45 +3277,45 @@ Z Asia/Nicosia 2:13:28 - LMT 1921 N 14
2 CY EE%sT 1998 S
2 E EE%sT
Z Asia/Novokuznetsk 5:48:48 - LMT 1924 May
-6 - +06 1930 Jun 21
-7 R +07/+08 1991 Mar 31 2s
-6 R +06/+07 1992 Ja 19 2s
-7 R +07/+08 2010 Mar 28 2s
-6 R +06/+07 2011 Mar 27 2s
-7 - +07
+6 - %z 1930 Jun 21
+7 R %z 1991 Mar 31 2s
+6 R %z 1992 Ja 19 2s
+7 R %z 2010 Mar 28 2s
+6 R %z 2011 Mar 27 2s
+7 - %z
Z Asia/Novosibirsk 5:31:40 - LMT 1919 D 14 6
-6 - +06 1930 Jun 21
-7 R +07/+08 1991 Mar 31 2s
-6 R +06/+07 1992 Ja 19 2s
-7 R +07/+08 1993 May 23
-6 R +06/+07 2011 Mar 27 2s
-7 - +07 2014 O 26 2s
-6 - +06 2016 Jul 24 2s
-7 - +07
+6 - %z 1930 Jun 21
+7 R %z 1991 Mar 31 2s
+6 R %z 1992 Ja 19 2s
+7 R %z 1993 May 23
+6 R %z 2011 Mar 27 2s
+7 - %z 2014 O 26 2s
+6 - %z 2016 Jul 24 2s
+7 - %z
Z Asia/Omsk 4:53:30 - LMT 1919 N 14
-5 - +05 1930 Jun 21
-6 R +06/+07 1991 Mar 31 2s
-5 R +05/+06 1992 Ja 19 2s
-6 R +06/+07 2011 Mar 27 2s
-7 - +07 2014 O 26 2s
-6 - +06
+5 - %z 1930 Jun 21
+6 R %z 1991 Mar 31 2s
+5 R %z 1992 Ja 19 2s
+6 R %z 2011 Mar 27 2s
+7 - %z 2014 O 26 2s
+6 - %z
Z Asia/Oral 3:25:24 - LMT 1924 May 2
-3 - +03 1930 Jun 21
-5 - +05 1981 Ap
-5 1 +06 1981 O
-6 - +06 1982 Ap
-5 R +05/+06 1989 Mar 26 2s
-4 R +04/+05 1992 Ja 19 2s
-5 R +05/+06 1992 Mar 29 2s
-4 R +04/+05 2004 O 31 2s
-5 - +05
+3 - %z 1930 Jun 21
+5 - %z 1981 Ap
+5 1 %z 1981 O
+6 - %z 1982 Ap
+5 R %z 1989 Mar 26 2s
+4 R %z 1992 Ja 19 2s
+5 R %z 1992 Mar 29 2s
+4 R %z 2004 O 31 2s
+5 - %z
Z Asia/Pontianak 7:17:20 - LMT 1908 May
7:17:20 - PMT 1932 N
-7:30 - +0730 1942 Ja 29
-9 - +09 1945 S 23
-7:30 - +0730 1948 May
-8 - +08 1950 May
-7:30 - +0730 1964
+7:30 - %z 1942 Ja 29
+9 - %z 1945 S 23
+7:30 - %z 1948 May
+8 - %z 1950 May
+7:30 - %z 1964
8 - WITA 1988
7 - WIB
Z Asia/Pyongyang 8:23 - LMT 1908 Ap
@@ -3325,48 +3325,48 @@ Z Asia/Pyongyang 8:23 - LMT 1908 Ap
8:30 - KST 2018 May 4 23:30
9 - KST
Z Asia/Qatar 3:26:8 - LMT 1920
-4 - +04 1972 Jun
-3 - +03
+4 - %z 1972 Jun
+3 - %z
Z Asia/Qostanay 4:14:28 - LMT 1924 May 2
-4 - +04 1930 Jun 21
-5 - +05 1981 Ap
-5 1 +06 1981 O
-6 - +06 1982 Ap
-5 R +05/+06 1991 Mar 31 2s
-4 R +04/+05 1992 Ja 19 2s
-5 R +05/+06 2004 O 31 2s
-6 - +06 2024 Mar
-5 - +05
+4 - %z 1930 Jun 21
+5 - %z 1981 Ap
+5 1 %z 1981 O
+6 - %z 1982 Ap
+5 R %z 1991 Mar 31 2s
+4 R %z 1992 Ja 19 2s
+5 R %z 2004 O 31 2s
+6 - %z 2024 Mar
+5 - %z
Z Asia/Qyzylorda 4:21:52 - LMT 1924 May 2
-4 - +04 1930 Jun 21
-5 - +05 1981 Ap
-5 1 +06 1981 O
-6 - +06 1982 Ap
-5 R +05/+06 1991 Mar 31 2s
-4 R +04/+05 1991 S 29 2s
-5 R +05/+06 1992 Ja 19 2s
-6 R +06/+07 1992 Mar 29 2s
-5 R +05/+06 2004 O 31 2s
-6 - +06 2018 D 21
-5 - +05
+4 - %z 1930 Jun 21
+5 - %z 1981 Ap
+5 1 %z 1981 O
+6 - %z 1982 Ap
+5 R %z 1991 Mar 31 2s
+4 R %z 1991 S 29 2s
+5 R %z 1992 Ja 19 2s
+6 R %z 1992 Mar 29 2s
+5 R %z 2004 O 31 2s
+6 - %z 2018 D 21
+5 - %z
Z Asia/Riyadh 3:6:52 - LMT 1947 Mar 14
-3 - +03
+3 - %z
Z Asia/Sakhalin 9:30:48 - LMT 1905 Au 23
-9 - +09 1945 Au 25
-11 R +11/+12 1991 Mar 31 2s
-10 R +10/+11 1992 Ja 19 2s
-11 R +11/+12 1997 Mar lastSu 2s
-10 R +10/+11 2011 Mar 27 2s
-11 - +11 2014 O 26 2s
-10 - +10 2016 Mar 27 2s
-11 - +11
+9 - %z 1945 Au 25
+11 R %z 1991 Mar 31 2s
+10 R %z 1992 Ja 19 2s
+11 R %z 1997 Mar lastSu 2s
+10 R %z 2011 Mar 27 2s
+11 - %z 2014 O 26 2s
+10 - %z 2016 Mar 27 2s
+11 - %z
Z Asia/Samarkand 4:27:53 - LMT 1924 May 2
-4 - +04 1930 Jun 21
-5 - +05 1981 Ap
-5 1 +06 1981 O
-6 - +06 1982 Ap
-5 R +05/+06 1992
-5 - +05
+4 - %z 1930 Jun 21
+5 - %z 1981 Ap
+5 1 %z 1981 O
+6 - %z 1982 Ap
+5 R %z 1992
+5 - %z
Z Asia/Seoul 8:27:52 - LMT 1908 Ap
8:30 - KST 1912
9 - JST 1945 S 8
@@ -3378,161 +3378,147 @@ Z Asia/Shanghai 8:5:43 - LMT 1901
8 CN C%sT
Z Asia/Singapore 6:55:25 - LMT 1901
6:55:25 - SMT 1905 Jun
-7 - +07 1933
-7 0:20 +0720 1936
-7:20 - +0720 1941 S
-7:30 - +0730 1942 F 16
-9 - +09 1945 S 12
-7:30 - +0730 1981 D 31 16u
-8 - +08
+7 - %z 1933
+7 0:20 %z 1936
+7:20 - %z 1941 S
+7:30 - %z 1942 F 16
+9 - %z 1945 S 12
+7:30 - %z 1981 D 31 16u
+8 - %z
Z Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2
-10 - +10 1930 Jun 21
-11 R +11/+12 1991 Mar 31 2s
-10 R +10/+11 1992 Ja 19 2s
-11 R +11/+12 2011 Mar 27 2s
-12 - +12 2014 O 26 2s
-11 - +11
+10 - %z 1930 Jun 21
+11 R %z 1991 Mar 31 2s
+10 R %z 1992 Ja 19 2s
+11 R %z 2011 Mar 27 2s
+12 - %z 2014 O 26 2s
+11 - %z
Z Asia/Taipei 8:6 - LMT 1896
8 - CST 1937 O
9 - JST 1945 S 21 1
8 f C%sT
Z Asia/Tashkent 4:37:11 - LMT 1924 May 2
-5 - +05 1930 Jun 21
-6 R +06/+07 1991 Mar 31 2
-5 R +05/+06 1992
-5 - +05
+5 - %z 1930 Jun 21
+6 R %z 1991 Mar 31 2
+5 R %z 1992
+5 - %z
Z Asia/Tbilisi 2:59:11 - LMT 1880
2:59:11 - TBMT 1924 May 2
-3 - +03 1957 Mar
-4 R +04/+05 1991 Mar 31 2s
-3 R +03/+04 1992
-3 e +03/+04 1994 S lastSu
-4 e +04/+05 1996 O lastSu
-4 1 +05 1997 Mar lastSu
-4 e +04/+05 2004 Jun 27
-3 R +03/+04 2005 Mar lastSu 2
-4 - +04
+3 - %z 1957 Mar
+4 R %z 1991 Mar 31 2s
+3 R %z 1992
+3 e %z 1994 S lastSu
+4 e %z 1996 O lastSu
+4 1 %z 1997 Mar lastSu
+4 e %z 2004 Jun 27
+3 R %z 2005 Mar lastSu 2
+4 - %z
Z Asia/Tehran 3:25:44 - LMT 1916
3:25:44 - TMT 1935 Jun 13
-3:30 i +0330/+0430 1977 O 20 24
-4 i +04/+05 1979
-3:30 i +0330/+0430
+3:30 i %z 1977 O 20 24
+4 i %z 1979
+3:30 i %z
Z Asia/Thimphu 5:58:36 - LMT 1947 Au 15
-5:30 - +0530 1987 O
-6 - +06
+5:30 - %z 1987 O
+6 - %z
Z Asia/Tokyo 9:18:59 - LMT 1887 D 31 15u
9 JP J%sT
Z Asia/Tomsk 5:39:51 - LMT 1919 D 22
-6 - +06 1930 Jun 21
-7 R +07/+08 1991 Mar 31 2s
-6 R +06/+07 1992 Ja 19 2s
-7 R +07/+08 2002 May 1 3
-6 R +06/+07 2011 Mar 27 2s
-7 - +07 2014 O 26 2s
-6 - +06 2016 May 29 2s
-7 - +07
+6 - %z 1930 Jun 21
+7 R %z 1991 Mar 31 2s
+6 R %z 1992 Ja 19 2s
+7 R %z 2002 May 1 3
+6 R %z 2011 Mar 27 2s
+7 - %z 2014 O 26 2s
+6 - %z 2016 May 29 2s
+7 - %z
Z Asia/Ulaanbaatar 7:7:32 - LMT 1905 Au
-7 - +07 1978
-8 X +08/+09
+7 - %z 1978
+8 X %z
Z Asia/Urumqi 5:50:20 - LMT 1928
-6 - +06
+6 - %z
Z Asia/Ust-Nera 9:32:54 - LMT 1919 D 15
-8 - +08 1930 Jun 21
-9 R +09/+10 1981 Ap
-11 R +11/+12 1991 Mar 31 2s
-10 R +10/+11 1992 Ja 19 2s
-11 R +11/+12 2011 Mar 27 2s
-12 - +12 2011 S 13 0s
-11 - +11 2014 O 26 2s
-10 - +10
+8 - %z 1930 Jun 21
+9 R %z 1981 Ap
+11 R %z 1991 Mar 31 2s
+10 R %z 1992 Ja 19 2s
+11 R %z 2011 Mar 27 2s
+12 - %z 2011 S 13 0s
+11 - %z 2014 O 26 2s
+10 - %z
Z Asia/Vladivostok 8:47:31 - LMT 1922 N 15
-9 - +09 1930 Jun 21
-10 R +10/+11 1991 Mar 31 2s
-9 R +09/+10 1992 Ja 19 2s
-10 R +10/+11 2011 Mar 27 2s
-11 - +11 2014 O 26 2s
-10 - +10
+9 - %z 1930 Jun 21
+10 R %z 1991 Mar 31 2s
+9 R %z 1992 Ja 19 2s
+10 R %z 2011 Mar 27 2s
+11 - %z 2014 O 26 2s
+10 - %z
Z Asia/Yakutsk 8:38:58 - LMT 1919 D 15
-8 - +08 1930 Jun 21
-9 R +09/+10 1991 Mar 31 2s
-8 R +08/+09 1992 Ja 19 2s
-9 R +09/+10 2011 Mar 27 2s
-10 - +10 2014 O 26 2s
-9 - +09
+8 - %z 1930 Jun 21
+9 R %z 1991 Mar 31 2s
+8 R %z 1992 Ja 19 2s
+9 R %z 2011 Mar 27 2s
+10 - %z 2014 O 26 2s
+9 - %z
Z Asia/Yangon 6:24:47 - LMT 1880
6:24:47 - RMT 1920
-6:30 - +0630 1942 May
-9 - +09 1945 May 3
-6:30 - +0630
+6:30 - %z 1942 May
+9 - %z 1945 May 3
+6:30 - %z
Z Asia/Yekaterinburg 4:2:33 - LMT 1916 Jul 3
3:45:5 - PMT 1919 Jul 15 4
-4 - +04 1930 Jun 21
-5 R +05/+06 1991 Mar 31 2s
-4 R +04/+05 1992 Ja 19 2s
-5 R +05/+06 2011 Mar 27 2s
-6 - +06 2014 O 26 2s
-5 - +05
+4 - %z 1930 Jun 21
+5 R %z 1991 Mar 31 2s
+4 R %z 1992 Ja 19 2s
+5 R %z 2011 Mar 27 2s
+6 - %z 2014 O 26 2s
+5 - %z
Z Asia/Yerevan 2:58 - LMT 1924 May 2
-3 - +03 1957 Mar
-4 R +04/+05 1991 Mar 31 2s
-3 R +03/+04 1995 S 24 2s
-4 - +04 1997
-4 R +04/+05 2011
-4 AM +04/+05
+3 - %z 1957 Mar
+4 R %z 1991 Mar 31 2s
+3 R %z 1995 S 24 2s
+4 - %z 1997
+4 R %z 2011
+4 AM %z
Z Atlantic/Azores -1:42:40 - LMT 1884
-1:54:32 - HMT 1912 Ja 1 2u
--2 p -02/-01 1942 Ap 25 22s
--2 p +00 1942 Au 15 22s
--2 p -02/-01 1943 Ap 17 22s
--2 p +00 1943 Au 28 22s
--2 p -02/-01 1944 Ap 22 22s
--2 p +00 1944 Au 26 22s
--2 p -02/-01 1945 Ap 21 22s
--2 p +00 1945 Au 25 22s
--2 p -02/-01 1966 Ap 3 2
--1 p -01/+00 1983 S 25 1s
--1 W- -01/+00 1992 S 27 1s
-0 E WE%sT 1993 Mar 28 1u
--1 E -01/+00
+-2 p %z 1966 O 2 2s
+-1 - %z 1982 Mar 28 0s
+-1 p %z 1986
+-1 E %z 1992 D 27 1s
+0 E WE%sT 1993 Jun 17 1u
+-1 E %z
Z Atlantic/Bermuda -4:19:18 - LMT 1890
-4:19:18 Be BMT/BST 1930 Ja 1 2
-4 Be A%sT 1974 Ap 28 2
-4 C A%sT 1976
-4 u A%sT
Z Atlantic/Canary -1:1:36 - LMT 1922 Mar
--1 - -01 1946 S 30 1
+-1 - %z 1946 S 30 1
0 - WET 1980 Ap 6 0s
0 1 WEST 1980 S 28 1u
0 E WE%sT
Z Atlantic/Cape_Verde -1:34:4 - LMT 1912 Ja 1 2u
--2 - -02 1942 S
--2 1 -01 1945 O 15
--2 - -02 1975 N 25 2
--1 - -01
+-2 - %z 1942 S
+-2 1 %z 1945 O 15
+-2 - %z 1975 N 25 2
+-1 - %z
Z Atlantic/Faroe -0:27:4 - LMT 1908 Ja 11
0 - WET 1981
0 E WE%sT
Z Atlantic/Madeira -1:7:36 - LMT 1884
-1:7:36 - FMT 1912 Ja 1 1u
--1 p -01/+00 1942 Ap 25 22s
--1 p +01 1942 Au 15 22s
--1 p -01/+00 1943 Ap 17 22s
--1 p +01 1943 Au 28 22s
--1 p -01/+00 1944 Ap 22 22s
--1 p +01 1944 Au 26 22s
--1 p -01/+00 1945 Ap 21 22s
--1 p +01 1945 Au 25 22s
--1 p -01/+00 1966 Ap 3 2
-0 p WE%sT 1983 S 25 1s
+-1 p %z 1966 O 2 2s
+0 - WET 1982 Ap 4
+0 p WE%sT 1986 Jul 31
0 E WE%sT
Z Atlantic/South_Georgia -2:26:8 - LMT 1890
--2 - -02
+-2 - %z
Z Atlantic/Stanley -3:51:24 - LMT 1890
-3:51:24 - SMT 1912 Mar 12
--4 FK -04/-03 1983 May
--3 FK -03/-02 1985 S 15
--4 FK -04/-03 2010 S 5 2
--3 - -03
+-4 FK %z 1983 May
+-3 FK %z 1985 S 15
+-4 FK %z 2010 S 5 2
+-3 - %z
Z Australia/Adelaide 9:14:20 - LMT 1895 F
9 - ACST 1899 May
9:30 AU AC%sT 1971
@@ -3550,8 +3536,8 @@ Z Australia/Darwin 8:43:20 - LMT 1895 F
9 - ACST 1899 May
9:30 AU AC%sT
Z Australia/Eucla 8:35:28 - LMT 1895 D
-8:45 AU +0845/+0945 1943 Jul
-8:45 AW +0845/+0945
+8:45 AU %z 1943 Jul
+8:45 AW %z
Z Australia/Hobart 9:49:16 - LMT 1895 S
10 AT AE%sT 1919 O 24
10 AU AE%sT 1967
@@ -3562,8 +3548,8 @@ Z Australia/Lindeman 9:55:56 - LMT 1895
10 Ho AE%sT
Z Australia/Lord_Howe 10:36:20 - LMT 1895 F
10 - AEST 1981 Mar
-10:30 LH +1030/+1130 1985 Jul
-10:30 LH +1030/+11
+10:30 LH %z 1985 Jul
+10:30 LH %z
Z Australia/Melbourne 9:39:52 - LMT 1895 F
10 AU AE%sT 1971
10 AV AE%sT
@@ -3573,52 +3559,47 @@ Z Australia/Perth 7:43:24 - LMT 1895 D
Z Australia/Sydney 10:4:52 - LMT 1895 F
10 AU AE%sT 1971
10 AN AE%sT
-Z CET 1 c CE%sT
-Z CST6CDT -6 u C%sT
-Z EET 2 E EE%sT
-Z EST -5 - EST
-Z EST5EDT -5 u E%sT
Z Etc/GMT 0 - GMT
-Z Etc/GMT+1 -1 - -01
-Z Etc/GMT+10 -10 - -10
-Z Etc/GMT+11 -11 - -11
-Z Etc/GMT+12 -12 - -12
-Z Etc/GMT+2 -2 - -02
-Z Etc/GMT+3 -3 - -03
-Z Etc/GMT+4 -4 - -04
-Z Etc/GMT+5 -5 - -05
-Z Etc/GMT+6 -6 - -06
-Z Etc/GMT+7 -7 - -07
-Z Etc/GMT+8 -8 - -08
-Z Etc/GMT+9 -9 - -09
-Z Etc/GMT-1 1 - +01
-Z Etc/GMT-10 10 - +10
-Z Etc/GMT-11 11 - +11
-Z Etc/GMT-12 12 - +12
-Z Etc/GMT-13 13 - +13
-Z Etc/GMT-14 14 - +14
-Z Etc/GMT-2 2 - +02
-Z Etc/GMT-3 3 - +03
-Z Etc/GMT-4 4 - +04
-Z Etc/GMT-5 5 - +05
-Z Etc/GMT-6 6 - +06
-Z Etc/GMT-7 7 - +07
-Z Etc/GMT-8 8 - +08
-Z Etc/GMT-9 9 - +09
+Z Etc/GMT+1 -1 - %z
+Z Etc/GMT+10 -10 - %z
+Z Etc/GMT+11 -11 - %z
+Z Etc/GMT+12 -12 - %z
+Z Etc/GMT+2 -2 - %z
+Z Etc/GMT+3 -3 - %z
+Z Etc/GMT+4 -4 - %z
+Z Etc/GMT+5 -5 - %z
+Z Etc/GMT+6 -6 - %z
+Z Etc/GMT+7 -7 - %z
+Z Etc/GMT+8 -8 - %z
+Z Etc/GMT+9 -9 - %z
+Z Etc/GMT-1 1 - %z
+Z Etc/GMT-10 10 - %z
+Z Etc/GMT-11 11 - %z
+Z Etc/GMT-12 12 - %z
+Z Etc/GMT-13 13 - %z
+Z Etc/GMT-14 14 - %z
+Z Etc/GMT-2 2 - %z
+Z Etc/GMT-3 3 - %z
+Z Etc/GMT-4 4 - %z
+Z Etc/GMT-5 5 - %z
+Z Etc/GMT-6 6 - %z
+Z Etc/GMT-7 7 - %z
+Z Etc/GMT-8 8 - %z
+Z Etc/GMT-9 9 - %z
Z Etc/UTC 0 - UTC
Z Europe/Andorra 0:6:4 - LMT 1901
0 - WET 1946 S 30
1 - CET 1985 Mar 31 2
1 E CE%sT
Z Europe/Astrakhan 3:12:12 - LMT 1924 May
-3 - +03 1930 Jun 21
-4 R +04/+05 1989 Mar 26 2s
-3 R +03/+04 1991 Mar 31 2s
-4 - +04 1992 Mar 29 2s
-3 R +03/+04 2011 Mar 27 2s
-4 - +04 2014 O 26 2s
-3 - +03 2016 Mar 27 2s
-4 - +04
+3 - %z 1930 Jun 21
+4 R %z 1989 Mar 26 2s
+3 R %z 1991 Mar 31 2s
+4 - %z 1992 Mar 29 2s
+3 R %z 2011 Mar 27 2s
+4 - %z 2014 O 26 2s
+3 - %z 2016 Mar 27 2s
+4 - %z
Z Europe/Athens 1:34:52 - LMT 1895 S 14
1:34:52 - AMT 1916 Jul 28 0:1
2 g EE%sT 1941 Ap 30
@@ -3691,7 +3672,7 @@ Z Europe/Helsinki 1:39:49 - LMT 1878 May 31
Z Europe/Istanbul 1:55:52 - LMT 1880
1:56:56 - IMT 1910 O
2 T EE%sT 1978 Jun 29
-3 T +03/+04 1984 N 1 2
+3 T %z 1984 N 1 2
2 T EE%sT 2007
2 E EE%sT 2011 Mar 27 1u
2 - EET 2011 Mar 28 1u
@@ -3700,19 +3681,19 @@ Z Europe/Istanbul 1:55:52 - LMT 1880
2 E EE%sT 2015 O 25 1u
2 1 EEST 2015 N 8 1u
2 E EE%sT 2016 S 7
-3 - +03
+3 - %z
Z Europe/Kaliningrad 1:22 - LMT 1893 Ap
1 c CE%sT 1945 Ap 10
2 O EE%sT 1946 Ap 7
3 R MSK/MSD 1989 Mar 26 2s
2 R EE%sT 2011 Mar 27 2s
-3 - +03 2014 O 26 2s
+3 - %z 2014 O 26 2s
2 - EET
Z Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0u
-3 - +03 1930 Jun 21
-4 R +04/+05 1989 Mar 26 2s
+3 - %z 1930 Jun 21
+4 R %z 1989 Mar 26 2s
3 R MSK/MSD 1991 Mar 31 2s
-4 - +04 1992 Mar 29 2s
+4 - %z 1992 Mar 29 2s
3 R MSK/MSD 2011 Mar 27 2s
4 - MSK 2014 O 26 2s
3 - MSK
@@ -3727,10 +3708,10 @@ Z Europe/Kyiv 2:2:4 - LMT 1880
2 E EE%sT
Z Europe/Lisbon -0:36:45 - LMT 1884
-0:36:45 - LMT 1912 Ja 1 0u
-0 p WE%sT 1966 Ap 3 2
+0 p WE%sT 1966 O 2 2s
1 - CET 1976 S 26 1
-0 p WE%sT 1983 S 25 1s
-0 W- WE%sT 1992 S 27 1s
+0 p WE%sT 1986
+0 E WE%sT 1992 S 27 1u
1 E CE%sT 1996 Mar 31 1u
0 E WE%sT
Z Europe/London -0:1:15 - LMT 1847 D
@@ -3754,7 +3735,7 @@ Z Europe/Minsk 1:50:16 - LMT 1880
3 R MSK/MSD 1990
3 - MSK 1991 Mar 31 2s
2 R EE%sT 2011 Mar 27 2s
-3 - +03
+3 - %z
Z Europe/Moscow 2:30:17 - LMT 1880
2:30:17 - MMT 1916 Jul 3
2:31:19 R %s 1919 Jul 1 0u
@@ -3802,24 +3783,24 @@ Z Europe/Rome 0:49:56 - LMT 1866 D 12
1 I CE%sT 1980
1 E CE%sT
Z Europe/Samara 3:20:20 - LMT 1919 Jul 1 0u
-3 - +03 1930 Jun 21
-4 - +04 1935 Ja 27
-4 R +04/+05 1989 Mar 26 2s
-3 R +03/+04 1991 Mar 31 2s
-2 R +02/+03 1991 S 29 2s
-3 - +03 1991 O 20 3
-4 R +04/+05 2010 Mar 28 2s
-3 R +03/+04 2011 Mar 27 2s
-4 - +04
+3 - %z 1930 Jun 21
+4 - %z 1935 Ja 27
+4 R %z 1989 Mar 26 2s
+3 R %z 1991 Mar 31 2s
+2 R %z 1991 S 29 2s
+3 - %z 1991 O 20 3
+4 R %z 2010 Mar 28 2s
+3 R %z 2011 Mar 27 2s
+4 - %z
Z Europe/Saratov 3:4:18 - LMT 1919 Jul 1 0u
-3 - +03 1930 Jun 21
-4 R +04/+05 1988 Mar 27 2s
-3 R +03/+04 1991 Mar 31 2s
-4 - +04 1992 Mar 29 2s
-3 R +03/+04 2011 Mar 27 2s
-4 - +04 2014 O 26 2s
-3 - +03 2016 D 4 2s
-4 - +04
+3 - %z 1930 Jun 21
+4 R %z 1988 Mar 27 2s
+3 R %z 1991 Mar 31 2s
+4 - %z 1992 Mar 29 2s
+3 R %z 2011 Mar 27 2s
+4 - %z 2014 O 26 2s
+3 - %z 2016 D 4 2s
+4 - %z
Z Europe/Simferopol 2:16:24 - LMT 1880
2:16 - SMT 1924 May 2
2 - EET 1930 Jun 21
@@ -3863,14 +3844,14 @@ Z Europe/Tirane 1:19:20 - LMT 1914
1 q CE%sT 1984 Jul
1 E CE%sT
Z Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0u
-3 - +03 1930 Jun 21
-4 R +04/+05 1989 Mar 26 2s
-3 R +03/+04 1991 Mar 31 2s
-2 R +02/+03 1992 Ja 19 2s
-3 R +03/+04 2011 Mar 27 2s
-4 - +04 2014 O 26 2s
-3 - +03 2016 Mar 27 2s
-4 - +04
+3 - %z 1930 Jun 21
+4 R %z 1989 Mar 26 2s
+3 R %z 1991 Mar 31 2s
+2 R %z 1992 Ja 19 2s
+3 R %z 2011 Mar 27 2s
+4 - %z 2014 O 26 2s
+3 - %z 2016 Mar 27 2s
+4 - %z
Z Europe/Vienna 1:5:21 - LMT 1893 Ap
1 c CE%sT 1920
1 a CE%sT 1940 Ap 1 2s
@@ -3895,15 +3876,15 @@ Z Europe/Vilnius 1:41:16 - LMT 1880
2 - EET 2003
2 E EE%sT
Z Europe/Volgograd 2:57:40 - LMT 1920 Ja 3
-3 - +03 1930 Jun 21
-4 - +04 1961 N 11
-4 R +04/+05 1988 Mar 27 2s
+3 - %z 1930 Jun 21
+4 - %z 1961 N 11
+4 R %z 1988 Mar 27 2s
3 R MSK/MSD 1991 Mar 31 2s
-4 - +04 1992 Mar 29 2s
+4 - %z 1992 Mar 29 2s
3 R MSK/MSD 2011 Mar 27 2s
4 - MSK 2014 O 26 2s
3 - MSK 2018 O 28 2s
-4 - +04 2020 D 27 2s
+4 - %z 2020 D 27 2s
3 - MSK
Z Europe/Warsaw 1:24 - LMT 1880
1:24 - WMT 1915 Au 5
@@ -3919,58 +3900,53 @@ Z Europe/Zurich 0:34:8 - LMT 1853 Jul 16
1 CH CE%sT 1981
1 E CE%sT
Z Factory 0 - -00
-Z HST -10 - HST
Z Indian/Chagos 4:49:40 - LMT 1907
-5 - +05 1996
-6 - +06
+5 - %z 1996
+6 - %z
Z Indian/Maldives 4:54 - LMT 1880
4:54 - MMT 1960
-5 - +05
+5 - %z
Z Indian/Mauritius 3:50 - LMT 1907
-4 MU +04/+05
-Z MET 1 c ME%sT
-Z MST -7 - MST
-Z MST7MDT -7 u M%sT
-Z PST8PDT -8 u P%sT
+4 MU %z
Z Pacific/Apia 12:33:4 - LMT 1892 Jul 5
-11:26:56 - LMT 1911
--11:30 - -1130 1950
--11 WS -11/-10 2011 D 29 24
-13 WS +13/+14
+-11:30 - %z 1950
+-11 WS %z 2011 D 29 24
+13 WS %z
Z Pacific/Auckland 11:39:4 - LMT 1868 N 2
11:30 NZ NZ%sT 1946
12 NZ NZ%sT
Z Pacific/Bougainville 10:22:16 - LMT 1880
9:48:32 - PMMT 1895
-10 - +10 1942 Jul
-9 - +09 1945 Au 21
-10 - +10 2014 D 28 2
-11 - +11
+10 - %z 1942 Jul
+9 - %z 1945 Au 21
+10 - %z 2014 D 28 2
+11 - %z
Z Pacific/Chatham 12:13:48 - LMT 1868 N 2
-12:15 - +1215 1946
-12:45 k +1245/+1345
+12:15 - %z 1946
+12:45 k %z
Z Pacific/Easter -7:17:28 - LMT 1890
-7:17:28 - EMT 1932 S
--7 x -07/-06 1982 Mar 14 3u
--6 x -06/-05
+-7 x %z 1982 Mar 14 3u
+-6 x %z
Z Pacific/Efate 11:13:16 - LMT 1912 Ja 13
-11 VU +11/+12
+11 VU %z
Z Pacific/Fakaofo -11:24:56 - LMT 1901
--11 - -11 2011 D 30
-13 - +13
+-11 - %z 2011 D 30
+13 - %z
Z Pacific/Fiji 11:55:44 - LMT 1915 O 26
-12 FJ +12/+13
+12 FJ %z
Z Pacific/Galapagos -5:58:24 - LMT 1931
--5 - -05 1986
--6 EC -06/-05
+-5 - %z 1986
+-6 EC %z
Z Pacific/Gambier -8:59:48 - LMT 1912 O
--9 - -09
+-9 - %z
Z Pacific/Guadalcanal 10:39:48 - LMT 1912 O
-11 - +11
+11 - %z
Z Pacific/Guam -14:21 - LMT 1844 D 31
9:39 - LMT 1901
10 - GST 1941 D 10
-9 - +09 1944 Jul 31
+9 - %z 1944 Jul 31
10 Gu G%sT 2000 D 23
10 - ChST
Z Pacific/Honolulu -10:31:26 - LMT 1896 Ja 13 12
@@ -3979,74 +3955,73 @@ Z Pacific/Honolulu -10:31:26 - LMT 1896 Ja 13 12
-10:30 u H%sT 1947 Jun 8 2
-10 - HST
Z Pacific/Kanton 0 - -00 1937 Au 31
--12 - -12 1979 O
--11 - -11 1994 D 31
-13 - +13
+-12 - %z 1979 O
+-11 - %z 1994 D 31
+13 - %z
Z Pacific/Kiritimati -10:29:20 - LMT 1901
--10:40 - -1040 1979 O
--10 - -10 1994 D 31
-14 - +14
+-10:40 - %z 1979 O
+-10 - %z 1994 D 31
+14 - %z
Z Pacific/Kosrae -13:8:4 - LMT 1844 D 31
10:51:56 - LMT 1901
-11 - +11 1914 O
-9 - +09 1919 F
-11 - +11 1937
-10 - +10 1941 Ap
-9 - +09 1945 Au
-11 - +11 1969 O
-12 - +12 1999
-11 - +11
+11 - %z 1914 O
+9 - %z 1919 F
+11 - %z 1937
+10 - %z 1941 Ap
+9 - %z 1945 Au
+11 - %z 1969 O
+12 - %z 1999
+11 - %z
Z Pacific/Kwajalein 11:9:20 - LMT 1901
-11 - +11 1937
-10 - +10 1941 Ap
-9 - +09 1944 F 6
-11 - +11 1969 O
--12 - -12 1993 Au 20 24
-12 - +12
+11 - %z 1937
+10 - %z 1941 Ap
+9 - %z 1944 F 6
+11 - %z 1969 O
+-12 - %z 1993 Au 20 24
+12 - %z
Z Pacific/Marquesas -9:18 - LMT 1912 O
--9:30 - -0930
+-9:30 - %z
Z Pacific/Nauru 11:7:40 - LMT 1921 Ja 15
-11:30 - +1130 1942 Au 29
-9 - +09 1945 S 8
-11:30 - +1130 1979 F 10 2
-12 - +12
+11:30 - %z 1942 Au 29
+9 - %z 1945 S 8
+11:30 - %z 1979 F 10 2
+12 - %z
Z Pacific/Niue -11:19:40 - LMT 1952 O 16
--11:20 - -1120 1964 Jul
--11 - -11
+-11:20 - %z 1964 Jul
+-11 - %z
Z Pacific/Norfolk 11:11:52 - LMT 1901
-11:12 - +1112 1951
-11:30 - +1130 1974 O 27 2s
-11:30 1 +1230 1975 Mar 2 2s
-11:30 - +1130 2015 O 4 2s
-11 - +11 2019 Jul
-11 AN +11/+12
+11:12 - %z 1951
+11:30 - %z 1974 O 27 2s
+11:30 1 %z 1975 Mar 2 2s
+11:30 - %z 2015 O 4 2s
+11 - %z 2019 Jul
+11 AN %z
Z Pacific/Noumea 11:5:48 - LMT 1912 Ja 13
-11 NC +11/+12
+11 NC %z
Z Pacific/Pago_Pago 12:37:12 - LMT 1892 Jul 5
-11:22:48 - LMT 1911
-11 - SST
Z Pacific/Palau -15:2:4 - LMT 1844 D 31
8:57:56 - LMT 1901
-9 - +09
+9 - %z
Z Pacific/Pitcairn -8:40:20 - LMT 1901
--8:30 - -0830 1998 Ap 27
--8 - -08
+-8:30 - %z 1998 Ap 27
+-8 - %z
Z Pacific/Port_Moresby 9:48:40 - LMT 1880
9:48:32 - PMMT 1895
-10 - +10
+10 - %z
Z Pacific/Rarotonga 13:20:56 - LMT 1899 D 26
-10:39:4 - LMT 1952 O 16
--10:30 - -1030 1978 N 12
--10 CK -10/-0930
+-10:30 - %z 1978 N 12
+-10 CK %z
Z Pacific/Tahiti -9:58:16 - LMT 1912 O
--10 - -10
+-10 - %z
Z Pacific/Tarawa 11:32:4 - LMT 1901
-12 - +12
+12 - %z
Z Pacific/Tongatapu 12:19:12 - LMT 1945 S 10
-12:20 - +1220 1961
-13 - +13 1999
-13 TO +13/+14
-Z WET 0 E WE%sT
+12:20 - %z 1961
+13 - %z 1999
+13 TO %z
L Etc/GMT GMT
L Australia/Sydney Australia/ACT
L Australia/Lord_Howe Australia/LHI
@@ -4062,6 +4037,8 @@ L America/Rio_Branco Brazil/Acre
L America/Noronha Brazil/DeNoronha
L America/Sao_Paulo Brazil/East
L America/Manaus Brazil/West
+L Europe/Brussels CET
+L America/Chicago CST6CDT
L America/Halifax Canada/Atlantic
L America/Winnipeg Canada/Central
L America/Toronto Canada/Eastern
@@ -4073,6 +4050,9 @@ L America/Whitehorse Canada/Yukon
L America/Santiago Chile/Continental
L Pacific/Easter Chile/EasterIsland
L America/Havana Cuba
+L Europe/Athens EET
+L America/Panama EST
+L America/New_York EST5EDT
L Africa/Cairo Egypt
L Europe/Dublin Eire
L Etc/GMT Etc/GMT+0
@@ -4096,6 +4076,9 @@ L America/Jamaica Jamaica
L Asia/Tokyo Japan
L Pacific/Kwajalein Kwajalein
L Africa/Tripoli Libya
+L Europe/Brussels MET
+L America/Phoenix MST
+L America/Denver MST7MDT
L America/Tijuana Mexico/BajaNorte
L America/Mazatlan Mexico/BajaSur
L America/Mexico_City Mexico/General
@@ -4259,6 +4242,7 @@ L America/Denver America/Shiprock
L America/Toronto America/Thunder_Bay
L America/Edmonton America/Yellowknife
L Pacific/Auckland Antarctica/South_Pole
+L Asia/Ulaanbaatar Asia/Choibalsan
L Asia/Shanghai Asia/Chongqing
L Asia/Shanghai Asia/Harbin
L Asia/Urumqi Asia/Kashgar
@@ -4273,6 +4257,7 @@ L Europe/Kyiv Europe/Zaporozhye
L Pacific/Kanton Pacific/Enderbury
L Pacific/Honolulu Pacific/Johnston
L Pacific/Port_Moresby Pacific/Yap
+L Europe/Lisbon WET
L Africa/Nairobi Africa/Asmera
L America/Nuuk America/Godthab
L Asia/Ashgabat Asia/Ashkhabad
@@ -4290,5 +4275,7 @@ L Asia/Ulaanbaatar Asia/Ulan_Bator
L Atlantic/Faroe Atlantic/Faeroe
L Europe/Kyiv Europe/Kiev
L Asia/Nicosia Europe/Nicosia
+L Pacific/Honolulu HST
+L America/Los_Angeles PST8PDT
L Pacific/Guadalcanal Pacific/Ponape
L Pacific/Port_Moresby Pacific/Truk
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/zone.tab b/contrib/python/tzdata/tzdata/zoneinfo/zone.tab
index 3fa9306afb..bfc0b59330 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/zone.tab
+++ b/contrib/python/tzdata/tzdata/zoneinfo/zone.tab
@@ -264,8 +264,7 @@ MK +4159+02126 Europe/Skopje
ML +1239-00800 Africa/Bamako
MM +1647+09610 Asia/Yangon
MN +4755+10653 Asia/Ulaanbaatar most of Mongolia
-MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan
-MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar
+MN +4801+09139 Asia/Hovd Bayan-Olgii, Hovd, Uvs
MO +221150+1133230 Asia/Macau
MP +1512+14545 Pacific/Saipan
MQ +1436-06105 America/Martinique
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/zone1970.tab b/contrib/python/tzdata/tzdata/zoneinfo/zone1970.tab
index abd9489753..7726f39a09 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/zone1970.tab
+++ b/contrib/python/tzdata/tzdata/zoneinfo/zone1970.tab
@@ -209,8 +209,7 @@ MD +4700+02850 Europe/Chisinau
MH +0905+16720 Pacific/Kwajalein Kwajalein
MM,CC +1647+09610 Asia/Yangon
MN +4755+10653 Asia/Ulaanbaatar most of Mongolia
-MN +4801+09139 Asia/Hovd Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan
-MN +4804+11430 Asia/Choibalsan Dornod, Sükhbaatar
+MN +4801+09139 Asia/Hovd Bayan-Ölgii, Hovd, Uvs
MO +221150+1133230 Asia/Macau
MQ +1436-06105 America/Martinique
MT +3554+01431 Europe/Malta
diff --git a/contrib/python/tzdata/tzdata/zoneinfo/zonenow.tab b/contrib/python/tzdata/tzdata/zoneinfo/zonenow.tab
index b6f2910956..01f536b3ba 100644
--- a/contrib/python/tzdata/tzdata/zoneinfo/zonenow.tab
+++ b/contrib/python/tzdata/tzdata/zoneinfo/zonenow.tab
@@ -5,7 +5,7 @@
# From Paul Eggert (2023-12-18):
# This file contains a table where each row stands for a timezone
# where civil timestamps are predicted to agree from now on.
-# This file is like zone1970.tab (see zone1970.tab's coments),
+# This file is like zone1970.tab (see zone1970.tab's comments),
# but with the following changes:
#
# 1. Each timezone corresponds to a set of clocks that are planned
@@ -123,8 +123,6 @@ XX +1455-02331 Atlantic/Cape_Verde Cape Verde
#
# -01/+00 (EU DST)
XX +3744-02540 Atlantic/Azores Azores
-# -01/+00 (EU DST) until 2024-03-31; then -02/-01 (EU DST)
-XX +7029-02158 America/Scoresbysund Ittoqqortoormiit
#
# +00 - GMT
XX +0519-00402 Africa/Abidjan far western Africa; Iceland ("GMT")
@@ -199,7 +197,7 @@ XX +2518+05518 Asia/Dubai Russia; Caucasus; Persian Gulf; Seychelles; Réunion
XX +3431+06912 Asia/Kabul Afghanistan
#
# +05
-XX +4120+06918 Asia/Tashkent Russia; west Kazakhstan; Tajikistan; Turkmenistan; Uzbekistan; Maldives
+XX +4120+06918 Asia/Tashkent Russia; Kazakhstan; Tajikistan; Turkmenistan; Uzbekistan; Maldives
#
# +05 - PKT
XX +2452+06703 Asia/Karachi Pakistan ("PKT")
@@ -215,8 +213,6 @@ XX +2743+08519 Asia/Kathmandu Nepal
#
# +06
XX +2343+09025 Asia/Dhaka Russia; Kyrgyzstan; Bhutan; Bangladesh; Chagos
-# +06 until 2024-03-01; then +05
-XX +4315+07657 Asia/Almaty Kazakhstan (except western areas)
#
# +06:30
XX +1647+09610 Asia/Yangon Myanmar; Cocos
diff --git a/contrib/python/tzdata/tzdata/zones b/contrib/python/tzdata/tzdata/zones
index b054f01012..3c4a951d49 100644
--- a/contrib/python/tzdata/tzdata/zones
+++ b/contrib/python/tzdata/tzdata/zones
@@ -159,7 +159,6 @@ Asia/Barnaul
Asia/Beirut
Asia/Bishkek
Asia/Chita
-Asia/Choibalsan
Asia/Colombo
Asia/Damascus
Asia/Dhaka
@@ -239,11 +238,6 @@ Australia/Lord_Howe
Australia/Melbourne
Australia/Perth
Australia/Sydney
-CET
-CST6CDT
-EET
-EST
-EST5EDT
Etc/GMT
Etc/GMT+1
Etc/GMT+10
@@ -311,14 +305,9 @@ Europe/Volgograd
Europe/Warsaw
Europe/Zurich
Factory
-HST
Indian/Chagos
Indian/Maldives
Indian/Mauritius
-MET
-MST
-MST7MDT
-PST8PDT
Pacific/Apia
Pacific/Auckland
Pacific/Bougainville
@@ -349,7 +338,6 @@ Pacific/Rarotonga
Pacific/Tahiti
Pacific/Tarawa
Pacific/Tongatapu
-WET
GMT
Australia/ACT
Australia/LHI
@@ -365,6 +353,8 @@ Brazil/Acre
Brazil/DeNoronha
Brazil/East
Brazil/West
+CET
+CST6CDT
Canada/Atlantic
Canada/Central
Canada/Eastern
@@ -376,6 +366,9 @@ Canada/Yukon
Chile/Continental
Chile/EasterIsland
Cuba
+EET
+EST
+EST5EDT
Egypt
Eire
Etc/GMT+0
@@ -399,6 +392,9 @@ Jamaica
Japan
Kwajalein
Libya
+MET
+MST
+MST7MDT
Mexico/BajaNorte
Mexico/BajaSur
Mexico/General
@@ -562,6 +558,7 @@ America/Shiprock
America/Thunder_Bay
America/Yellowknife
Antarctica/South_Pole
+Asia/Choibalsan
Asia/Chongqing
Asia/Harbin
Asia/Kashgar
@@ -576,6 +573,7 @@ Europe/Zaporozhye
Pacific/Enderbury
Pacific/Johnston
Pacific/Yap
+WET
Africa/Asmera
America/Godthab
Asia/Ashkhabad
@@ -593,5 +591,7 @@ Asia/Ulan_Bator
Atlantic/Faeroe
Europe/Kiev
Europe/Nicosia
+HST
+PST8PDT
Pacific/Ponape
Pacific/Truk
diff --git a/contrib/python/tzdata/ya.make b/contrib/python/tzdata/ya.make
index d89c71bae8..6fbf62e9d8 100644
--- a/contrib/python/tzdata/ya.make
+++ b/contrib/python/tzdata/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(2024.1)
+VERSION(2024.2)
LICENSE(Apache-2.0)