Skip to content

Commit

Permalink
Merge pull request #48 from jgeewax/demo-parser
Browse files Browse the repository at this point in the history
Added DemoRunner and cleaned up demo scripts.
  • Loading branch information
jgeewax committed Feb 25, 2014
2 parents c20cbf1 + 1ebdec6 commit 26d2125
Show file tree
Hide file tree
Showing 11 changed files with 266 additions and 221 deletions.
109 changes: 0 additions & 109 deletions gcloud/datastore/demo.py

This file was deleted.

14 changes: 14 additions & 0 deletions gcloud/datastore/demo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import os
from gcloud import datastore


__all__ = ['get_dataset', 'CLIENT_EMAIL', 'DATASET_ID', 'PRIVATE_KEY_PATH']


CLIENT_EMAIL = '754762820716-gimou6egs2hq1rli7el2t621a1b04t9i@developer.gserviceaccount.com'
DATASET_ID = 'gcloud-datastore-demo'
PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'demo.key')


def get_dataset():
return datastore.get_dataset(DATASET_ID, CLIENT_EMAIL, PRIVATE_KEY_PATH)
5 changes: 5 additions & 0 deletions gcloud/datastore/demo/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from gcloud import demo
from gcloud import datastore


demo.DemoRunner.from_module(datastore).run()
File renamed without changes.
81 changes: 81 additions & 0 deletions gcloud/datastore/demo/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Welcome to the gCloud Datastore Demo! (hit enter)

# We're going to walk through some of the basics...
# Don't worry though. You don't need to do anything, just keep hitting enter...

# Let's start by importing the demo module and getting a dataset:
from gcloud.datastore import demo
dataset = demo.get_dataset()

# Let's create a new entity of type "Thing" and name it 'Toy':
toy = dataset.entity('Thing')
toy.update({'name': 'Toy'})

# Now let's save it to our datastore:
toy.save()

# If we look it up by its key, we should find it...
print dataset.get_entities([toy.key()])

# And we should be able to delete it...
toy.delete()

# Since we deleted it, if we do another lookup it shouldn't be there again:
print dataset.get_entities([toy.key()])

# Now let's try a more advanced query.
# We'll start by look at all Thing entities:
query = dataset.query().kind('Thing')

# Let's look at the first two.
print query.limit(2).fetch()

# Now let's check for Thing entities named 'Computer'
print query.filter('name =', 'Computer').fetch()

# If you want to filter by multiple attributes,
# you can string .filter() calls together.
print query.filter('name =', 'Computer').filter('age =', 10).fetch()

# You can also work inside a transaction.
# (Check the official docs for explanations of what's happening here.)
with dataset.transaction():
print 'Creating and savng an entity...'
thing = dataset.entity('Thing')
thing.key(thing.key().name('foo'))
thing['age'] = 10
thing.save()

print 'Creating and saving another entity...'
thing2 = dataset.entity('Thing')
thing2.key(thing2.key().name('bar'))
thing2['age'] = 15
thing2.save()

print 'Committing the transaction...'

# Now that the transaction is commited, let's delete the entities.
print thing.delete(), thing2.delete()

# To rollback a transaction, just call .rollback()
with dataset.transaction() as t:
thing = dataset.entity('Thing')
thing.key(thing.key().name('another'))
thing.save()
t.rollback()

# Let's check if the entity was actually created:
created = dataset.get_entities([thing.key()])
print 'yes' if created else 'no'

# Remember, a key won't be complete until the transaction is commited.
# That is, while inside the transaction block, thing.key() will be incomplete.
with dataset.transaction():
thing = dataset.entity('Thing')
thing.save()
print thing.key() # This will be partial

print thing.key() # This will be complete

# Now let's delete the entity.
thing.delete()
108 changes: 108 additions & 0 deletions gcloud/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from code import interact
import itertools
import os.path
import sys
import time


class DemoRunner(object):
"""An interactive runner of demo scripts."""

KEYPRESS_DELAY = 0.05
GLOBALS, LOCALS = globals(), locals()
CODE, COMMENT = 'code', 'comment'

def __init__(self, fp):
self.lines = [line.rstrip() for line in fp.readlines()]

@classmethod
def from_module(cls, module):
path = os.path.join(os.path.dirname(module.__file__),
'demo', 'demo.py')

return cls(open(path, 'r'))

def run(self):
line_groups = itertools.groupby(self.lines, self.get_line_type)

for group_type, lines in line_groups:
if group_type == self.COMMENT:
self.write(lines)

elif group_type == self.CODE:
self.code(lines)

interact('(Hit CTRL-D to exit...)', local=self.LOCALS)

def wait(self):
raw_input()

@classmethod
def get_line_type(cls, line):
if line.startswith('#'):
return cls.COMMENT
else:
return cls.CODE

@staticmethod
def get_indent_level(line):
if not line.strip():
return None
return len(line) - len(line.lstrip())

def write(self, lines):
print
print '\n'.join(lines),
self.wait()

def code(self, lines):
code_lines = []

for line in lines:
indent = self.get_indent_level(line)

# If we've completed a block,
# run whatever code was built up in code_lines.
if indent == 0:
self._execute_lines(code_lines)
code_lines = []

# Print the prefix for the line depending on the indentation level.
if indent == 0:
print '>>> ',
elif indent > 0:
print '\n... ',
elif indent is None:
continue

# Break the line into the code section and the comment section.
if '#' in line:
code, comment = line.split('#', 2)
else:
code, comment = line, None

# 'Type' out the comment section.
for char in code.rstrip():
time.sleep(self.KEYPRESS_DELAY)
sys.stdout.write(char)
sys.stdout.flush()

# Print the comment section (not typed out).
if comment:
sys.stdout.write(' # %s' % comment.strip())

# Add the current line to the list of lines to be run in this block.
code_lines.append(line)

# If we had any code built up that wasn't part of a completed block
# (ie, the lines ended with an indented line),
# run that code.
if code_lines:
self._execute_lines(code_lines)

def _execute_lines(self, lines):
if lines:
self.wait()

# Yes, this is crazy unsafe... but it's demo code.
exec('\n'.join(lines), self.GLOBALS, self.LOCALS)
Loading

0 comments on commit 26d2125

Please sign in to comment.