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

Allow both typed and raw subclasses of MapAttribute #596

Open
bugeats opened this issue Feb 15, 2019 · 8 comments
Open

Allow both typed and raw subclasses of MapAttribute #596

bugeats opened this issue Feb 15, 2019 · 8 comments

Comments

@bugeats
Copy link

bugeats commented Feb 15, 2019

Imagine me wanting a simple key/value attribute. Ok no prob just use MapAttribute -- just as long as you don't subclass MapAttribute -- in which case the entire behavior is flipped upside down. Wah?

I find this documentation to be completely impenetrable:

class MapAttribute(Attribute, AttributeContainer):

I read it 10 times at least, and I still don't know what to do. Regardless if that design is here to stay or not, I humbly suggest adding something like KeyValueAttribute to hide the pain from dummies like me.

@jpinner-lyft
Copy link
Contributor

jpinner-lyft commented Feb 15, 2019

👋 can you add some example code to show what you're trying to do when subclassing? In the subclass' init method, did you call super init?

@bugeats
Copy link
Author

bugeats commented Feb 15, 2019

Oh hi. 👋 Yeah. I'm just sub-classing to support a simple framework for aggregation of schema definitions. So it might look like this:

from pynamodb.attributes import MapAttribute
from pynamodb.models import Model


class MyKeyValueMapAttribute(MapAttribute):
    @classmethod
    def to_schema(cls):
        return {
            'type': 'object'
        }


class MyModel(Model):
    class Meta:
        host = '...'
        table_name = '...'

    bucket = MyKeyValueMapAttribute(null=True, attr_name='bucket', default={})

I'm not trying to make a unique record, just trying to extend the base MapAttribute with some custom methods.

EDIT: no, no super init

@jpinner-lyft
Copy link
Contributor

jpinner-lyft commented Feb 15, 2019

So MapAttributes as you've found are unfortunately very "special" -- they have a dual behavior that depends on both where they are defined and how they are accessed :(

The short answer is I think you need to override the is_raw class method in your subclass to return True.

Edit: is_raw is used to distinguish between MapAttributes that are "simple" maps versus those that strictly define the attributes inside of them.

@bugeats
Copy link
Author

bugeats commented Feb 15, 2019

Hey is_raw class method did the trick, thanks!

I was trying to be careful with the title of this issue, since I do think special behavior is the core of the problem. May we keep the ticket open to represent the hope of creating Attribute classes with more clearly defined boundaries in their behavior?

Again I think teasing out a KeyValueAttribute would go a long way, whether or not the core architecture of "dual behavior that depends on both where they are defined and how they are accessed" is reconsidered.

Thanks again.

@jpinner-lyft
Copy link
Contributor

jpinner-lyft commented Feb 15, 2019

The addition of "typed" subclasses. along with the use of class attributes in expressions, certainly caused complexity in the implementation. A lot was done to ensure backwards compatibility as the feature set grew.

I don't think there was ever any thought to allowing users to subclass map attributes while keeping the "raw" behavior. All subclasses were assumed to be typed bags.

Perhaps a better way to phrase this would be as a feature request?

"Allow both typed and raw subclasses of MapAttribute."

cc/ @ikonst @jmphilli @garrettheel

@bugeats bugeats changed the title MapAttribute has different behavior if subclassed Allow both typed and raw subclasses of MapAttribute Feb 15, 2019
@ikonst
Copy link
Contributor

ikonst commented Feb 16, 2019

Splitting the "raw" behavior out of MapAttribute would probably make the type annotation simpler too.

@garrettheel
Copy link
Member

@jpinner-lyft @ikonst agreed that subclassing while maintaining the "raw" behavior is something we should support. Feel free to file this as a bug or feature request

@jpinner-lyft
Copy link
Contributor

#868 might actually address this

by subclassing DynamicMapAttribute you always get a "raw" version as long as you don't define any attributes

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

4 participants