Commit af5625fa authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Modify PatternEnum subclasses' members with a method

Replace static additional members dict with a method for programmatic
modifications.
parent 3128b302
Loading
Loading
Loading
Loading
+25 −3
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@ Step implementations dealing with HTTP requests

from __future__ import annotations

from typing import Any

from behave import then
from behave import when
from behave.runner import Context
@@ -25,10 +27,30 @@ class ResponseCode(int, PatternEnum):
	ok = 200
	not_found = 404

	members = {
		"200": 200, "OK": 200,
		"404": 404, "Not Found": 404,
	# Aliases for the above codes, for mapping natural language in feature files to enums
	ALIASES = {
		"OK": 200,
		"Not Found": 404,
	}

	@staticmethod
	def member_filter(attr: dict[str, Any], member_names: list[str]) -> None:
		"""
		Add natural language aliases and stringified code values to members

		Most will be accessible only though a class call, which is acceptable as that is how
		step implementations look up the values.
		"""
		additional = {
			str(value): value
			for name in member_names
			for value in [attr[name]]
			if isinstance(value, int)
		}
		additional.update(attr["ALIASES"])
		member_names.remove("ALIASES")
		member_names.extend(additional)
		attr.update(additional)


@when("{url:URL} is requested")
+5 −6
Original line number Diff line number Diff line
@@ -67,17 +67,16 @@ def register_pattern(pattern: str, converter: PatternConverter|None = None) -> P

class EnumMeta(enum.EnumMeta):

	MEMBERS = 'members'
	MEMBER_FILTER = 'member_filter'

	T = TypeVar("T", bound="EnumMeta")

	def __new__(mtc: type[T], name: str, bases: tuple[type, ...], attr: dict[str, Any], **kwds: Any) -> T:
		member_names: list[str] = attr._member_names  # type: ignore
		if mtc.MEMBERS in member_names:
			members = attr.pop(mtc.MEMBERS)
			member_names.remove(mtc.MEMBERS)
			member_names.extend(members)
			attr.update(members)
		member_filter = attr.pop(mtc.MEMBER_FILTER, None)
		if member_filter:
			assert isinstance(member_filter, staticmethod)
			member_filter.__func__(attr, member_names)
		cls = enum.EnumMeta.__new__(mtc, name, bases, attr, **kwds)
		decorator = parse.with_pattern('|'.join(member for member in cls.__members__))
		behave.register_type(**{name: decorator(cls)})