-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
GeoPt not honoured #1065
Comments
/cc @pcostell |
@thinrhino Here is what I've just done: from google.appengine.ext import ndb
class Foo(ndb.Model):
bar = ndb.GeoPtProperty()
g = ndb.GeoPt(10.0, 10.0)
f = Foo(bar=g)
f.put()
print(f) which created Then in from gcloud import datastore
client = datastore.Client()
key = client.key('Foo', 5634472569470976)
entity = client.get(key)
print(entity) which is <Entity[{'kind': u'Foo', 'id': 5634472569470976L}] {u'bar': <Entity {u'y': 10.0, u'x': 10.0}>}> So the data is still there, but I'm not sure the |
I believe this is doing what it should -- as GeoPt isn't something supported by the JSON API, but instead is an abstraction in DB / NDB
So under the hood, it looks like NDB is taking a GeoPt and turning into a pair of coordinates before saving via the API -- and then loading it into that property on the way out of the API as well. If we get NDB running on top of the Cloud Datastore API this problem should go away as you'd just use NDB the whole time (see to #557). |
Actually stepping into
The only real mention of "meaning" in the
so maybe we need to add support for setting "meaning" in these cases. |
@jgeewax Thanks for hunting down the source,
and the list of meanings is defined in |
Yea we definitely need @pcostell to chime in on this -- I have no idea what the meaning value might mean in a broader sense. Hopefully we can use that.. Hypothetically, if that did exist, do you think gcloud.datastore should have a GeoPt data type? |
v1beta2 doesn't have a specific geopt field, which is why it is represented using this "legacy-supported" type (an In general, fields with the meaning should always be preserved, however we should never be creating new fields with meanings set (which is why in the API they are not actually explained). You should still be able to edit this field in the same way you can edit an |
@pcostell When can we start using |
"Soon". This should still work in v1beta2, as the property should still be editable as a normal entity_value. You should never be setting the meaning, but you should be persisting an existing meaning. So if users can edit an entity value, this should work. |
Is it worth making a change to preserve to meaning if we are just going to ditch meanings all together "soon"? (It really depends on your judgment of how soon.) We just did a release 8/12 so even if we made a fix it may not be in a release for another 14-21 days . |
Yes, we should always be preserving the meaning. There are other legacy properties that will still require meaning even after the |
OK great. Secondary question, what are the mysterious enums at 20 and 21 for meaning?
|
Secret :-). We don't want clients of the gcloud libraries actually depending on meaning value (they should only be persisting them). At the moment (but we reserve the right to change them): 9 is a GeoPt which is exists in the geo-range (lat/lng), 21 is an "invalid" geopoint (any range, so really just a point), and 20 represents an App Engine UserProperty. |
Thanks! I was just saying secret because they aren't in |
I was just pointing out that they were intentionally left out because we don't want people to depend on them. |
Gotcher. Just wanted to make sure we were on the same page. I'll ping you when I add the fix for |
@pcostell Trying to implement this, I'm realizing we have no way (without some re-architecting) to preserve the Comments like
make me think we should keep meaning irrespective of the other property on the We could fail (i.e. raise an exception) if |
I think we need to preserve the meaning regardless. Otherwise you'll break GAE apps that rely on the typing which is determined by the meaning. |
OK thanks. Some mad science going in my brain right now (involving over-riding |
@pcostell I took a few stabs at this and didn't like anything I created. What does the horizon look like for support of |
We'll likely have to support |
I'm thinking the "easiest" way to deal with this is just to define a For things like lat/long we can have a custom |
ping! This right now will corrupt users data in ways that will likely break their GAE applications. I think if at any point a user sets a value, it is acceptable to lose any notion of the existing meaning. However, if a user does: |
I agree with @pcostell here ( |
I spent a fair bit of time trying to make this work in August and it was really tough given our current model. TL;DR we store properties just using the value and then have a strict mapping from acceptable Python types to the actual proto field types. Thus there is no easy way to store a value and some data about that value. I was hoping |
Like I mentioned before, On Sun, Nov 8, 2015, 9:24 AM Danny Hermes [email protected] wrote:
|
I should just mock up the Are we safe to switch over? If not, when can the switch occur? |
On Mon, Nov 9, 2015 at 1:37 AM Danny Hermes [email protected]
|
What do we have to change for that to be possible? As of now we're technically corrupting people's data if they happen to use fancy structures in App Engine and write back that same data from gcloud-python. Even for a 0.x release that's a pretty bad thing. |
There are a few approaches, none of which is very compelling. The one I settled on was to use a custom wrapper type to hold a value and meaning when necessary. I've still got a dead-ish branch for this approach. I'm currently breaking down |
@jgeewax and @pcostell I am curious what you think of these strategies: Choice 1
Choice 2
I am partial to Choice 1 because re-implementing As a "modification" to Choice 1, we could also store something like _meanings = {
'prop1': (DATETIME_MEANING, datetime.datetime),
'prop2': (EMAIL_MEANING, str),
...
} and then throw an error on serialization if
Also as a modification to Choice 1 (in the name of leaving
|
Another suggestion from @tseaver:
|
The Cloud Datastore API doesn't make any commitment about meaning <==> type In general, I think it is ok if you store the meaning internally but then On Tue, Nov 17, 2015 at 6:50 PM Danny Hermes [email protected]
|
Thanks Patrick! |
FYI I'm closing in on a fix for this (also fixes #1206 as a side effect) |
To do this, added entity_to_protobuf method that could be used recursively. Also solves googleapis#1206 since recursively serializing nested entities to protobuf was being done incorrectly. Fixes googleapis#1065. Fixes googleapis#1206.
To do this, added entity_to_protobuf method that could be used recursively. Also solves googleapis#1206 since recursively serializing nested entities to protobuf was being done incorrectly. Fixes googleapis#1065. Fixes googleapis#1206.
To do this, added entity_to_protobuf method that could be used recursively. Also solves googleapis#1206 since recursively serializing nested entities to protobuf was being done incorrectly. Fixes googleapis#1065. Fixes googleapis#1206.
@thinrhino Sorry for the delay but this has been fixed and will hopefully be in a release soon. From my App Engine app (using the remote api) I made a property with lots of meanings (including geo point): from google.appengine.ext import ndb
class Foo2(ndb.Model):
_use_cache = False
_use_memcache = False
b1 = ndb.BlobProperty(compressed=True)
class Foo(ndb.Model):
_use_cache = False
_use_memcache = False
b1 = ndb.BlobProperty(compressed=True)
b2 = ndb.BlobProperty(compressed=True, repeated=True)
t1 = ndb.TextProperty(compressed=False, indexed=False)
geo = ndb.GeoPtProperty()
struct_p = ndb.StructuredProperty(Foo2)
loc_struct_p = ndb.LocalStructuredProperty(Foo2)
f1 = Foo2(b1='hey')
f2 = Foo(id=1234, b1='b1', b2=['hi', 'ok'],
t1='t1', geo=ndb.GeoPt(52.37, 4.88),
struct_p=f1, loc_struct_p=f1)
f2.put() and then I retrieved it with >>> import os
>>> import pprint
>>> from gcloud import datastore
>>> os.environ.pop('GOOGLE_APPLICATION_CREDENTIALS')
'path/redacted'
>>> client = datastore.Client(dataset_id='gae-app-id')
>>> key = client.key('Foo', 1234)
>>> entity = client.get(key)
>>> pprint.pprint(entity._meanings)
{u'b1': (22, 'x\x9cK2\x04\x00\x00\xf7\x00\x94'),
u'b2': (22,
['x\x9c\xcb\xc8\x04\x00\x01;\x00\xd2',
'x\x9c\xcb\xcf\x06\x00\x01K\x00\xdb']),
u'geo': (9, <Entity {u'y': 4.88, u'x': 52.37}>),
u'struct_p.b1': (22, 'x\x9c\xcbH\xad\x04\x00\x02~\x01G'),
u't1': (15, u't1')}
>>> sorted(entity._meanings.keys())
[u'b1', u'b2', u'geo', u'struct_p.b1', u't1']
>>> sorted(entity.keys())
[u'b1', u'b2', u'geo', u'loc_struct_p', u'struct_p.b1', u't1']
>>> entity['geo']._meanings
{}
>>> entity['geo']
<Entity {u'y': 4.88, u'x': 52.37}>
>>> entity['loc_struct_p']._meanings
{u'b1': (22, 'x\x9c\xcbH\xad\x04\x00\x02~\x01G')}
>>> entity['loc_struct_p']
<Entity {u'b1': 'x\x9c\xcbH\xad\x04\x00\x02~\x01G'}> even more, I made a change to the geo point (and sent to backend) and retrieved again to make sure they were identical >>> entity['geo']['x'] = 3.14
>>> client.put(entity)
>>> entity2 = client.get(key)
>>> entity == entity2
True
>>> entity._meanings == entity2._meanings
True
>>> client.delete(entity.key) (I also verified in the App Engine datastore viewer that the geo point change went through as expected) |
@dhermes thanks a lot. Will check it out soon. |
We have a record in the datastore which has the object type
ndb.GeoPtProperty
. This record was set via ndb from the app engine. Now we are running a script on GCE to modify one field in this record, without touching the original location point.When the record is saved from gCloud API, the record looses it's
GeoPtProperty
.Before:
After:
The text was updated successfully, but these errors were encountered: