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

Polymodel instances' class_ attribute should contain a list of str objects on creation #89

Open
spiqueras opened this issue May 26, 2023 · 3 comments · May be fixed by #93
Open

Polymodel instances' class_ attribute should contain a list of str objects on creation #89

spiqueras opened this issue May 26, 2023 · 3 comments · May be fixed by #93

Comments

@spiqueras
Copy link

Expected Behavior

Polyclass models have a read-only attribute called class_ that contains the class hierarchy in form of a list. This attribute should always contain a list of either str or bytes, preferably the former.

Actual Behavior

On instance creation, the class_ attribute is filled with bytes objects. After the object is put and on any subsequent read, this attribute will contain str objects instead. This makes the attribute hard to rely on, as if you ever want to use it you need to know if the entity has already been written to the database or not or convert between types. It also breaks instance equality checks when one of the instance has just been created and the other has been retrieved from the database.

This is similar in Python 2 SDK (the attribute is of type str pre-put and unicode after), but due to Python 2's str and unicode being mostly compatible, it wasn't that much of an issue.

Steps to Reproduce the Problem

The following test will work fine in Python 2 but fail in Python 3.

from google.appengine.ext import testbed
from google.appengine.ext.ndb import polymodel


class APolymodel(polymodel.PolyModel):
    pass


def test_class_in_polymodel():
    bed = testbed.Testbed()
    bed.activate()
    bed.init_datastore_v3_stub()
    bed.init_memcache_stub()

    concrete = APolymodel(id=1)
    concrete.put()

    concrete_2 = APolymodel(id=1)
    assert concrete == concrete_2

    bed.deactivate()

The error

FAILED tests_py3/model_test.py::test_class_in_polymodel - AssertionError: assert APolymodel(key=Key('APolymodel', 1), class_=['APolymodel']) == APolymodel(key=Key('APolymodel', 1), class_=[b'APolymodel'])

The offending code is likely the following:

def _class_key(cls):
"""Return the class key.
This is a list of class names, e.g. ['Animal', 'Feline', 'Cat'].
"""
return [six.ensure_binary(c._class_name()) for c in cls._get_hierarchy()]

Unless there's a clear reason to enforce class_ being a bytes list on instance creation, I'd be great to remove the ensure_binary, making it consistently an str list.

Goes without saying, but this issue does not happen to classes that inherit from ndb.Model.

Specifications

  • Version: 1.1.1
  • Platform: python3.9
@shreejad shreejad self-assigned this May 30, 2023
spiqueras pushed a commit to spiqueras/appengine-python-standard that referenced this issue Jun 29, 2023
@spiqueras spiqueras linked a pull request Jul 3, 2023 that will close this issue
1 task
@shreejad
Copy link
Collaborator

We are considering this change. It will take some time because we need to ensure this will not break existing users.
My current plan is to introduce this change in the next Major Version update enabled by a flag. In a subsequent update, we can update the flag to be enabled by default.

@estrellis
Copy link
Collaborator

estrellis commented Jul 25, 2023 via email

spiqueras pushed a commit to spiqueras/appengine-python-standard that referenced this issue Aug 7, 2023
@shreejad shreejad removed their assignment Oct 23, 2024
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

Successfully merging a pull request may close this issue.

3 participants