-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Add more descriptive pydeck types classes #4897
base: master
Are you sure you want to change the base?
Conversation
try: | ||
json.dumps(value) | ||
except TypeError as e: | ||
raise TypeError("Literal value must be JSON serializable\n" + e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're going to get a TypeError in your TypeError message, since the string and error don't concatenate. Maybe
raise TypeError("pydeck Literal value must be JSON serializable and input {} is not".format(value))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes you're right. I think I'm looking for e.message
.
|
||
|
||
class Type(metaclass=abc.ABCMeta): | ||
"""Base class for Pydeck defined type""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of having typed objects for these and not automagically deduce the encoding
ENUM_IDENTIFIER = "@@#" | ||
|
||
|
||
class Type(metaclass=abc.ABCMeta): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest naming this something more descriptive than "Type", which seems a little generic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's a base class, BaseType
might be more apt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Naming base classes with Base...
is one my pet peeves. I feel that it is a design cop-out. Let's ideate a bit more first.
SerializableType
, TransportType
, TransportableType
, ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. This base class isn't public so I'm not too concerned with what the name should be, and welcome those suggestions. I'd also consider prefixing with _
to make clear it's private.
@@ -82,28 +83,29 @@ def __init__(self, type, data, id=None, use_binary_transport=None, **kwargs): | |||
self._kwargs = kwargs.copy() | |||
if kwargs: | |||
for k, v in kwargs.items(): | |||
if isinstance(v, Type): | |||
continue | |||
|
|||
# We assume strings and arrays of strings are identifiers | |||
# ["lng", "lat"] would be converted to '[lng, lat]' | |||
# TODO given that data here is usually a list of records, | |||
# we could probably check that the identifier is in the row | |||
# Errors on case like get_position='-', however | |||
|
|||
if isinstance(v, str) and v[0] in QUOTE_CHARS and v[0] == v[-1]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will also fail for "a" + b + "c"
(results in a" + b + "c
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the question here is what is the desired behavior? Is "a" + b + "c"
-> a + b + c
more desired?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect "a" + b + "c"
to be "a" + b + "c"
to match the behavior of "a" + "c" + b
. The type result changing so dramatically from changing the order of operators is surprising.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right I'd also prefer that but it's a breaking change.
Side note: don't want to make this more complex but I am thinking about how these design choices translate to the bigger cross-language picture. E.g. if similar constructs would make sense in C++, Java, Swift Proxy bindings... I really want these various API to develop in the same general direction. Could be worth sketching out how things would look in those APIs... |
I think it's good to have that discussion before merging a PR such as this one into Pydeck. I could envision a similar API for other languages. A good precursor might be to minimize the differences between pydeck and the JSON spec? |
Agreed. About Proxy API definition: At the moment we don't have a reference Proxy API for deck.gl JSON that other languages can just follow. The most "natural" proxy API would be implemented in JavaScript - but it is not really needed for obvious reasons (though it could potentially be useful for e.g. for rendering deck.gl from Node.js, and certainly for testing proxying setups). We do have pydeck and experimental Java and Swift proxy APIs. We may also want to start sketching on a C++ proxy API. |
0a083b6
to
eb85da3
Compare
Background
Currently pydeck does a lot of "magic" behind the scenes to coerce user input into the representation sent to
@deck.gl/json
."properties.valuePerSqm"
becomes the functiondatum => datum.properties.valuePerSqm
. To pass a string literal, you need to use'"literal string"'
.'"literal "" string"'
in Python becomes'literal string'
in JS.Change List
These changes are designed to minimize backwards incompatibility.
Enum
,Literal
,Function
andIdentifier
.Enum
takes string input and prefixes@@#
before serializationLiteral
takes any JSON-encodable object and passes it unchanged to JSFunction
takes varied input.For string input it prefixes
@@=
for serialization.For number input it stringifies the number and prefixes
@@=
.For
Literal
input it prefixes@@=
and surrounds the input with double quotes. I.e.Literal('foo')
becomes@@="foo"
. This is necessary because the@deck.gl/json
docs say:The
Identifier
class is included as a more-explicit form of string input. It includes its string unquoted.Each of these should also work within array input. So you should be able to pass
Function([Identifier('x'), Identifier('y'), Literal(0)])
to render data at ground level.'"literal "" string"'
in Python becomes'literal "" string'
in JS. This is a backwards incompatible change, but the existing behavior is arguably broken.