Files
open-webui/static/pyodide/cycler-0.12.1-py3-none-any.whl

691 lines
23 KiB
Plaintext
Raw Normal View History

2024-05-16 22:54:37 -10:00
PK1RnX' <0C><>EAEAcycler/__init__.py"""
Cycler
======
Cycling through combinations of values, producing dictionaries.
You can add cyclers::
from cycler import cycler
cc = (cycler(color=list('rgb')) +
cycler(linestyle=['-', '--', '-.']))
for d in cc:
print(d)
Results in::
{'color': 'r', 'linestyle': '-'}
{'color': 'g', 'linestyle': '--'}
{'color': 'b', 'linestyle': '-.'}
You can multiply cyclers::
from cycler import cycler
cc = (cycler(color=list('rgb')) *
cycler(linestyle=['-', '--', '-.']))
for d in cc:
print(d)
Results in::
{'color': 'r', 'linestyle': '-'}
{'color': 'r', 'linestyle': '--'}
{'color': 'r', 'linestyle': '-.'}
{'color': 'g', 'linestyle': '-'}
{'color': 'g', 'linestyle': '--'}
{'color': 'g', 'linestyle': '-.'}
{'color': 'b', 'linestyle': '-'}
{'color': 'b', 'linestyle': '--'}
{'color': 'b', 'linestyle': '-.'}
"""
from __future__ import annotations
from collections.abc import Hashable, Iterable, Generator
import copy
from functools import reduce
from itertools import product, cycle
from operator import mul, add
# Dict, List, Union required for runtime cast calls
from typing import TypeVar, Generic, Callable, Union, Dict, List, Any, overload, cast
__version__ = "0.12.1"
K = TypeVar("K", bound=Hashable)
L = TypeVar("L", bound=Hashable)
V = TypeVar("V")
U = TypeVar("U")
def _process_keys(
left: Cycler[K, V] | Iterable[dict[K, V]],
right: Cycler[K, V] | Iterable[dict[K, V]] | None,
) -> set[K]:
"""
Helper function to compose cycler keys.
Parameters
----------
left, right : iterable of dictionaries or None
The cyclers to be composed.
Returns
-------
keys : set
The keys in the composition of the two cyclers.
"""
l_peek: dict[K, V] = next(iter(left)) if left != [] else {}
r_peek: dict[K, V] = next(iter(right)) if right is not None else {}
l_key: set[K] = set(l_peek.keys())
r_key: set[K] = set(r_peek.keys())
if l_key & r_key:
raise ValueError("Can not compose overlapping cycles")
return l_key | r_key
def concat(left: Cycler[K, V], right: Cycler[K, U]) -> Cycler[K, V | U]:
r"""
Concatenate `Cycler`\s, as if chained using `itertools.chain`.
The keys must match exactly.
Examples
--------
>>> num = cycler('a', range(3))
>>> let = cycler('a', 'abc')
>>> num.concat(let)
cycler('a', [0, 1, 2, 'a', 'b', 'c'])
Returns
-------
`Cycler`
The concatenated cycler.
"""
if left.keys != right.keys:
raise ValueError(
"Keys do not match:\n"
"\tIntersection: {both!r}\n"
"\tDisjoint: {just_one!r}".format(
both=left.keys & right.keys, just_one=left.keys ^ right.keys
)
)
_l = cast(Dict[K, List[Union[V, U]]], left.by_key())
_r = cast(Dict[K, List[Union[V, U]]], right.by_key())
return reduce(add, (_cycler(k, _l[k] + _r[k]) for k in left.keys))
class Cycler(Generic[K, V]):
"""
Composable cycles.
This class has compositions methods:
``+``
for 'inner' products (zip)
``+=``
in-place ``+``
``*``
for outer products (`itertools.product`) and integer multiplication
``*=``
in-place ``*``
and supports basic slicing via ``[]``.
Parameters
----------
left, right : Cycler or None
The 'left' and 'right' cyclers.
op : func or None
Function which composes the 'left' and 'right' cyclers.
"""
def __call__(self):
return cycle(self)
def __init__(
self,
left: Cycler[K, V] | Iterable[dict[K, V]] | None,
right: Cycler[K, V] | None = None,
op: Any = None,
):
"""
Semi-private init.
Do not use this directly, use `cycler` function instead.
"""
if isinstance(left, Cycler):
self._left: Cycler[K, V] | list[dict[K, V]] = Cycler(
left._left, left._right, left._op
)
elif left is not None:
# Need to copy the dictionary or else that will be a residual
# mutable that could lead to strange errors
self._left = [copy.copy(v) for v in left]
else:
self._left = []
if isinstance(right, Cycler):
self._right: Cycler[K, V] | None = Cycler(
right._left, right._right, right._op
)
else:
self._right = None
self._keys: set[K] = _process_keys(self._left, self._right)
self._op: Any = op
def __contains__(self, k):
return k in self._keys
@property
def keys(self) -> set[K]:
"""The keys this Cycler knows about."""
return set(self._keys)
def change_key(self, old: K, new: K) -> None:
"""
Change a key in this cycler to a new name.
Modification is performed in-place.
Does nothing if the old key is the same as the new key.
Raises a ValueError if the new key is already a key.
Raises a KeyError if the old key isn't a key.
"""
if old == new:
return
if new in self._keys:
raise ValueError(
f"Can't replace {old} with {new}, {new} is already a key"
)
if old not in self._keys:
raise KeyError(
f"Can't replace {old} with {new}, {old} is not a key"
)
self._keys.remove(old)
self._keys.add(new)
if self._right is not None and old in self._right.keys:
self._right.change_key(old, new)
# self._left should always be non-None
# if self._keys is non-empty.
elif isinstance(self._left, Cycler):
self._left.change_key(old, new)
else:
# It should be completely safe at this point to
# assume that the old key can be found in each
# iteration.
self._left = [{new: entry[old]} for entry in self._left]
@classmethod
def _from_iter(cls, label: K, itr: Iterable[V]) -> Cycler[K, V]:
"""
Class method to create 'base' Cycler objects
that do not have a 'right' or 'op' and for which
the 'left' object is not another Cycler.
Parameters
----------
label : hashable
The property key.
itr : iterable
Finite length iterable of the property values.
Returns
-------
`Cycler`
New 'base' cycler.
"""
ret: Cycler[K, V] = cls(None)
ret._left = list({label: v} for v in itr)
ret._keys = {label}
return ret
def __getitem__(self, key: slice) -> Cycler[K, V]:
# TODO : maybe add numpy style fancy slicing
if isinstance(key, slice):
trans = self.by_key()
return reduce(add, (_cycler(k, v[key]) for k, v in trans.items()))
else:
raise ValueError("Can only use slices with Cycler.__getitem__")
def __iter__(self) -> Generator[dict[K, V], None, None]:
if self._right is None:
for left in self._left:
yield dict(left)
else:
if self._op is None:
raise TypeError(
"Operation cannot be None when both left and right are defined"
)
for a, b in self._op(self._left, self._right):
out = {}
out.update(a)
out.update(b)
yield out
def __add__(self, other: Cycler[L, U]) -> Cycler[K | L, V | U]:
"""
Pair-wise combine two equal length cyclers (zip).
Parameters
----------
other : Cycler
"""
if len(self) != len(other):
raise ValueError(
f"Can only add equal length cycles, not {len(self)} and {len(other)}"
)
return Cycler(
cast(Cycler[Union[K, L], Union[V, U]], self),
cast(Cycler[Union[K, L], Union[V, U]], other),
zip
)
@overload
def __mul__(self, other: Cycler[L, U]) -> Cycler[K | L, V | U]:
...
@overload
def __mul__(self, other: int) -> Cycler[K, V]:
...
def __mul__(self, other):
"""
Outer product of two cyclers (`itertools.product`) or integer
multiplication.
Parameters
----------
other : Cycler or int
"""
if isinstance(other, Cycler):
return Cycler(
cast(Cycler[Union[K, L], Union[V, U]], self),
cast(Cycler[Union[K, L], Union[V, U]], other),
product
)
elif isinstance(other, int):
trans = self.by_key()
return reduce(
add, (_cycler(k, v * other) for k, v in trans.items())
)
else:
return NotImplemented
@overload
def __rmul__(self, other: Cycler[L, U]) -> Cycler[K | L, V | U]:
...
@overload
def __rmul__(self, other: int) -> Cycler[K, V]:
...
def __rmul__(self, other):
return self * other
def __len__(self) -> int:
op_dict: dict[Callable, Callable[[int, int], int]] = {zip: min, product: mul}
if self._right is None:
return len(self._left)
l_len = len(self._left)
r_len = len(self._right)
return op_dict[self._op](l_len, r_len)
# iadd and imul do not exapand the the type as the returns must be consistent with
# self, thus they flag as inconsistent with add/mul
def __iadd__(self, other: Cycler[K, V]) -> Cycler[K, V]: # type: ignore[misc]
"""
In-place pair-wise combine two equal length cyclers (zip).
Parameters
----------
other : Cycler
"""
if not isinstance(other, Cycler):
raise TypeError("Cannot += with a non-Cycler object")
# True shallow copy of self is fine since this is in-place
old_self = copy.copy(self)
self._keys = _process_keys(old_self, other)
self._left = old_self
self._op = zip
self._right = Cycler(other._left, other._right, other._op)
return self
def __imul__(self, other: Cycler[K, V] | int) -> Cycler[K, V]: # type: ignore[misc]
"""
In-place outer product of two cyclers (`itertools.product`).
Parameters
----------
other : Cycler
"""
if not isinstance(other, Cycler):
raise TypeError("Cannot *= with a non-Cycler object")
# True shallow copy of self is fine since this is in-place
old_self = copy.copy(self)
self._keys = _process_keys(old_self, other)
self._left = old_self
self._op = product
self._right = Cycler(other._left, other._right, other._op)
return self
def __eq__(self, other: object) -> bool:
if not isinstance(other, Cycler):
return False
if len(self) != len(other):
return False
if self.keys ^ other.keys:
return False
return all(a == b for a, b in zip(self, other))
__hash__ = None # type: ignore
def __repr__(self) -> str:
op_map = {zip: "+", product: "*"}
if self._right is None:
lab = self.keys.pop()
itr = list(v[lab] for v in self)
return f"cycler({lab!r}, {itr!r})"
else:
op = op_map.get(self._op, "?")
msg = "({left!r} {op} {right!r})"
return msg.format(left=self._left, op=op, right=self._right)
def _repr_html_(self) -> str:
# an table showing the value of each key through a full cycle
output = "<table>"
sorted_keys = sorted(self.keys, key=repr)
for key in sorted_keys:
output += f"<th>{key!r}</th>"
for d in iter(self):
output += "<tr>"
for k in sorted_keys:
output += f"<td>{d[k]!r}</td>"
output += "</tr>"
output += "</table>"
return output
def by_key(self) -> dict[K, list[V]]:
"""
Values by key.
This returns the transposed values of the cycler. Iterating
over a `Cycler` yields dicts with a single value for each key,
this method returns a `dict` of `list` which are the values
for the given key.
The returned value can be used to create an equivalent `Cycler`
using only `+`.
Returns
-------
transpose : dict
dict of lists of the values for each key.
"""
# TODO : sort out if this is a bottle neck, if there is a better way
# and if we care.
keys = self.keys
out: dict[K, list[V]] = {k: list() for k in keys}
for d in self:
for k in keys:
out[k].append(d[k])
return out
# for back compatibility
_transpose = by_key
def simplify(self) -> Cycler[K, V]:
"""
Simplify the cycler into a sum (but no products) of cyclers.
Returns
-------
simple : Cycler
"""
# TODO: sort out if it is worth the effort to make sure this is
# balanced. Currently it is is
# (((a + b) + c) + d) vs
# ((a + b) + (c + d))
# I would believe that there is some performance implications
trans = self.by_key()
return reduce(add, (_cycler(k, v) for k, v in trans.items()))
concat = concat
@overload
def cycler(arg: Cycler[K, V]) -> Cycler[K, V]:
...
@overload
def cycler(**kwargs: Iterable[V]) -> Cycler[str, V]:
...
@overload
def cycler(label: K, itr: Iterable[V]) -> Cycler[K, V]:
...
def cycler(*args, **kwargs):
"""
Create a new `Cycler` object from a single positional argument,
a pair of positional arguments, or the combination of keyword arguments.
cycler(arg)
cycler(label1=itr1[, label2=iter2[, ...]])
cycler(label, itr)
Form 1 simply copies a given `Cycler` object.
Form 2 composes a `Cycler` as an inner product of the
pairs of keyword arguments. In other words, all of the
iterables are cycled simultaneously, as if through zip().
Form 3 creates a `Cycler` from a label and an iterable.
This is useful for when the label cannot be a keyword argument
(e.g., an integer or a name that has a space in it).
Parameters
----------
arg : Cycler
Copy constructor for Cycler (does a shallow copy of iterables).
label : name
The property key. In the 2-arg form of the function,
the label can be any hashable object. In the keyword argument
form of the function, it must be a valid python identifier.
itr : iterable
Finite length iterable of the property values.
Can be a single-property `Cycler` that would
be like a key change, but as a shallow copy.
Returns
-------
cycler : Cycler
New `Cycler` for the given property
"""
if args and kwargs:
raise TypeError(
"cycler() can only accept positional OR keyword arguments -- not both."
)
if len(args) == 1:
if not isinstance(args[0], Cycler):
raise TypeError(
"If only one positional argument given, it must "
"be a Cycler instance."
)
return Cycler(args[0])
elif len(args) == 2:
return _cycler(*args)
elif len(args) > 2:
raise TypeError(
"Only a single Cycler can be accepted as the lone "
"positional argument. Use keyword arguments instead."
)
if kwargs:
return reduce(add, (_cycler(k, v) for k, v in kwargs.items()))
raise TypeError("Must have at least a positional OR keyword arguments")
def _cycler(label: K, itr: Iterable[V]) -> Cycler[K, V]:
"""
Create a new `Cycler` object from a property name and iterable of values.
Parameters
----------
label : hashable
The property key.
itr : iterable
Finite length iterable of the property values.
Returns
-------
cycler : Cycler
New `Cycler` for the given property
"""
if isinstance(itr, Cycler):
keys = itr.keys
if len(keys) != 1:
msg = "Can not create Cycler from a multi-property Cycler"
raise ValueError(msg)
lab = keys.pop()
# Doesn't need to be a new list because
# _from_iter() will be creating that new list anyway.
itr = (v[lab] for v in itr)
return Cycler._from_iter(label, itr)
PK1RnXcycler/py.typedPK1RnXZ+<2B><><EFBFBD><00>cycler-0.12.1.dist-info/LICENSECopyright (c) 2015, matplotlib project
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the matplotlib project nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.PK1RnX<6E><58><EFBFBD><EFBFBD><EFBFBD><00> cycler-0.12.1.dist-info/METADATAMetadata-Version: 2.1
Name: cycler
Version: 0.12.1
Summary: Composable style cycles
Author-email: Thomas A Caswell <matplotlib-users@python.org>
License: Copyright (c) 2015, matplotlib project
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the matplotlib project nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Project-URL: homepage, https://matplotlib.org/cycler/
Project-URL: repository, https://github.com/matplotlib/cycler
Keywords: cycle kwargs
Classifier: License :: OSI Approved :: BSD License
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.8
Description-Content-Type: text/x-rst
License-File: LICENSE
Provides-Extra: docs
Requires-Dist: ipython ; extra == 'docs'
Requires-Dist: matplotlib ; extra == 'docs'
Requires-Dist: numpydoc ; extra == 'docs'
Requires-Dist: sphinx ; extra == 'docs'
Provides-Extra: tests
Requires-Dist: pytest ; extra == 'tests'
Requires-Dist: pytest-cov ; extra == 'tests'
Requires-Dist: pytest-xdist ; extra == 'tests'
|PyPi|_ |Conda|_ |Supported Python versions|_ |GitHub Actions|_ |Codecov|_
.. |PyPi| image:: https://img.shields.io/pypi/v/cycler.svg?style=flat
.. _PyPi: https://pypi.python.org/pypi/cycler
.. |Conda| image:: https://img.shields.io/conda/v/conda-forge/cycler
.. _Conda: https://anaconda.org/conda-forge/cycler
.. |Supported Python versions| image:: https://img.shields.io/pypi/pyversions/cycler.svg
.. _Supported Python versions: https://pypi.python.org/pypi/cycler
.. |GitHub Actions| image:: https://github.com/matplotlib/cycler/actions/workflows/tests.yml/badge.svg
.. _GitHub Actions: https://github.com/matplotlib/cycler/actions
.. |Codecov| image:: https://codecov.io/github/matplotlib/cycler/badge.svg?branch=main&service=github
.. _Codecov: https://codecov.io/github/matplotlib/cycler?branch=main
cycler: composable cycles
=========================
Docs: https://matplotlib.org/cycler/
PK1RnXI<><49>\\cycler-0.12.1.dist-info/WHEELWheel-Version: 1.0
Generator: bdist_wheel (0.41.2)
Root-Is-Purelib: true
Tag: py3-none-any
PK1RnX<6E>k<EFBFBD>%cycler-0.12.1.dist-info/top_level.txtcycler
PK1RnX<6E><58><1A>cycler-0.12.1.dist-info/RECORDcycler/__init__.py,sha256=1JdRgv5Zzxo-W1ev7B_LWquysWP6LZH6CHk_COtIaXE,16709
cycler/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
cycler-0.12.1.dist-info/LICENSE,sha256=8SGBQ9dm2j_qZvEzlrfxXfRqgzA_Kb-Wum6Y601C9Ag,1497
cycler-0.12.1.dist-info/METADATA,sha256=IyieGbdvHgE5Qidpbmryts0c556JcxIJv5GVFIsY7TY,3779
cycler-0.12.1.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
cycler-0.12.1.dist-info/top_level.txt,sha256=D8BVVDdAAelLb2FOEz7lDpc6-AL21ylKPrMhtG6yzyE,7
cycler-0.12.1.dist-info/RECORD,,
PK1RnX' <0C><>EAEA<00>cycler/__init__.pyPK1RnX<00>uAcycler/py.typedPK1RnXZ+<2B><><EFBFBD><00><00><01>Acycler-0.12.1.dist-info/LICENSEPK1RnX<6E><58><EFBFBD><EFBFBD><EFBFBD><00> <00><01>Gcycler-0.12.1.dist-info/METADATAPK1RnXI<><49>\\<00><01>Vcycler-0.12.1.dist-info/WHEELPK1RnX<6E>k<EFBFBD>%<00>PWcycler-0.12.1.dist-info/top_level.txtPK1RnX<6E><58><1A><00><01>Wcycler-0.12.1.dist-info/RECORDPK<00>Y