This example illustrates how Python code can access data types written in the Xc++ language. See also the documentation of the cxPython library.
This example assumes you have installed the pyceda module and installed the pypizza module.
The pypizza module defines some data types in the Xc++ language associated with a pizza delivery database:
// PizzaDeliveries.h
@import "Pizza.h"
@import "DateTime.h"
@import "Shapes.h"
namespace pizza
{
$typedef+ int32 TToppingId;
$typedef+ int32 TEmployeeId;
$typedef+ int32 TVehicleTypeId;
$typedef+ int32 TVehicleId;
$typedef+ int64 TCustomerId;
$typedef+ int64 TOrderId;
$typedef+ float64 TCurrency;
$typedef+ string8 TEmail;
$typedef+ string8 TPhoneNumber;
$model+ TAddress <<multiline>>
{
int32 Number;
string8 Street;
string8 City;
int32 ZipPostCode;
string8 StateProvinceCounty;
string8 Country;
};
$model+ TEmployee <<multiline>>
{
TAddress Address;
string8 FirstName;
string8 LastName;
TPhoneNumber PhoneNumber;
};
$model+ TVehicleType
{
string8 Description;
};
$model+ TVehicle
{
TVehicleTypeId VehicleTypeId;
string8 LicensePlateNumber;
};
$enum+ class EPaymentMethod
{
Cash,
EftPos,
CreditCard
};
$model+ TCustomer <<multiline>>
{
TAddress Address;
string8 FirstName;
string8 LastName;
TPhoneNumber PhoneNumber;
TEmail Email;
dt::TDateTime DateOfFirstOrder;
EPaymentMethod PaymentMethod;
};
$enum+ class EDeliveryStatus
{
Cooking,
Delivering,
Completed,
Returned
};
$enum+ class EBaseType
{
Thin,
DeepPan
};
$model+ TCircle
{
float32 Radius;
};
$model+ TRectangle
{
float32 Width;
float32 Height;
};
$variant+ TShape
{
default TCircle(200);
TCircle Circle;
TRectangle Rectangle;
};
$model+ TTopping <<multiline>>
{
TCurrency Price;
string8 Description;
};
$model+ TOrderedPizza <<multiline>>
{
TShape Shape;
EBaseType BaseType;
xvector<TToppingId> ToppingIds;
};
$struct+ TPizzaOrder <<multiline>> isa ceda::IPersistable :
model
{
TOrderId Id;
TCustomerId CustomerId;
TEmployeeId TakenByEmployeeId;
TEmployeeId DeliveredByEmployeeId;
EDeliveryStatus DeliveryStatus;
TVehicleId VehicleId;
dt::TDateTime DateTimeOrderTaken;
dt::TDateTime DateTimeOrderDelivered;
TCurrency TotalOrderPrice;
xvector<TOrderedPizza> Pizzas;
}
{
};
$struct+ TPizzaDeliveryDatabase <<multiline>> isa ceda::IPersistable :
model
{
xmap<TVehicleId, TVehicle> Vehicles;
xmap<TVehicleTypeId, TVehicleType> VehicleTypes;
xmap<TEmployeeId, TEmployee> Employees;
xmap<TToppingId, TTopping> Toppings;
xmap<TCustomerId, TCustomer> Customers;
xvector< movable< cref<TPizzaOrder> > > Orders;
}
{
};
} // namespace pizza
First create a general utility class to open/close ceda databases.
Using your favorite text editor, write a file named pizza-example.py as follows:
# pizza-example.py
# This is python
import random
import string
import pyceda
import pypizza
from cedadatabase import *
ceda = pyceda.cns.ceda
dt = pyceda.cns.dt
shapes = pyceda.cns.shapes
pizza = pyceda.cns.pizza
def printMap(name,m):
print ' len(' + name + ') = ' + `len(m)`
for key in m:
print ' ' + name + '.has_key(' + `key` + ') = ' + `m.has_key(key)`
for key in m:
print ' ' + `key` + ' in ' + name + ' = ' + `key in m`
for key in m.iterkeys():
print ' ' + name + '[' + `key` + '] = ' + `m[key]`
for value in m.itervalues():
print ' value: ' + `value`
for item in m.iteritems():
print ' item: ' + `item`
for key,value in m.iteritems():
print ' key: ' + `key` + ' value: ' + `value`
####################### DateTime
def selectDate():
y = random.randint(2016,2017)
m = random.randint(0,11)
d = random.randint(1,28)
return dt.TDate(Year=y,Month=m,Day=d)
def selectTime():
h = random.randint(0,23)
m = random.randint(0,59)
return dt.TTime(Hour=h,Minute=m,Second=0)
def selectDateTime():
return dt.TDateTime(selectDate(), selectTime())
def setDate(d):
d.Year = random.randint(2016,2017)
d.Month = random.randint(0,11)
d.Day = random.randint(1,28)
def setTime(t):
t.Hour = random.randint(0,23)
t.Minute = random.randint(0,59)
def setDateTime(dt):
setDate(dt.Date)
setTime(dt.Time)
####################### TVehicleType
# Add all vehicle types to the given TPizzaDeliveryDatabase pdd
def addVehicleTypes(pdd):
for s in [ 'Ford Fiesta', 'Mazda3', 'Kia Rio', 'Toyota Yaris', 'Honda Civic', 'Mitsubishi Lancer', 'Subaru Impreza', 'Volkswagen Passat']:
id = len(pdd.VehicleTypes)+1
pdd.VehicleTypes[id].Description = s
####################### TVehicle
def selectLicensePlateNumber():
s = ''
for i in range(3):
s += random.choice(string.ascii_uppercase)
s += '.'
for i in range(3):
s += str(random.randint(0,9))
return s
def setVehicle(v):
v.VehicleTypeId = random.randint(1,8)
v.LicensePlateNumber = selectLicensePlateNumber()
####################### Address
def selectStreet():
return random.choice([ 'Old Kent Road', 'Mayfair St', 'Oxford St', 'Regent St'])
def selectCity():
return random.choice([ 'London', 'New York', 'Paris', 'Perth', 'Berlin'])
def selectState():
return random.choice([ 'Alaska', 'New South Wales', 'Florida', 'California', 'Texas'])
def selectCountry():
return random.choice([ 'Australia', 'USA', 'England', 'India'])
def selectZipCode():
return random.randint(1000,9999)
def setAddress(a):
a.Number = random.randint(1,50)
a.Street = selectStreet()
a.City = selectCity()
a.ZipPostCode = selectZipCode()
a.StateProvinceCounty = selectState()
a.Country = selectCountry()
####################### Employee
def selectFirstName():
return random.choice([ 'John', 'Janet', 'Kate', 'Rihanna', 'Peter', 'Greg'])
def selectLastName():
return random.choice([ 'Smith', 'Matthews', 'Gates', 'Howard', 'Johnson'])
def selectPhoneNumber():
s = ''
for i in range(10):
s += str(random.randint(0,9))
if i == 3 or i == 6:
s += ' '
return s
def setEmployee(e):
setAddress(e.Address)
e.FirstName = selectFirstName()
e.LastName = selectLastName()
e.PhoneNumber = selectPhoneNumber()
# Add an employee to the given TPizzaDeliveryDatabase pdd
def addEmployee(pdd):
i = len(pdd.Employees)
setEmployee(pdd.Employees[i])
####################### Shape
def selectCircle():
return pizza.TCircle(Radius=random.choice([100, 150, 250, 300]))
def selectRectangle():
return pizza.TRectangle(Width=random.choice([100, 200]), Height=random.choice([200, 300]))
# Assign to s which is a variable of type TShape
def setShape(s):
if random.randint(0,2) == 0:
s.Circle = selectCircle()
else:
s.Rectangle = selectRectangle()
####################### Pizza
def selectTopping():
return random.choice([ pizza.EBaseType.Thin, pizza.EBaseType.DeepPan])
def selectPizza():
p = pizza.TOrderedPizza()
setShape(p.Shape)
p.BaseType = selectTopping()
for i in range(random.randint(0,5)):
p.ToppingIds.append(random.randint(0,10))
return p
####################### TPizzaOrder
def selectDeliveryStatus():
return random.choice([ pizza.EDeliveryStatus.Cooking, pizza.EDeliveryStatus.Delivering, pizza.EDeliveryStatus.Completed, pizza.EDeliveryStatus.Returned])
# Must be called by a thread that has opened a transaction on the database.
# Create an object of type TPizzaOrder.
def createPizzaOrder(id):
order = pizza.TPizzaOrder(
Id = id,
CustomerId = random.randint(1,15),
TakenByEmployeeId = random.randint(1,9),
DeliveredByEmployeeId = random.randint(1,9),
DeliveryStatus = selectDeliveryStatus(),
VehicleId = random.randint(1,9),
DateTimeOrderTaken = selectDateTime(),
DateTimeOrderDelivered = selectDateTime(),
TotalOrderPrice = random.randint(1000,5000)/100.0,
Pizzas = [])
for i in range(random.randint(0,3)):
order.Pizzas.insert(i,selectPizza())
return order
def insertSomeOrders(pdd, count):
for i in range(count):
pdd.Orders.insert(0, createPizzaOrder())
def appendSomeOrders(pdd, count):
for i in range(count):
pdd.Orders.append(createPizzaOrder())
# Add an order to the given TPizzaDeliveryDatabase pdd
def addOrder(pdd):
id = len(pdd.Orders)
pdd.Orders.append(createPizzaOrder(id))
# Replace last pizza in the ith order in the given TPizzaDeliveryDatabase pdd
def ReplaceLastPizzaInOrder(pdd,i):
if pdd.Orders[i].Pizzas:
pdd.Orders[i].Pizzas.pop()
pdd.Orders[i].Pizzas.append(selectPizza())
# Print all the orders in the given TPizzaDeliveryDatabase pdd
def printOrders(pdd):
print 'Num orders = ' + `len(pdd.Orders)`
for i in range(len(pdd.Orders)):
order = pdd.Orders[i]
print `order`
def printOrdersInTable(pdd):
print ' Id CustomerId Name Status'
print '------------------------------------------'
for i in range(len(pdd.Orders)):
order = pdd.Orders[i]
if order.CustomerId in pdd.Customers:
c = pdd.Customers[order.CustomerId]
print "{0:>4} {1:>10} {2:>17} {3:>6}".format(order.Id, order.CustomerId, (c.FirstName + ' ' + c.LastName), order.DeliveryStatus)
####################### Customers
def selectEmail():
return selectFirstName() + '.' + selectLastName() + '@gmail.com'
def selectPaymentMethod():
return random.choice([ pizza.EPaymentMethod.Cash, pizza.EPaymentMethod.EftPos, pizza.EPaymentMethod.CreditCard])
def setCustomer(c):
setAddress(c.Address)
c.FirstName = selectFirstName()
c.LastName = selectLastName()
c.PhoneNumber = selectPhoneNumber()
c.Email = selectEmail()
setDateTime(c.DateOfFirstOrder)
c.PaymentMethod = selectPaymentMethod()
# Add a customer to the given TPizzaDeliveryDatabase pdd
def addCustomer(pdd):
id = len(pdd.Customers)
setCustomer(pdd.Customers[id])
####################### Toppings
def selectToppingPrice():
return random.randint(100,200)/100.0
def selectToppingDescription():
return random.choice([ 'Ham', 'Pineapple', 'Chicken', 'Jalapenos', 'Mushrooms', 'Zucchini', 'Garlic', 'Red peppers'])
def setTopping(t):
t.Price = selectToppingPrice()
t.Description = selectToppingDescription()
# Add a topping to the given TPizzaDeliveryDatabase pdd
def addTopping(pdd):
id = len(pdd.Toppings)
setTopping(pdd.Toppings[id])
# Returns a dictionary representation of the toppings
def getToppings(pdd):
d = {}
for id,topping in pdd.Toppings.iteritems():
# The types of the topping fields are native python value types, so as required we are not
# returning references to objects in the database (which can be an issue when done across a
# transaction boundary).
assert type(topping.Price) is float
assert type(topping.Description) is str
d[id] = (topping.Price, topping.Description)
return d
####################### TPizzaDeliveryDatabase
def createPizzaDeliveryDatabase():
pdd = pizza.TPizzaDeliveryDatabase()
addVehicleTypes(pdd)
for i in range(10):
setVehicle(pdd.Vehicles[i+1])
for i in range(10):
addCustomer(pdd)
return pdd
def printPizzaDeliveryDatabase(pdd):
print str(pdd)
#printOrders(pdd)
#printMap('pdd.Employees', pdd.Employees)
utRootKey = 'pizzadatabaseroot'
class PizzaDeliveryDatabase(Database):
def __init__(self, path, createNew):
Database.__init__(self)
self.path = path
self.createNew = createNew
def __enter__(self):
Database.open(self, self.path, self.createNew)
self.bootstrapRootObject(utRootKey, lambda : createPizzaDeliveryDatabase())
return self
def __exit__(self, etype, value, tb):
self.close()
#######################
for repeat in range(3):
createNew = True if repeat==0 else False
with PizzaDeliveryDatabase('mypizzadatabase', createNew) as db:
pdd = db.rootObj # The TPizzaDeliveryDatabase in the database
if db.justCreated:
print 'Created new database'
else:
print 'Opened existing database'
with Txn(db):
addCustomer(pdd)
with Txn(db):
addEmployee(pdd)
with Txn(db):
addTopping(pdd)
with Txn(db):
for i in range(10):
addOrder(pdd)
with Txn(db):
ReplaceLastPizzaInOrder(pdd,0)
with Txn(db):
printOrdersInTable(pdd)
#printPizzaDeliveryDatabase(pdd)
with Txn(db):
d = getToppings(pdd)
print 'toppings: ' + str(d)
# Cannot assign attribute FirstName of read-only pizza::TEmployee
#with Txn(db):
# for id,e in pdd.Employees.iteritems():
# e.FirstName = 'Burt'
DataReplicationTest('mypizzadatabase', 'myreplicatedpizzadatabase', utRootKey, printPizzaDeliveryDatabase)
In a bash terminal run pizza-example.py as follows:
# bash
python pizza-example.py
The following output is generated:
Opening mypizzadatabase Opening PSpace Opening working set Created new database Id CustomerId Name Status ------------------------------------------ 1 2 Peter Smith 1 2 5 Janet Gates 1 3 2 Peter Smith 1 4 1 Janet Johnson 0 6 9 Peter Howard 2 8 1 Janet Johnson 1 9 1 Janet Johnson 2 toppings: {0: (1.58, 'Jalapenos')} Closing WorkingSet Closing PSpace Closing PersistStore Opening mypizzadatabase Opening PSpace Opening working set Opened existing database Id CustomerId Name Status ------------------------------------------ 1 2 Peter Smith 1 2 5 Janet Gates 1 3 2 Peter Smith 1 4 1 Janet Johnson 0 6 9 Peter Howard 2 8 1 Janet Johnson 1 9 1 Janet Johnson 2 10 10 Peter Howard 3 11 1 Janet Johnson 2 12 2 Peter Smith 3 15 2 Peter Smith 1 16 9 Peter Howard 1 17 2 Peter Smith 1 18 4 Rihanna Johnson 2 19 6 Kate Johnson 2 toppings: {0: (1.58, 'Jalapenos'), 1: (1.42, 'Jalapenos')} Closing WorkingSet Closing PSpace Closing PersistStore Opening mypizzadatabase Opening PSpace Opening working set Opened existing database Id CustomerId Name Status ------------------------------------------ 1 2 Peter Smith 1 2 5 Janet Gates 1 3 2 Peter Smith 1 4 1 Janet Johnson 0 5 12 Peter Gates 3 6 9 Peter Howard 2 8 1 Janet Johnson 1 9 1 Janet Johnson 2 10 10 Peter Howard 3 11 1 Janet Johnson 2 12 2 Peter Smith 3 15 2 Peter Smith 1 16 9 Peter Howard 1 17 2 Peter Smith 1 18 4 Rihanna Johnson 2 19 6 Kate Johnson 2 20 8 Kate Howard 0 22 1 Janet Johnson 1 23 10 Peter Howard 3 25 3 Greg Johnson 0 26 11 Rihanna Gates 2 27 7 John Johnson 1 28 10 Peter Howard 0 29 4 Rihanna Johnson 3 toppings: {0: (1.58, 'Jalapenos'), 1: (1.42, 'Jalapenos'), 2: (1.99, 'Mushrooms')} Closing WorkingSet Closing PSpace Closing PersistStore Replication test mypizzadatabase to myreplicatedpizzadatabase Opening mypizzadatabase Opening PSpace Opening working set Creating server listening on port 3000 num server operations = 16 Opening myreplicatedpizzadatabase Opening PSpace Opening working set Creating client connecting to '127.0.0.1':3000 num client operations = 0 num client operations = 0 Peer : WsipcHostInfo(,,,,,MGuid({00000000-0000-0000-0000-000000000000})) Peer : WsipcHostInfo(127.0.0.1,,,,,MGuid({00000000-0000-0000-0000-000000000000})) num client operations = 0 num client operations = 0 num client operations = 0 num client operations = 0 num client operations = 16 time to sync databases = 0.05200004577636719 seconds TPizzaDeliveryDatabase { Vehicles = { 1 : TVehicle(8,YXS.839) 2 : TVehicle(2,FFU.635) 3 : TVehicle(7,QFX.635) 4 : TVehicle(4,BHP.238) 5 : TVehicle(1,MCI.265) 6 : TVehicle(5,CSD.871) 7 : TVehicle(8,HUB.274) 8 : TVehicle(8,VUG.192) 9 : TVehicle(4,NVF.156) 10 : TVehicle(7,TDQ.610) } VehicleTypes = { 1 : TVehicleType(Ford Fiesta) 2 : TVehicleType(Mazda3) 3 : TVehicleType(Kia Rio) 4 : TVehicleType(Toyota Yaris) 5 : TVehicleType(Honda Civic) 6 : TVehicleType(Mitsubishi Lancer) 7 : TVehicleType(Subaru Impreza) 8 : TVehicleType(Volkswagen Passat) } Employees = { 0 : TEmployee { Address = TAddress { Number = 27 Street = Old Kent Road City = Perth ZipPostCode = 2571 StateProvinceCounty = Alaska Country = England } FirstName = Rihanna LastName = Gates PhoneNumber = 5106 963 004 } 1 : TEmployee { Address = TAddress { Number = 16 Street = Oxford St City = Perth ZipPostCode = 1603 StateProvinceCounty = Alaska Country = England } FirstName = Greg LastName = Howard PhoneNumber = 6043 167 801 } 2 : TEmployee { Address = TAddress { Number = 16 Street = Mayfair St City = Perth ZipPostCode = 5426 StateProvinceCounty = California Country = Australia } FirstName = Greg LastName = Johnson PhoneNumber = 4875 255 681 } } Toppings = { 0 : TTopping { Price = 1.58 Description = Jalapenos } 1 : TTopping { Price = 1.42 Description = Jalapenos } 2 : TTopping { Price = 1.99 Description = Mushrooms } } Customers = { 0 : TCustomer { Address = TAddress { Number = 14 Street = Oxford St City = Perth ZipPostCode = 1025 StateProvinceCounty = California Country = USA } FirstName = Kate LastName = Smith PhoneNumber = 8216 122 701 Email = Rihanna.Johnson@gmail.com DateOfFirstOrder = Feb 15 2016 23:04 PaymentMethod = Cash } 1 : TCustomer { Address = TAddress { Number = 49 Street = Regent St City = Paris ZipPostCode = 1669 StateProvinceCounty = California Country = Australia } FirstName = Janet LastName = Johnson PhoneNumber = 0117 164 824 Email = Rihanna.Matthews@gmail.com DateOfFirstOrder = Aug 20 2016 03:46 PaymentMethod = Cash } 2 : TCustomer { Address = TAddress { Number = 3 Street = Oxford St City = Perth ZipPostCode = 7708 StateProvinceCounty = California Country = Australia } FirstName = Peter LastName = Smith PhoneNumber = 3054 223 635 Email = Kate.Howard@gmail.com DateOfFirstOrder = Sep 04 2017 05:36 PaymentMethod = CreditCard } 3 : TCustomer { Address = TAddress { Number = 26 Street = Oxford St City = Berlin ZipPostCode = 3073 StateProvinceCounty = California Country = Australia } FirstName = Greg LastName = Johnson PhoneNumber = 8776 922 547 Email = Kate.Howard@gmail.com DateOfFirstOrder = Dec 01 2016 00:51 PaymentMethod = CreditCard } 4 : TCustomer { Address = TAddress { Number = 27 Street = Regent St City = Paris ZipPostCode = 7270 StateProvinceCounty = Texas Country = Australia } FirstName = Rihanna LastName = Johnson PhoneNumber = 0588 381 744 Email = John.Matthews@gmail.com DateOfFirstOrder = Apr 06 2017 21:15 PaymentMethod = CreditCard } 5 : TCustomer { Address = TAddress { Number = 4 Street = Regent St City = New York ZipPostCode = 9025 StateProvinceCounty = New South Wales Country = USA } FirstName = Janet LastName = Gates PhoneNumber = 8528 389 151 Email = Kate.Johnson@gmail.com DateOfFirstOrder = Mar 09 2016 18:56 PaymentMethod = CreditCard } 6 : TCustomer { Address = TAddress { Number = 42 Street = Regent St City = Perth ZipPostCode = 6959 StateProvinceCounty = Texas Country = England } FirstName = Kate LastName = Johnson PhoneNumber = 0472 139 741 Email = Greg.Smith@gmail.com DateOfFirstOrder = Oct 27 2016 02:41 PaymentMethod = CreditCard } 7 : TCustomer { Address = TAddress { Number = 40 Street = Regent St City = New York ZipPostCode = 2573 StateProvinceCounty = Texas Country = England } FirstName = John LastName = Johnson PhoneNumber = 5523 452 183 Email = Peter.Howard@gmail.com DateOfFirstOrder = Apr 27 2016 02:14 PaymentMethod = Cash } 8 : TCustomer { Address = TAddress { Number = 41 Street = Old Kent Road City = Perth ZipPostCode = 3850 StateProvinceCounty = Texas Country = USA } FirstName = Kate LastName = Howard PhoneNumber = 3514 973 228 Email = Peter.Matthews@gmail.com DateOfFirstOrder = Dec 18 2017 01:30 PaymentMethod = EftPos } 9 : TCustomer { Address = TAddress { Number = 9 Street = Regent St City = London ZipPostCode = 5896 StateProvinceCounty = Alaska Country = India } FirstName = Peter LastName = Howard PhoneNumber = 2656 601 423 Email = Kate.Matthews@gmail.com DateOfFirstOrder = Dec 16 2016 05:56 PaymentMethod = CreditCard } 10 : TCustomer { Address = TAddress { Number = 8 Street = Oxford St City = Berlin ZipPostCode = 9674 StateProvinceCounty = New South Wales Country = Australia } FirstName = Peter LastName = Howard PhoneNumber = 8485 417 068 Email = Greg.Smith@gmail.com DateOfFirstOrder = Feb 07 2017 02:00 PaymentMethod = CreditCard } 11 : TCustomer { Address = TAddress { Number = 29 Street = Mayfair St City = New York ZipPostCode = 1162 StateProvinceCounty = Texas Country = Australia } FirstName = Rihanna LastName = Gates PhoneNumber = 3218 554 983 Email = Peter.Matthews@gmail.com DateOfFirstOrder = Aug 03 2016 21:13 PaymentMethod = CreditCard } 12 : TCustomer { Address = TAddress { Number = 3 Street = Mayfair St City = New York ZipPostCode = 6800 StateProvinceCounty = California Country = USA } FirstName = Peter LastName = Gates PhoneNumber = 6864 440 503 Email = Janet.Smith@gmail.com DateOfFirstOrder = May 14 2016 15:29 PaymentMethod = CreditCard } } Orders = [00000004.0000000b,00000004.0000000c,00000004.0000000d,00000004.0000000e,00000004.0000000f,00000004.00000010,00000004.00000011,00000004.00000012,00000004.00000013,00000004.00000014,00000004.00000015,00000004.00000016,00000004.00000017,00000004.00000018,00000004.00000019,00000004.0000001a,00000004.0000001b,00000004.0000001c,00000004.0000001d,00000004.0000001e,00000004.0000001f,00000004.00000020,00000004.00000021,00000004.00000022,00000004.00000023,00000004.00000024,00000004.00000025,00000004.00000026,00000004.00000027,00000004.00000028] } Closing client Failure : mcsf = 1 ec = connection has been closed Failure : mcsf = 1 ec = An existing connection was forcibly closed by the remote host Closing Iocp Closing WorkingSet Closing PSpace Closing PersistStore Closing server Closing Iocp Closing WorkingSet Closing PSpace Closing PersistStore