Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-mizani for openSUSE:Factory checked in at 2026-10-26 10:01:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-mizani (Old) and /work/SRC/openSUSE:Factory/.python-mizani.new.2252680 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-mizani" Mon Oct 26 10:01:20 2026 rev:12 rq:1392485 version:0.14.6 Changes: -------- --- /work/SRC/openSUSE:Factory/python-mizani/python-mizani.changes 2026-03-16 14:20:16.588627045 +0100 +++ /work/SRC/openSUSE:Factory/.python-mizani.new.2252680/python-mizani.changes 2026-10-26 10:02:51.029880739 +0100 @@ -1,0 +2,15 @@ +Sun Oct 25 16:32:09 UTC 2026 - Dirk Müller <[email protected]> + +- update to 0.14.6: + * :class:`~mizani.breaks.breaks_extended` accepts a pair for + only_inside, one flag per end, so a break sequence can be + held inside the limits at one end and allowed past them at + the other. + * :func:`~mizani.palettes.brewer_pal` now resolves a named + palette to its own type, so the name no longer has to match + the type argument. brewer_pal(palette="Set2") now works even + though type defaults to sequential and Set2 is qualitative. + An unknown name raises a ValueError listing the valid names. + This resolves (plotnine #1048). + +------------------------------------------------------------------- Old: ---- mizani-0.14.4.tar.gz New: ---- mizani-0.14.6.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-mizani.spec ++++++ --- /var/tmp/diff_new_pack.NTBSG2/_old 2026-10-26 10:02:52.330935301 +0100 +++ /var/tmp/diff_new_pack.NTBSG2/_new 2026-10-26 10:02:52.334935469 +0100 @@ -17,7 +17,7 @@ Name: python-mizani -Version: 0.14.4 +Version: 0.14.6 Release: 0 Summary: Scales for Python License: BSD-3-Clause ++++++ mizani-0.14.4.tar.gz -> mizani-0.14.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/.gitignore new/mizani-0.14.6/.gitignore --- old/mizani-0.14.4/.gitignore 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/.gitignore 2026-09-07 18:14:10.312042500 +0200 @@ -23,6 +23,14 @@ *.egg-info/ .installed.cfg *.egg +__pypackages__/ +node_modules/ + +# Environments +.direnv +.venv +venv +uv.lock # PyInstaller # Usually these files are written by a python script from a template diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/.pre-commit-config.yaml new/mizani-0.14.6/.pre-commit-config.yaml --- old/mizani-0.14.4/.pre-commit-config.yaml 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/.pre-commit-config.yaml 2026-09-07 18:14:10.312042500 +0200 @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.14 + rev: v0.16.6 hooks: - id: ruff args: [--select=I001, --fix] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/PKG-INFO new/mizani-0.14.6/PKG-INFO --- old/mizani-0.14.4/PKG-INFO 2026-01-28 15:42:01.085750600 +0100 +++ new/mizani-0.14.6/PKG-INFO 2026-09-07 18:14:20.825758200 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: mizani -Version: 0.14.4 +Version: 0.14.6 Summary: Scales for Python Author-email: Hassan Kibirige <[email protected]> License: Copyright (c) 2016, Hassan Kibirige @@ -73,7 +73,7 @@ Requires-Dist: pre-commit; extra == "dev" Requires-Dist: mizani[typing]; extra == "dev" Provides-Extra: typing -Requires-Dist: pyright==1.1.408; extra == "typing" +Requires-Dist: pyright==1.1.411; extra == "typing" Requires-Dist: pandas-stubs; extra == "typing" Dynamic: license-file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/doc/changelog.rst new/mizani-0.14.6/doc/changelog.rst --- old/mizani-0.14.4/doc/changelog.rst 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/doc/changelog.rst 2026-09-07 18:14:10.312504800 +0200 @@ -1,6 +1,35 @@ Changelog ========= +v0.14.6 +------- + +2026-09-07 + +Enhancements +************ + +- :class:`~mizani.breaks.breaks_extended` accepts a pair for + ``only_inside``, one flag per end, so a break sequence can be held + inside the limits at one end and allowed past them at the other. + + +v0.14.5 +------- + +2026-09-04 + +Bug Fixes +********* + +- :func:`~mizani.palettes.brewer_pal` now resolves a named palette to its own + type, so the name no longer has to match the ``type`` argument. + ``brewer_pal(palette="Set2")`` now works even though ``type`` defaults to + sequential and ``Set2`` is qualitative. An unknown name raises a + ``ValueError`` listing the valid names. This resolves `(plotnine #1048) + <https://github.com/has2k1/plotnine/issues/1048>`_. + + v0.14.4 ------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani/_colors/_palettes/brewer/__init__.py new/mizani-0.14.6/mizani/_colors/_palettes/brewer/__init__.py --- old/mizani-0.14.4/mizani/_colors/_palettes/brewer/__init__.py 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/mizani/_colors/_palettes/brewer/__init__.py 2026-09-07 18:14:10.316721700 +0200 @@ -1,5 +1,6 @@ from __future__ import annotations +from functools import cache from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -36,7 +37,42 @@ return diverging else: - raise ValueError(f"Unknown type of brewer palette: {type}") + raise ValueError(f"Unknown type of brewer palette: {scheme}") + + +@cache +def _palette_schemes() -> dict[str, ColorScheme]: + """ + Return every brewer palette's scheme, keyed by palette name + + Palette names are unique across schemes, so each name identifies one + scheme. + """ + schemes: tuple[ColorScheme, ...] = ( + "sequential", + "qualitative", + "diverging", + ) + return { + name: scheme + for scheme in schemes + for name in get_palette_names(scheme) + } + + +def get_palette_scheme(name: str) -> ColorScheme: + """ + Return the scheme for a named palette + + Raise a `ValueError` if the name is not a brewer palette. + """ + lookup = _palette_schemes() + if name not in lookup: + raise ValueError( + f"Unknown brewer palette: '{name}'. The valid names are " + f"{sorted(lookup)}." + ) + return lookup[name] def number_to_name(scheme: ColorScheme | ColorSchemeShort, n: int) -> str: @@ -49,7 +85,7 @@ names = mod.__all__ if n > len(names): raise ValueError( - f"There are only '{n}' palettes of type {scheme}. " + f"There are only '{len(names)}' palettes of type {scheme}. " f"You requested palette no. {n}" ) return names[n - 1] @@ -60,8 +96,13 @@ ) -> ColorPalette: """ Return color palette from a given scheme + + The scheme selects a palette given by number. A palette given by name + belongs to one scheme only, so the name overrides `scheme`. """ if isinstance(palette, int): palette = number_to_name(scheme, palette) + else: + scheme = get_palette_scheme(palette) mod = get_palette_module(scheme) return getattr(mod, palette) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani/_datetime/utils.py new/mizani-0.14.6/mizani/_datetime/utils.py --- old/mizani-0.14.4/mizani/_datetime/utils.py 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/mizani/_datetime/utils.py 2026-09-07 18:14:10.317370200 +0200 @@ -29,7 +29,6 @@ SECONDS_PER_DAY = 24 * 60 * 60 MICROSECONDS_PER_DAY = SECONDS_PER_DAY * (10**6) -NaT_int = np.datetime64("NaT").astype(np.int64) MIN_DATETIME64 = np.datetime64("0001-01-01") MAX_DATETIME64 = np.datetime64("10000-01-01") UTC = ZoneInfo("UTC") @@ -162,8 +161,7 @@ + diff_ns.astype(np.float64) / 1.0e9 ) / SECONDS_PER_DAY - x_int = x.astype(np.int64) - res[x_int == NaT_int] = np.nan + res[np.isnat(x)] = np.nan return res diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani/breaks.py new/mizani-0.14.6/mizani/breaks.py --- old/mizani-0.14.4/mizani/breaks.py 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/mizani/breaks.py 2026-09-07 18:14:10.317621000 +0200 @@ -193,13 +193,13 @@ lower_end = np.max( [ np.min(np.where(limits[0] <= breaks)) - 1, - 0, # type: ignore + 0, ] ) upper_end = np.min( [ np.max(np.where(breaks <= limits[1])) + 1, - len(breaks), # type: ignore + len(breaks), ] ) return breaks[lower_end : upper_end + 1] @@ -655,9 +655,14 @@ Desired number of breaks Q : list List of nice numbers - only_inside : bool + only_inside : bool | tuple[bool, bool] If ``True``, then all the breaks will be within the given - range. + range. A pair ``(lower, upper)`` constrains each end on its + own, so ``(True, False)`` keeps the first break at or above + the lower limit while the last break may lie beyond the + upper limit. The coverage score treats the two ends + separately (Talbot et al., 2010), so the search is unchanged; + only the candidates it admits are. w : list Weights applied to the four optimization components (simplicity, coverage, density, and legibility). They @@ -670,6 +675,8 @@ array([ 0. , 2.5, 5. , 7.5, 10. ]) >>> breaks_extended(n=6)(limits) array([ 0., 2., 4., 6., 8., 10.]) + >>> breaks_extended(n=3, only_inside=(True, False))((-7.7, 196.9)) + array([ 0., 100., 200.]) References ---------- @@ -683,12 +690,16 @@ n: int = 5 Q: Sequence[float] = (1, 5, 2, 2.5, 4, 3) - only_inside: bool = False + only_inside: bool | tuple[bool, bool] = False w: Sequence[float] = (0.25, 0.2, 0.5, 0.05) def __post_init__(self): # Used for lookups during the computations self.Q_index = {q: i for i, q in enumerate(self.Q)} + if isinstance(self.only_inside, bool): + self._inside = (self.only_inside, self.only_inside) + else: + self._inside = tuple(self.only_inside) def coverage( self, dmin: float, dmax: float, lmin: float, lmax: float @@ -764,7 +775,7 @@ """ Q = self.Q w = self.w - only_inside = self.only_inside + inside_lower, inside_upper = self._inside simplicity_max = self.simplicity_max density_max = self.density_max coverage_max = self.coverage_max @@ -835,9 +846,10 @@ score = w[0] * s + w[1] * c + w[2] * d + w[3] * l - if score > best_score and ( - not only_inside - or (lmin >= dmin and lmax <= dmax) + if ( + score > best_score + and (not inside_lower or lmin >= dmin) + and (not inside_upper or lmax <= dmax) ): best_score = score best = (lmin, lmax, lstep, q, k) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani/palettes.py new/mizani-0.14.6/mizani/palettes.py --- old/mizani-0.14.4/mizani/palettes.py 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/mizani/palettes.py 2026-09-07 18:14:10.317621000 +0200 @@ -18,7 +18,7 @@ import colorsys from dataclasses import dataclass -from typing import TYPE_CHECKING, Protocol +from typing import TYPE_CHECKING, Protocol, cast from warnings import warn import numpy as np @@ -477,15 +477,14 @@ Parameters ---------- type : 'sequential' | 'qualitative' | 'diverging' - Type of palette. Sequential, Qualitative or - Diverging. The following abbreviations may - be used, ``seq``, ``qual`` or ``div``. + Type from which to choose a numeric `palette`. The abbreviations + `seq`, `qual`, and `div` are supported. A named palette selects its + own type, and `type` becomes its long form, such as `'qualitative'`. palette : int | str - Which palette to choose from. If is an integer, - it must be in the range ``[0, m]``, where ``m`` - depends on the number sequential, qualitative or - diverging palettes. If it is a string, then it - is the name of the palette. + Palette to choose. An integer must be in the range `[0, m]`, where + `m` depends on the number of sequential, qualitative, or diverging + palettes. A string must be a palette name; an unknown name raises a + `ValueError`. direction : int The order of colours in the scale. If -1 the order of colors is reversed. The default is 1. @@ -509,10 +508,18 @@ >>> brewer_pal('seq', 'PuBuGn')(5) ['#F6EFF7', '#BDC9E1', '#67A9CF', '#1C9099', '#016C59'] + A named palette does not need a matching `type`. + + >>> pal = brewer_pal(palette='Set2') + >>> pal(3) + ['#66C2A5', '#FC8D62', '#8DA0CB'] + >>> pal.type + 'qualitative' + The available color names for each palette type can be obtained using the following code:: - from mizani._colors.brewer import get_palette_names + from mizani._colors._palettes.brewer import get_palette_names print(get_palette_names("sequential")) print(get_palette_names("qualitative")) @@ -530,6 +537,7 @@ raise ValueError("direction should be 1 or -1.") self.bpal = get_brewer_palette(self.type, self.palette) + self.type = cast("ColorScheme", self.bpal.kind.value) def __call__(self, n: int) -> Sequence[RGBHexColor | None]: # Only draw the maximum allowable colors from the palette diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani/scale.py new/mizani-0.14.6/mizani/scale.py --- old/mizani-0.14.4/mizani/scale.py 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/mizani/scale.py 2026-09-07 18:14:10.317621000 +0200 @@ -54,6 +54,7 @@ ContinuousPalette, DiscretePalette, FloatArrayLike, + NDArrayAny, NDArrayFloat, Trans, ) @@ -76,7 +77,7 @@ palette: ContinuousPalette, na_value: Any = None, trans: Trans | None = None, - ) -> NDArrayFloat: + ) -> NDArrayAny: """ Scale data continuously @@ -144,7 +145,7 @@ limits: tuple[float, float], na_value: Any = None, oob: Callable[[TVector], TVector] = censor, - ) -> NDArrayFloat: + ) -> NDArrayAny: """ Map values to a continuous palette diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani/typing.py new/mizani-0.14.6/mizani/typing.py --- old/mizani-0.14.4/mizani/typing.py 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/mizani/typing.py 2026-09-07 18:14:10.317706300 +0200 @@ -163,7 +163,9 @@ ) TimedeltaOffset: TypeAlias = timedelta | str | Sequence[str] | None - ContinuousPalette: TypeAlias = Callable[[FloatArrayLike], Sequence[Any]] + ContinuousPalette: TypeAlias = Callable[ + [FloatArrayLike], NDArrayAny | Sequence[Any] + ] DiscretePalette: TypeAlias = Callable[[int], NDArrayAny | AnySeries] # Mizani diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani.egg-info/PKG-INFO new/mizani-0.14.6/mizani.egg-info/PKG-INFO --- old/mizani-0.14.4/mizani.egg-info/PKG-INFO 2026-01-28 15:42:01.000000000 +0100 +++ new/mizani-0.14.6/mizani.egg-info/PKG-INFO 2026-09-07 18:14:20.781757800 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: mizani -Version: 0.14.4 +Version: 0.14.6 Summary: Scales for Python Author-email: Hassan Kibirige <[email protected]> License: Copyright (c) 2016, Hassan Kibirige @@ -73,7 +73,7 @@ Requires-Dist: pre-commit; extra == "dev" Requires-Dist: mizani[typing]; extra == "dev" Provides-Extra: typing -Requires-Dist: pyright==1.1.408; extra == "typing" +Requires-Dist: pyright==1.1.411; extra == "typing" Requires-Dist: pandas-stubs; extra == "typing" Dynamic: license-file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani.egg-info/SOURCES.txt new/mizani-0.14.6/mizani.egg-info/SOURCES.txt --- old/mizani-0.14.4/mizani.egg-info/SOURCES.txt 2026-01-28 15:42:01.000000000 +0100 +++ new/mizani-0.14.6/mizani.egg-info/SOURCES.txt 2026-09-07 18:14:20.800408000 +0200 @@ -63,6 +63,8 @@ mizani.egg-info/SOURCES.txt mizani.egg-info/dependency_links.txt mizani.egg-info/requires.txt +mizani.egg-info/scm_file_list.json +mizani.egg-info/scm_version.json mizani.egg-info/top_level.txt mizani/_colors/__init__.py mizani/_colors/_named_color_values.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani.egg-info/requires.txt new/mizani-0.14.6/mizani.egg-info/requires.txt --- old/mizani-0.14.4/mizani.egg-info/requires.txt 2026-01-28 15:42:01.000000000 +0100 +++ new/mizani-0.14.6/mizani.egg-info/requires.txt 2026-09-07 18:14:20.784434800 +0200 @@ -36,5 +36,5 @@ pytest-cov>=4.0.0 [typing] -pyright==1.1.408 +pyright==1.1.411 pandas-stubs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani.egg-info/scm_file_list.json new/mizani-0.14.6/mizani.egg-info/scm_file_list.json --- old/mizani-0.14.4/mizani.egg-info/scm_file_list.json 1970-01-01 01:00:00.000000000 +0100 +++ new/mizani-0.14.6/mizani.egg-info/scm_file_list.json 2026-09-07 18:14:20.780415800 +0200 @@ -0,0 +1,130 @@ +{ + "files": [ + ".gitattributes", + ".github/workflows/release.yml", + ".github/workflows/testing.yml", + ".gitignore", + ".pre-commit-config.yaml", + ".readthedocs.yaml", + "LICENSE", + "Makefile", + "README.md", + "codecov.yml", + "doc/Makefile", + "doc/_static/copybutton.js", + "doc/_static/custom.css", + "doc/bounds.rst", + "doc/breaks.rst", + "doc/changelog.rst", + "doc/conf.py", + "doc/docutils.conf", + "doc/index.rst", + "doc/installation.rst", + "doc/labels.rst", + "doc/palettes.rst", + "doc/scale.rst", + "doc/sphinxext/__init__.py", + "doc/sphinxext/inline_code_highlight.py", + "doc/theme/globaltoc.html", + "doc/theme/layout.html", + "doc/theme/localtoc.html", + "doc/theme/navbar-2.html", + "doc/theme/navbar.html", + "doc/theme/navbarsearchbox.html", + "doc/theme/navbartoc.html", + "doc/theme/relations.html", + "doc/theme/search.html", + "doc/theme/searchbox.html", + "doc/theme/searchresults.html", + "doc/theme/sourcelink.html", + "doc/theme/static/bootstrap-3.4.1/css/bootstrap.min.css", + "doc/theme/static/bootstrap-3.4.1/js/bootstrap.min.js", + "doc/theme/static/bootstrap-sphinx.css_t", + "doc/theme/static/bootstrap-sphinx.js_t", + "doc/theme/static/js/jquery-1.12.4.min.js", + "doc/theme/static/js/jquery-fix.js", + "doc/theme/theme.conf", + "doc/transforms.rst", + "licences/HUSL_LICENSE", + "licences/SCALES_LICENSE", + "licences/SEABORN_LICENSE", + "licences/SIX_LICENSE", + "mizani/__init__.py", + "mizani/_colors/__init__.py", + "mizani/_colors/_colormaps/__init__.py", + "mizani/_colors/_colormaps/_colormap.py", + "mizani/_colors/_colormaps/_cubehelix.py", + "mizani/_colors/_colormaps/_interpolated.py", + "mizani/_colors/_colormaps/_listed.py", + "mizani/_colors/_colormaps/_maps/__init__.py", + "mizani/_colors/_colormaps/_maps/_interpolated.py", + "mizani/_colors/_colormaps/_maps/_listed.py", + "mizani/_colors/_colormaps/_maps/_palette_interpolated.py", + "mizani/_colors/_colormaps/_maps/_segment_function.py", + "mizani/_colors/_colormaps/_maps/_segment_interpolated.py", + "mizani/_colors/_colormaps/_palette_interpolated.py", + "mizani/_colors/_colormaps/_segment_function.py", + "mizani/_colors/_colormaps/_segment_interpolated.py", + "mizani/_colors/_named_color_values.py", + "mizani/_colors/_palettes/__init__.py", + "mizani/_colors/_palettes/_palette.py", + "mizani/_colors/_palettes/brewer/__init__.py", + "mizani/_colors/_palettes/brewer/diverging.py", + "mizani/_colors/_palettes/brewer/qualitative.py", + "mizani/_colors/_palettes/brewer/sequential.py", + "mizani/_colors/_palettes/other/__init__.py", + "mizani/_colors/_palettes/other/qualitative.py", + "mizani/_colors/hsluv.py", + "mizani/_colors/named_colors.py", + "mizani/_colors/utils.py", + "mizani/_datetime/__init__.py", + "mizani/_datetime/breaks.py", + "mizani/_datetime/rounding.py", + "mizani/_datetime/types.py", + "mizani/_datetime/utils.py", + "mizani/_timedelta/__init__.py", + "mizani/_timedelta/breaks.py", + "mizani/_timedelta/utils.py", + "mizani/bounds.py", + "mizani/breaks.py", + "mizani/formatters.py", + "mizani/labels.py", + "mizani/palettes.py", + "mizani/py.typed", + "mizani/scale.py", + "mizani/transforms.py", + "mizani/typing.py", + "mizani/utils.py", + "pyproject.toml", + "tests/__init__.py", + "tests/colors/__init__.py", + "tests/colors/data/hsluv-snapshot-rev4.json", + "tests/colors/test_cubehelix.py", + "tests/colors/test_hsluv.py", + "tests/colors/test_interpolated.py", + "tests/colors/test_listed.py", + "tests/colors/test_named_colors.py", + "tests/colors/test_segment_function.py", + "tests/colors/test_utils.py", + "tests/conftest.py", + "tests/datetime/__init__.py", + "tests/datetime/test_breaks.py", + "tests/datetime/test_rounding.py", + "tests/datetime/test_utils.py", + "tests/test_bounds.py", + "tests/test_breaks.py", + "tests/test_labels.py", + "tests/test_palettes.py", + "tests/test_scale.py", + "tests/test_transforms.py", + "tests/test_utils.py", + "tests/timedelta/__init__.py", + "tests/timedelta/test_breaks.py", + "tests/timedelta/test_utils.py", + "tools/build_theme.sh", + "tools/gha_check_semver.py", + "tools/release-checklist-tpl.md", + "tools/release-checklist.py", + "tools/term.py" + ] +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/mizani.egg-info/scm_version.json new/mizani-0.14.6/mizani.egg-info/scm_version.json --- old/mizani-0.14.4/mizani.egg-info/scm_version.json 1970-01-01 01:00:00.000000000 +0100 +++ new/mizani-0.14.6/mizani.egg-info/scm_version.json 2026-09-07 18:14:20.768881300 +0200 @@ -0,0 +1,8 @@ +{ + "tag": "0.14.6", + "distance": 0, + "node": "ga056fe2c8649a2c8ffd09430952e69137f5ae3b5", + "dirty": false, + "branch": "HEAD", + "node_date": "2026-09-07" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/pyproject.toml new/mizani-0.14.6/pyproject.toml --- old/mizani-0.14.4/pyproject.toml 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/pyproject.toml 2026-09-07 18:14:10.317706300 +0200 @@ -65,7 +65,7 @@ ] typing = [ - "pyright==1.1.408", + "pyright==1.1.411", "pandas-stubs", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/tests/datetime/test_utils.py new/mizani-0.14.6/tests/datetime/test_utils.py --- old/mizani-0.14.4/tests/datetime/test_utils.py 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/tests/datetime/test_utils.py 2026-09-07 18:14:10.325093500 +0200 @@ -27,6 +27,13 @@ assert len(datetime_to_num([])) == 0 +def test_datetime_to_num_handles_nat(): + result = datetime_to_num( + np.array(["2020-01-01", "NaT"], dtype="datetime64[ns]") + ) + assert np.isnan(result[1]) + + def test_num_to_datetime(): limits = num_to_datetime((25552, 27743)) assert limits[0] == datetime(2039, 12, 17, tzinfo=ZoneInfo("UTC")) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/tests/test_breaks.py new/mizani-0.14.6/tests/test_breaks.py --- old/mizani-0.14.4/tests/test_breaks.py 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/tests/test_breaks.py 2026-09-07 18:14:10.325093500 +0200 @@ -438,3 +438,32 @@ limits = [np.pi, np.pi] assert len(breaks(limits)) == 1 assert breaks(limits)[0] == limits[1] + + +def test_breaks_extended_only_inside_per_end(): + limits = (-7.7, 196.9) + + # A pair of equal flags is the same as the single flag + for flag in (True, False): + npt.assert_array_equal( + breaks_extended(n=3, only_inside=(flag, flag))(limits), + breaks_extended(n=3, only_inside=flag)(limits), + ) + + # Each end honours its own flag: the constrained end stays inside, + # the free end may go past its limit + breaks = breaks_extended(n=3, only_inside=(True, False))(limits) + npt.assert_array_equal(breaks, [0, 100, 200]) + breaks = breaks_extended(n=3, only_inside=(False, True))((3.1, 207.7)) + npt.assert_array_equal(breaks, [0, 100, 200]) + + # Over many ranges the constrained end never crosses its limit + rng = np.random.default_rng(0) + for _ in range(200): + lo = rng.uniform(-50, 50) + hi = lo + 10 ** rng.uniform(-1, 3) + n = int(rng.integers(2, 9)) + breaks = breaks_extended(n=n, only_inside=(True, False))((lo, hi)) + assert breaks[0] >= lo + breaks = breaks_extended(n=n, only_inside=(False, True))((lo, hi)) + assert breaks[-1] <= hi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.14.4/tests/test_palettes.py new/mizani-0.14.6/tests/test_palettes.py --- old/mizani-0.14.4/tests/test_palettes.py 2026-01-28 15:41:52.000000000 +0100 +++ new/mizani-0.14.6/tests/test_palettes.py 2026-09-07 18:14:10.325093500 +0200 @@ -135,6 +135,28 @@ brewer_pal(direction=-2)(100) +def test_brewer_pal_named_palette_selects_its_type(): + # A unique name identifies the palette type and overrides the default or + # explicitly supplied type. + result = brewer_pal(palette="Set2")(3) + assert all(s[0] == "#" and len(s) == 7 for s in result) + + result = brewer_pal("div", "Blues")(3) + assert all(s[0] == "#" and len(s) == 7 for s in result) + + assert brewer_pal(palette="Set2").type == "qualitative" + assert brewer_pal("div", "Blues").type == "sequential" + + with pytest.raises(ValueError, match="Nonesuch"): + brewer_pal(palette="Nonesuch") + + +def test_brewer_pal_number_out_of_range(): + # Report the number of available palettes, not the requested number. + with pytest.raises(ValueError, match="only '8' palettes of type qual"): + brewer_pal("qual", 20) + + def test_brewer_palette_names(): from mizani._colors._palettes.brewer import get_palette_names
