Enumerations¶
Simple Enums¶
enum Color:
RED = 1
GREEN = 2
BLUE = 3
enum HttpMethod:
GET = "GET"
POST = "POST"
PUT = "PUT"
DELETE = "DELETE"
def main() -> None:
favorite = Color.RED
if favorite == Color.RED:
print("Red is your favorite")
# Access underlying value
value = favorite.value # 1
name = favorite.name # "RED"
print(value, name) # 1 RED
Rules:
- All cases must have explicit constant values
- All values must be of the same type, either an integer type or the str type.
- Enums must have at least one case
Enum Iteration and Methods:
enum Color:
RED = 1
GREEN = 2
BLUE = 3
def main() -> None:
# Iterate over all enum values
for color in Color:
print(f"{color.name} = {color.value}")
# Output:
# RED = 1
# GREEN = 2
# BLUE = 3
# Get all values as a list
all_colors: list[Color] = list(Color)
# Get all names
names: list[str] = [c.name for c in Color] # ["RED", "GREEN", "BLUE"]
# Get all values
values: list[int] = [c.value for c in Color] # [1, 2, 3]
print(len(all_colors), names, values) # 3 ['RED', 'GREEN', 'BLUE'] [1, 2, 3]
str and repr of an integer enum are Python's: str(Color.RED) is Color.RED, repr is
<Color.RED: 1>, and .name is the member name exactly as declared — the same spelling on every
route (print, f-strings and format() pad the str, a list or dict element is the repr). The
rule covers every .NET enum reached through interop too: str(DayOfWeek.Monday) is
DayOfWeek.Monday (Sharpy-only; Python has no such type).
enum Color:
RED = 1
dark_blue = 2
def main() -> None:
print(Color.RED) # Color.RED
print(repr(Color.dark_blue)) # <Color.dark_blue: 2>
print(Color.dark_blue.name) # dark_blue
print(f"[{Color.RED:>12}]") # [ Color.RED]
print([Color.RED]) # [<Color.RED: 1>]
A string-backed enum keeps StrEnum's str (the value, below).
Note: Simple enums (non-tagged unions) cannot have custom methods. For enums with methods, use tagged unions, see tagged_unions.md.
String-Backed Enums¶
An enum whose members carry string values is a string-backed enum, and it behaves like
CPython's StrEnum: a member is its own type and is usable wherever a str is.
enum Color:
RED = "red"
GREEN = "green"
def describe(c: str) -> str:
return "<" + c + ">"
def main() -> None:
c: Color = Color.RED # the declared enum type is a real annotation
print(c.name) # RED — the member name
print(c.value) # red — the backing string
print(str(c)) # red — str() gives the value
print(repr(c)) # <Color.RED: 'red'> — repr() is StrEnum's
print(c == Color.RED) # True — member identity
print(c == "red") # True — and its backing string
print(describe(Color.GREEN)) # <green> — passes as a str
s: str = Color.GREEN # assigns to a str
for x in Color: # iterates its members
print(x.name)
Because a string-backed enum lowers to a class, no name the class declares may equal the enum's own
(C#'s CS0542). A member that compiles to the enum's name, and a string enum named like one of the
members its class synthesizes (Name, Value, Values, ToString — so enum value too), are
refused with SPY0525: rename the member or the enum. When it is the member's casing that
collides (color compiles to Color), backtick-escaping the member's declaration also works: an
escaped member compiles verbatim, and every reference to it — Color.color, Color.`color`,
case Color.color: — follows the declaration, escaped or not. An integer-backed enum is a C# enum,
whose members may share its name, so enum Color: Color = 1 compiles.
enum Color:
Color = "c" # SPY0525: emitted as 'Color', the same name as its enclosing type
RED = "r"
def main() -> None:
print(Color.RED)
enum Color:
`color` = "c" # escaped: compiles to 'color', no clash with 'Color'
RED = "r"
def main() -> None:
print(Color.color.value) # c — a plain use follows the escaped declaration
print(Color.`color`.value) # c
Implementation
- Integer enums: ✅ Native - C# enum
- String enums: 🔄 Lowered - sealed class of singleton instances carrying Name/Value, with
ToString() returning the value, an explicit Sharpy.IRepr.Repr() giving StrEnum's
<Color.RED: 'red'>, an implicit conversion to string, and a static Values list
- .name property: 🔄 Lowered - Sharpy.Builtins.EnumName (integer enums: the python name
the field records in [SharpyFieldName] when its C# name differs, else the field name — the same
channel str/repr read); the instance's Name (string enums)