Added github integration

This commit is contained in:
2025-12-02 14:32:10 +00:00
parent b6dd8b8fe2
commit 4076c4bf83
762 changed files with 193089 additions and 2 deletions

View File

@@ -0,0 +1,325 @@
import enum
from ._version import get_versions
from ._name_mangler import _NameMangler
__version__ = get_versions()["version"]
__version_info__ = tuple(int(n) for n in __version__.partition("+")[0].split("."))
del get_versions
_name_mangler = _NameMangler()
# The first argument to the `_generate_next_value_` function of the `enum.Enum`
# class is documented to be the name of the enum member, not the enum class:
#
# https://docs.python.org/3.6/library/enum.html#using-automatic-values
#
# Pylint, though, doesn't know about this so we need to disable it's check for
# `self` arguments.
# pylint: disable=no-self-argument
class StrEnum(str, enum.Enum):
"""
StrEnum is a Python ``enum.Enum`` that inherits from ``str``. The default
``auto()`` behavior uses the member name as its value.
Example usage::
class Example(StrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "UPPER_CASE"
assert Example.lower_case == "lower_case"
assert Example.MixedCase == "MixedCase"
"""
def __new__(cls, value, *args, **kwargs):
if not isinstance(value, (str, enum.auto)):
raise TypeError(
f"Values of StrEnums must be strings: {value!r} is a {type(value)}"
)
return super().__new__(cls, value, *args, **kwargs)
def __str__(self):
return str(self.value)
def _generate_next_value_(name, *_):
return name
class LowercaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `lowercase` to
produce each member's value.
Example usage::
class Example(LowercaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "upper_case"
assert Example.lower_case == "lower_case"
assert Example.MixedCase == "mixedcase"
.. versionadded:: 0.4.3
"""
def _generate_next_value_(name, *_):
return name.lower()
class UppercaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `UPPERCASE` to
produce each member's value.
Example usage::
class Example(UppercaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "UPPER_CASE"
assert Example.lower_case == "LOWER_CASE"
assert Example.MixedCase == "MIXEDCASE"
.. versionadded:: 0.4.3
"""
def _generate_next_value_(name, *_):
return name.upper()
class CamelCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `camelCase` to
produce each member's value.
Example usage::
class Example(CamelCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "upperCase"
assert Example.lower_case == "lowerCase"
assert Example.MixedCase == "mixedCase"
.. versionadded:: 0.4.5
"""
def _generate_next_value_(name, *_):
return _name_mangler.camel(name)
class PascalCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `PascalCase` to
produce each member's value.
Example usage::
class Example(PascalCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "UpperCase"
assert Example.lower_case == "LowerCase"
assert Example.MixedCase == "MixedCase"
.. versionadded:: 0.4.5
"""
def _generate_next_value_(name, *_):
return _name_mangler.pascal(name)
class KebabCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `kebab-case` to
produce each member's value.
Example usage::
class Example(KebabCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "upper-case"
assert Example.lower_case == "lower-case"
assert Example.MixedCase == "mixed-case"
.. versionadded:: 0.4.5
"""
def _generate_next_value_(name, *_):
return _name_mangler.kebab(name)
class SnakeCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `snake_case` to
produce each member's value.
Example usage::
class Example(SnakeCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "upper_case"
assert Example.lower_case == "lower_case"
assert Example.MixedCase == "mixed_case"
.. versionadded:: 0.4.5
"""
def _generate_next_value_(name, *_):
return _name_mangler.snake(name)
class MacroCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `MACRO_CASE` to
produce each member's value.
Example usage::
class Example(MacroCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "UPPER_CASE"
assert Example.lower_case == "LOWER_CASE"
assert Example.MixedCase == "MIXED_CASE"
.. versionadded:: 0.4.6
"""
def _generate_next_value_(name, *_):
return _name_mangler.macro(name)
class CamelSnakeCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `camel_Snake_Case` to
produce each member's value.
Example usage::
class Example(CamelSnakeCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "upper_Case"
assert Example.lower_case == "lower_Case"
assert Example.MixedCase == "mixed_Case"
.. versionadded:: 0.4.8
"""
def _generate_next_value_(name, *_):
return _name_mangler.camel_snake(name)
class PascalSnakeCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `Pascal_Snake_Case` to
produce each member's value.
Example usage::
class Example(PascalSnakeCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "Upper_Case"
assert Example.lower_case == "Lower_Case"
assert Example.MixedCase == "Mixed_Case"
.. versionadded:: 0.4.8
"""
def _generate_next_value_(name, *_):
return _name_mangler.pascal_snake(name)
class SpongebobCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `SpONGEBob_CAse` to
produce each member's value.
Example usage::
class Example(SpongebobCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "uPpER_cAsE"
assert Example.lower_case == "lowER_CASe"
assert Example.MixedCase == "MixeD_CAse"
.. versionadded:: 0.4.8
"""
def _generate_next_value_(name, *_):
return _name_mangler.spongebob(name)
class CobolCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `COBOL-CASE` to
produce each member's value.
Example usage::
class Example(CobolCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "UPPER-CASE"
assert Example.lower_case == "LOWER-CASE"
assert Example.MixedCase == "MIXED-CASE"
.. versionadded:: 0.4.8
"""
def _generate_next_value_(name, *_):
return _name_mangler.cobol(name)
class HttpHeaderCaseStrEnum(StrEnum):
"""
A ``StrEnum`` where ``auto()`` will convert the name to `Http-Header-Case` to
produce each member's value.
Example usage::
class Example(HttpHeaderCaseStrEnum):
UPPER_CASE = auto()
lower_case = auto()
MixedCase = auto()
assert Example.UPPER_CASE == "Upper-Case"
assert Example.lower_case == "Lower-Case"
assert Example.MixedCase == "Mixed-Case"
.. versionadded:: 0.4.8
"""
def _generate_next_value_(name, *_):
return _name_mangler.http_header(name)

View File

@@ -0,0 +1,43 @@
import enum
from typing import Union, Sequence, Mapping, Any
class StrEnum(str, enum.Enum):
def __new__(cls, value: Union[str, enum.auto], *args: Sequence[Any], **kwargs: Mapping[Any, Any]) -> StrEnum: ...
def __str__(self) -> str: ...
def _generate_next_value_(name: str, *_) -> str: ...
class LowercaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class UppercaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class CamelCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class PascalCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class KebabCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class SnakeCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class MacroCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class CamelSnakeCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class PascalSnakeCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class SpongebobCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class CobolCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...
class HttpHeaderCaseStrEnum(StrEnum):
def _generate_next_value_(name: str, *_) -> str: ...

View File

@@ -0,0 +1,127 @@
# pylint: disable=no-name-in-module
import re
from zlib import crc32
class _NameMangler:
_regex = re.compile(r"([A-Z]?[a-z]+)|([A-Z]+(?![a-z]))")
def words(self, name):
"""
Split a string into words. Should correctly handle splitting:
camelCase
PascalCase
kebab-case
snake_case
MACRO_CASE
camel_Snake_Case
Pascal_Snake_Case
COBOL-CASE
Http-Header-Case
It _does not_ handle splitting spongebob case.
"""
yield from (m.group(0) for m in self._regex.finditer(name))
def camel(self, name):
"""
Convert a name to camelCase
"""
def cased_words(word_iter):
yield next(word_iter, "").lower()
yield from (w.title() for w in word_iter)
return "".join(cased_words(self.words(name)))
def pascal(self, name):
"""
Convert a name to PascalCase
"""
return "".join(w.title() for w in self.words(name))
def kebab(self, name):
"""
Convert a name to kebab-case
"""
return "-".join(w.lower() for w in self.words(name))
def snake(self, name):
"""
Convert a name to snake_case
"""
return "_".join(w.lower() for w in self.words(name))
def macro(self, name):
"""
Convert a name to MACRO_CASE
"""
return "_".join(w.upper() for w in self.words(name))
# The following are inspired by examples in the Wikipedia
# [Naming convention](https://en.wikipedia.org/wiki/Naming_convention_(programming))
# article
def camel_snake(self, name):
"""
Convert a name to camel_Snake_Case
"""
def cased_words(word_iter):
yield next(word_iter, "").lower()
yield from (w.title() for w in word_iter)
return "_".join(cased_words(self.words(name)))
def pascal_snake(self, name):
"""
Convert a name to Pascal_Snake_Case
"""
return "_".join(w.title() for w in self.words(name))
def spongebob(self, name):
"""
Convert a name to SpOngEBOb_CASe
The PRNG we use is seeded with the word to be scrambled. This produces
stable output so the same input will always produce in the same output.
It's not `truly` random, but your tests will thank me.
"""
def prng(seed_word):
state = 1 << 31 | crc32(seed_word.encode("utf-8")) | 1
def step(state):
state = state >> 1 | (state & 0x01 ^ ((state & 0x02) >> 1)) << 31
bit = state & 0x1
return bit, state
for _ in range(100):
_, state = step(state)
while True:
bit, state = step(state)
yield str.upper if bit else str.lower
def scramble(word):
return "".join(f(ch) for ch, f in zip(word, prng(word)))
return "_".join(scramble(w) for w in self.words(name))
def cobol(self, name):
"""
Convert a name to COBOL-CASE
"""
return "-".join(w.upper() for w in self.words(name))
def http_header(self, name):
"""
Convert a name to Http-Header-Case
"""
return "-".join(w.title() for w in self.words(name))

View File

@@ -0,0 +1,15 @@
import re
from zlib import crc32
class _NameMangler:
def words(self, name: str) -> str: ...
def camel(self, name: str) -> str: ...
def pascal(self, name: str) -> str: ...
def kebab(self, name: str) -> str: ...
def snake(self, name: str) -> str: ...
def macro(self, name: str) -> str: ...
def camel_snake(self, name: str) -> str: ...
def pascal_snake(self, name: str) -> str: ...
def spongebob(self, name: str) -> str: ...
def cobol(self, name: str) -> str: ...
def http_header(self, name: str) -> str: ...

View File

@@ -0,0 +1,21 @@
# This file was generated by 'versioneer.py' (0.18) from
# revision-control system data, or from the parent directory name of an
# unpacked source archive. Distribution tarballs contain a pre-generated copy
# of this file.
import json
version_json = '''
{
"date": "2023-06-29T23:39:30+0200",
"dirty": false,
"error": null,
"full-revisionid": "ab34b770aacac80431cd77f28770a60144679d38",
"version": "0.4.15"
}
''' # END VERSION_JSON
def get_versions():
return json.loads(version_json)

View File

@@ -0,0 +1,64 @@
class Comparable:
"""Customise how your Enum acts when compared to other objects.
Your Enum must implement a ``_cmp_values`` method which takes the Enum
member's value and the other value and manipulates them into the actual
values that can be compared.
A case-insensitive StrEnum might look like this::
class HttpHeader(Comparable, KebabCaseStrEnum):
ContentType = auto()
Host = auto()
Accept = auto()
XForwardedFor = auto()
def _cmp_values(self, other):
return self.value.lower(), str(other).lower()
You could then use these headers in case-insensitive comparisons::
assert "Content-Type" == HttpHeader.ContentType
assert "content-type" == HttpHeader.ContentType
assert "coNtEnt-tyPe" == HttpHeader.ContentType
.. note::
Your ``_cmp_values`` method *must not* return ``self`` as one of the
values to be compared -- that would result in infinite recursion.
Instead, perform operations on ``self.value`` and return that.
.. warning::
A bug in Python prior to 3.7.1 prevents mix-ins working with Enum
subclasses.
.. versionadded:: 0.4.6
"""
def __eq__(self, other):
value, other = self._cmp_values(other)
return value == other
def __ne__(self, other):
value, other = self._cmp_values(other)
return value != other
def __lt__(self, other):
value, other = self._cmp_values(other)
return value < other
def __le__(self, other):
value, other = self._cmp_values(other)
return value <= other
def __gt__(self, other):
value, other = self._cmp_values(other)
return value > other
def __ge__(self, other):
value, other = self._cmp_values(other)
return value >= other
def _cmp_values(self, other):
raise NotImplementedError(
"Enum's using Comparable must implement their own _cmp_values function."
)

View File

@@ -0,0 +1,10 @@
from typing import Tuple, Any
class Comparable:
def __eq__(self, other: Any) -> bool: ...
def __ne__(self, other: Any) -> bool: ...
def __lt__(self, other: Any) -> bool: ...
def __le__(self, other: Any) -> bool: ...
def __gt__(self, other: Any) -> bool: ...
def __ge__(self, other: Any) -> bool: ...
def _cmp_values(self, other: Any) -> Tuple[str, str]: ...