Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unable to create ListAttribute of custom attribute #1194

Open
rsmekala opened this issue Sep 5, 2023 · 2 comments
Open

unable to create ListAttribute of custom attribute #1194

rsmekala opened this issue Sep 5, 2023 · 2 comments

Comments

@rsmekala
Copy link

rsmekala commented Sep 5, 2023

Steps to reproduce

  1. Following class definition
    Attribute definition
UnicodeEnumAttribute
from enum import Enum
from typing import Any
from typing import Optional
from typing import Type
from typing import TypeVar

import pynamodb.constants
from pynamodb.attributes import Attribute

from app.config.llmconfig import AvailableLLMEnum

T = TypeVar("T", bound=Enum)
_fail: Any = object()


class UnicodeEnumAttribute(Attribute[T]):
    attr_type = pynamodb.constants.STRING

    def __init__(
        self, enum_type: Type[T], unknown_value: Optional[T] = _fail, **kwargs: Any
    ) -> None:
        """
        :param enum_type: The type of the enum
        """
        super().__init__(**kwargs)
        self.enum_type = enum_type
        self.unknown_value = unknown_value
        if not all(isinstance(e.value, str) for e in self.enum_type):
            raise TypeError(
                f"Enumeration '{self.enum_type}' values must be all strings",
            )

    def deserialize(self, value: str) -> Optional[T]:
        try:
            return self.enum_type(value)
        except ValueError:
            if self.unknown_value is _fail:
                raise
            return self.unknown_value

    def serialize(self, value: T) -> str:
        if not isinstance(value, self.enum_type):
            raise TypeError(
                f"value has invalid type '{type(value)}'; expected '{self.enum_type}'",
            )
        return value.value

Model defintion

from typing import Optional

from pynamodb.attributes import UnicodeAttribute, ListAttribute, NumberAttribute

from app.config.dynamodbconfig import (
    DynamoDbTableEnum,
    DYNAMO_ENDPOINT,
    DYNAMO_REGION,
)
from app.config.llmconfig import AvailableLLMEnum
from app.models.basemodel import BaseModel
from app.models.custom_attributes.unicodeenum import UnicodeEnumAttribute, AvailableLLMUnicodeEnumListAttribute


class Channel(BaseModel):
    class Meta:
        table_name = DynamoDbTableEnum.CHANNELS_TABLE_NAME
        host = DYNAMO_ENDPOINT
        region = DYNAMO_REGION

    name = UnicodeAttribute(hash_key=True)
    # list of enums cannot be generated with the way of pynamo implements it, bec
    whitelisted_llms = ListAttribute(default=[], of=type(UnicodeEnumAttribute(AvailableLLMEnum)))
    temperature = NumberAttribute(null=True)
    presence_penalty = NumberAttribute(null=True)

    @staticmethod
    def get_channel_name(tenant_name: str, channel_name: str):
        return tenant_name + "|" + channel_name
  1. try saving an item
  2. issue
{"@timestamp":"2023-09-05T04:53:52.442Z","log.level":"error","message":"(TypeError(\"__init__() missing 1 required positional argument: 'enum_type'\"),)","ecs":{"version":"1.6.0"},"error":{"message":"unhandled errors in a TaskGroup (1 sub-exception)","stack_trace":"  File \"/Users/rajashekar/workspace/gai/maverick/venv/lib/python3.9/site-packages/starlette/middleware/errors.py\", line 162, in __call__\n    await self.app(scope, receive, _send)\n  File \"/Users/rajashekar/workspace/gai/maverick/venv/lib/python3.9/site-packages/starlette/middleware/base.py\", line 110, in __call__\n    response_sent.set()\n  File \"/Users/rajashekar/workspace/gai/maverick/venv/lib/python3.9/site-packages/anyio/_backends/_asyncio.py\", line 664, in __aexit__\n    raise BaseExceptionGroup(\n","type":"ExceptionGroup"},"log":{"logger":"app.exception_handlers","origin":{"file":{"line":1,"name":"<string>"},"function":"<module>"},"original":"(TypeError(\"__init__() missing 1 required positional argument: 'enum_type'\"),)"},"process":{"name":"SpawnProcess-3","pid":99594,"thread":{"id":8658525696,"name":"MainThread"}}}

Suspected cause

return self.element_type()

Temporary Workaround

Custom Attribute


class AvailableLLMUnicodeEnumListAttribute(UnicodeEnumAttribute[AvailableLLMEnum]):
    def __init__(self, **kwargs: Any) -> None:
        """
        :param enum_type: The type of the enum
        """
        super().__init__(AvailableLLMEnum, **kwargs)

Model

class Channel(BaseModel):
    class Meta:
        table_name = DynamoDbTableEnum.CHANNELS_TABLE_NAME
        host = DYNAMO_ENDPOINT
        region = DYNAMO_REGION

    name = UnicodeAttribute(hash_key=True)
    # list of enums cannot be generated with the way of pynamo implements it, bec
    whitelisted_llms = ListAttribute(default=[], of=AvailableLLMUnicodeEnumListAttribute)
    temperature = NumberAttribute(null=True)
    presence_penalty = NumberAttribute(null=True)

    @staticmethod
    def get_channel_name(tenant_name: str, channel_name: str):
        return tenant_name + "|" + channel_name
@rsmekala
Copy link
Author

rsmekala commented Sep 5, 2023

@ikonst is this the right way to achieve this ??

@ikonst
Copy link
Contributor

ikonst commented Sep 18, 2023

Your solution seems reasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants