The table below show you what python types to expect and to return when dealing with types defined in the NStack IDL:
| NStack Type | Python Type |
|---|---|
Integer |
int |
Double |
double.Double |
Boolean |
bool |
Text |
str |
| Tuple | tuple |
| Struct | collections.namedtuple * |
| Array | list |
| Sum | see section below |
[Byte] |
bytes |
x optional |
None or x |
*you can return a normal tuple (see Structs section below)
Python doesn't have support for Sum types (aka tagged/disjoint unions) but we still support them via inheritance.
Here's some example definitions of types in the nstack IDL:
type URL = Text; type Referrer = URL; type Target = URL; type Event = PageImpression URL | Click (Referrer, Target);
You can imagine that we create classes for Event and its constructors something like the following:
class Event(object):
...
class PageImpression(Event):
...
class Click(Event):
...
As the sum is defined as a type alias (this is the only way to define sums in the IDL) then the types will be available as members of the nstack package module, and we can construct new values (to return them from an nstack service method) like this:
import nstack
ex_impression = nstack.Event.PageImpression("http://www.nstack.com/")
ex_click = nstack.Event.Click(("http://www.nstack.com/", "http://demo.nstack.com/"))And we can see the class inheritance by asking python about the instances' types:
>> isinstance(ex_impression, nstack.Event) True >> isinstance(ex_impression, nstack.Event.PageImpression) True >> isinstance(ex_impression, nstack.Event.Click) False
You will usually need to handle each branch of the sum type differently. Case analysis can be achieved using python's isinstance function as above...
if isinstance(v, nstack.Event.PageImpression):
... # do something with a page impression
elif isinstance(v, nstack.Event.Click):
... # do something with a clickThe classes have some other useful properties/methods as shown below:
>> ex_impression.value
"http://www.nstack.com/"
>> ex_click.value
("http://www.nstack.com/", "http://demo.nstack.com/")
>> ex_impression.getPageImpression()
"http://www.nstack.com/"
>> ex_impression.getClick()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Not a Click
>> ex_impression.match(lambda i: "got a page impression",
lambda i: "got a click")
"got a page impression"
We an modify the Click branch from the sample above to be a struct/record instead:
type URL = Text;
type Event = PageImpression URL | Click { referrer: URL, target: URL };
When you receive this data into your service method from nstack it will appear as a namedtuple from the collections module in the standard-library. eg:
ClickData = collections.namedtuple("ClickData", ["referrer", "target"])This means you can treat the data as both a normal tuple (each field appears in the order it was defined) but also access each field as a property of the value:
>> input = nstack.Event.Click(("http://www.nstack.com/", "http://demo.nstack.com/"))
>> input.getClick().referrer
"http://www.nstack.com/"
>> input.getClick().target
"http://demo.nstack.com/"
In the example IDL we didn't give the struct a name, it was defined in-line inside the Click branch of the Event type, this means we can't construct it directly if we need to return it from our method. That's ok, namedtuples are just tuples so we can just return a normal tuple and nstack ensure it is correct. We can see this at work in the code example above where the Click constructor is called with a standard python tuple but when we inspect the value we get a namedtuple with the referrer and target properties.