Dynamic enum values on nested classes with Python

Question:

Consider the following enum class:

from enum import Enum


class Namespace:

    class StockAPI(Enum):
        ITEMS = "{url}/items"
        INVENTORY = "{url}/inventory"

    class CustomerAPI(Enum):
        USERS = "{url}/users"
        PURCHASES = "{url}/purchases"

    def __init__(self, url):
        self.url = url

I am trying to make url a dynamic value for each enum class.

What can I do here so that I can call some enum class in one of the following ways:

  • Namespace.StockAPI.ITEMS.value would return http://localhost/items?
  • Namespace(url="http://localhost").StockAPI.ITEMS.value would also return http://localhost/items

Is this possible to do without doing variable interpolation each time I access each enum property? Could factory pattern be of any help here?

Asked By: renatodamas

||

Answers:

use f-string:

ITEMS = "{}/items".format(url)

and so on,
but if you use classes, then add new attribute and call it in f-string:

class MyClass:
   url = "htpp://www.some.thing"

obj = MyClass()
ITEMS = "{0.url}/items".format(obj)

if you don’t have same names, it is possible to implement it without any Enum:

class Namespace:
    def __init__(self, url): 
        USERS = "{}/users".format(url)
        PURCHASES = "{}/purchases".format(url)
        ITEMS = "{}/items".format(url)
        INVENTORY = "{}/purchases".format(url)

obj = Namespace("https://www.some.news")
print(obj.USERS)        # https://www.some.news/users
print(obj.PURCHASES)    # https://www.some.news/purchases
print(obj.ITEMS)        # https://www.some.news/items    
print(obj.INVENTORY)    # https://www.some.news/inventory
Answered By: Ashgabyte

I did it the following way, while keeping the inner enum classes:

from enum import Enum


class Namespace:

    class StockAPI(Enum):
        ITEMS = "{url}/items"
        INVENTORY = "{url}/inventory"

    class CustomerAPI(Enum):
        USERS = "{url}/users"
        PURCHASES = "{url}/purchases"

    def __init__(self, url: str):
        attrs = (getattr(self, attr) for attr in dir(self))
        enums = (a for a in attrs if isinstance(a, type) and issubclass(a, Enum))
        for enum in enums:
            kv = {e.name: e.value.format(url=url) for e in enum}
            setattr(self, enum.__name__, Enum(enum.__name__, kv))

print(Namespace(url="http://test.com").StockAPI.ITEMS.value)
# http://test.com/items
Answered By: renatodamas
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.