zoom package¶
Subpackages¶
Submodules¶
zoom.alerts module¶
zoom alerts
zoom.apps module¶
zoom.apps
handles requests by locating and calling a suitable app
-
class
zoom.apps.App¶ Bases:
objectA Zoom application
Looks for a method to satisfy the request. If the method is not specified, it falls back to ‘index’. If there is no method on the app object to satisfy the method then it looks for a file in the app directory by that same name. If it finds such a file it looks for the an entrypoint and if found it calls the entrypoint with the parameters the entrypoint expects.
-
process(*route, **data)¶ Process request parameters
-
static(*args, **kwargs)¶
-
-
class
zoom.apps.AppProxy(name, filename, site)¶ Bases:
objectApp Proxy
Contains the various extra supporting parts of an app besides the actual functionality. Apps themselves are simply callables that accept a request and return a response. They can be implemented as simple functions or as something more substantial such as a subclass of the App class above. That’s entirely up to the app developer. The AppProxy takes care of the other parts that an app needs, from it’s location to it’s icon to it’s config files.
-
description¶ Returns the app description
-
get_config(default=None)¶ get the app config
-
get_icon_view()¶
-
keywords¶ Returns the app keywords
generate an app menu
-
method¶ Returns the app callable entry point
-
read_config(section, key, default=None)¶ read app config file values
-
run(request)¶ run the app
-
run_background_jobs()¶
-
templates_paths¶ Calculate Templates Paths
-
title¶ Returns the app title
-
-
class
zoom.apps.NoApp¶ Bases:
objectdefault app used when no app is available
This is mostly used so the helpers remain valid and return reasonable values when no app is available.
-
name= 'none'¶
-
theme= None¶
-
url= ''¶
-
-
zoom.apps.get_default_app_name(site, user)¶ get the default app for the currrent user
-
zoom.apps.get_main_apps(request)¶ Returns a list of the main apps.
Main apps are apps that appear in the main menu, which is usually found at the top of a web site’s pages. The system menu typically includes apps such as home, admin and the apps app.
This list can be defined in the site.ini file in the [apps] section using the key main. A example is provided in the default site.ini file.
-
zoom.apps.get_system_apps(request)¶ Returns a list containing the system apps.
System apps are apps that appear in the system menu, which is usually found at the top left of a web site. The system menu typically includes apps such as login, logout, profile and register.
This list can be defined in the site.ini file in the [apps] section using the key system. A example is provided in the default site.ini file.
-
zoom.apps.handle(request)¶ handle a request
-
zoom.apps.handler(request, next_handler, *rest)¶ Dispatch request to an application
-
zoom.apps.helpers(request)¶ return a dict of app helpers
-
zoom.apps.load_app(site, name)¶ get the location of an app by name
-
zoom.apps.load_module(module, filename)¶ Dynamically load a module
Returns the main menu.
Returns the main menu.
-
zoom.apps.respond(content, request)¶ construct a response
Returns the system menu.
Returns the system menu.
zoom.audit module¶
zoom.audit
zoom.auditing module¶
zoom.auditing
-
zoom.auditing.audit(action, subject1, subject2='', user=None)¶ audit an action
zoom.buckets module¶
buckets
stores blobs of data
-
zoom.buckets.Bucket¶ alias of
zoom.buckets.FileBucket
-
class
zoom.buckets.FileBucket(path, id_factory=<function new_id>)¶ Bases:
objectFile Bucket
FileBucket can store and retreive blobs of binary data. This is useful for storing images or files as attachments where you want to put the binary data somewhere and be able to retreive it later if asked. The id returned is generally stored in a database or somewhere else where it is associated with other entities in the system.
FileBucket stores directly into a folder on the drive of the web server where it has sufficient permissions to do so. This is a potential attack area so be careful to take the appropriate precautions.
The location of the buckets is determined by [data] path setting in the site.ini configuration file.
>>> import zoom >>> site = zoom.sites.Site() >>> path = os.path.join(site.data_path, 'buckets') >>> ids = ['id_%04d' % (9-i) for i in range(10)] >>> new_id = ids.pop
>>> bucket = Bucket(path, new_id) >>> item_id = bucket.put(b'some data') >>> item_id 'id_0000' >>> bucket.get(item_id) b'some data' >>> bucket.exists(item_id) True >>> bucket.delete(item_id) >>> bucket.exists(item_id) False
>>> data = ('%r' % list(range(10))).encode('utf8') >>> item_id = bucket.put(data) >>> item_id 'id_0001' >>> bucket.exists(item_id) True >>> bucket.get(item_id) b'[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]' >>> bucket.delete(item_id)
>>> bucket = Bucket(path, new_id) >>> bucket.put(b'some data') 'id_0002' >>> bucket.put(b'some more data') 'id_0003' >>> sorted(bucket.keys()) ['id_0002', 'id_0003'] >>> for item_id in bucket.keys(): ... bucket.delete(item_id)
-
delete(item_id)¶
-
exists(item_id)¶
-
get(item_id, default=None)¶
-
keys()¶
-
put(item)¶
-
-
zoom.buckets.mkdir_p(path)¶ make a directory path
Makes a directory path. If it already exists then return without doing anything.
-
zoom.buckets.new_id()¶ Generate a random unique id
zoom.cache module¶
zoom.cache - experimental¶
Provides a cache mechanism that can be used to add automatic caching to functions and methods. Handy for caching generated pages.
Use as a function or method decorator.
-
zoom.cache.cached(*keys, **kv)¶ decorator that caches method results
>>> bunch = zoom.utils.Bunch >>> key = 'x','abc' >>> db = zoom.database.setup_test('memory') >>> zoom.system.request = bunch(app=bunch(name='testapp')) >>> zoom.system.site = bunch(db=db) >>> class foo(object): ... def __init__(self, value): ... self.value = value ... @cached(key) ... def get_value(self, param=''): ... return self.value + param >>> clear_cache(key) >>> a = foo('bar') >>> a.get_value() 'bar' >>> a.value = 'bahr' >>> a.get_value() 'bar' >>> clear_cache('get_value', key) >>> a.get_value() 'bahr'
-
zoom.cache.clear_cache(method_name, *keys)¶ Clear all entries from cache
zoom.collect module¶
zoom.collect
-
class
zoom.collect.BasicSearch(collection)¶ Bases:
zoom.collect.RawSearchProvides basic unindexed field aware search capability
-
search(text)¶ Return records that match search text
-
-
class
zoom.collect.Collection(fields, **kwargs)¶ Bases:
objectA collection of Records
-
allows(user, action)¶ Policy rules for shared collection
-
controller¶ alias of
CollectionController
-
fields¶ a fields callable may have data intensive operations, delay execution until it is needed
-
get_columns()¶ Return the collection columns.
-
get_labels()¶ Return the collection labels.
-
handle(route, request)¶ handle a request
-
has_many_records¶
-
locate(key)¶ locate a record
-
order(item)¶ Returns the sort key
-
process(*args, **data)¶ Process method parameters
This style of calling collections is useful when you want to make your collection available as an attribute of a Dispatcher.
-
search(text)¶ Seach the collection for records matching text
-
set_fields(fields)¶ Set the fields to a new value
This can be used for switching fields on the fly, for example when your collection contains entities that are similar enough to be included in the same collection, but that require their own fields.
-
sorter= None¶
-
store= None¶
-
store_type¶ alias of
zoom.store.EntityStore
-
url= None¶
-
verbose= True¶
-
view¶ alias of
CollectionView
-
-
class
zoom.collect.CollectionController(collection)¶ Bases:
zoom.mvc.ControllerPerform operations on a Collection
-
add_image(*_, **kwargs)¶ accept uploaded images and attach them to the record
-
after_delete(record)¶ Things to do after deleting a record
-
after_insert(record)¶ Things to do after inserting a record
-
after_update(record)¶ Things to do after updating a record
-
before_delete(record)¶ Things to do before deleting a record
-
before_insert(record)¶ Things to do before inserting a record
-
before_update(record)¶ Things to do before updating a record
Create a record
-
delete(key, confirm='yes')¶ Delete a record
-
delete_image(key, name)¶ Delete an image field
-
reindex(**kwargs)¶ checks authorization and calls function if authorized
-
remove_image(*_, **kwargs)¶ remove a dropzone image
Save a record
-
-
class
zoom.collect.CollectionModel¶ Bases:
zoom.models.Model-
allows(user, action)¶ Item level policy
-
link¶ Return a link
-
url¶ Return a valid URL
-
-
zoom.collect.CollectionRecord¶ alias of
zoom.collect.CollectionModel
-
class
zoom.collect.CollectionStore(store)¶ Bases:
objectDecorate a Store
Provide additional features to a Store class to make it work with collections.
-
class
zoom.collect.CollectionView(collection)¶ Bases:
zoom.mvc.ViewView a collection
-
clear()¶ Clear the search
-
delete(key, confirm='yes')¶ Show a delete form for a collection record
-
edit(key, **data)¶ Display an edit form for a record
-
get_image(*a, **k)¶ return one of the images from an ImagesField value
-
image(key, name)¶ Respond with image field contents
-
index(q='', *args, **kwargs)¶ collection landing page
-
list_images(key=None, value=None)¶ return list of images for an ImagesField value for this record
-
new(*args, **kwargs)¶ Return a New Item form
-
show(key)¶ Show a record
-
-
class
zoom.collect.IndexedCollectionSearch(collection)¶ Bases:
objectProvides token index for fast lookups
We only provide enough room for tokens up to length 20 only because we have to draw the line somewhere. This may result in some records not being found if the search would have mached on characters beyond the position 20.
-
add(key, values)¶ Add record values to index
-
delete(key)¶ Delete indexed record values
-
max_token_len= 20¶
-
reindex()¶ Rebuild the collection index
This method indexes a few records at a time, in batches. It can be very slow so should be done only by admins or as part of a maintenance cycle in the background. Once the table is indexed this routine should not be needed. It’s mainly provided to index an already existing table or to replace a damaged index.
-
search(text)¶ Return records that match search text
-
update(key, values)¶ Update indexed record values
-
zap()¶ Delete values for all records
-
-
class
zoom.collect.RawSearch(collection)¶ Bases:
objectRaw Data Search
-
add(key, values)¶ Add record values to index
-
delete(key)¶ Delete indexed record values
-
reindex()¶
-
search(text)¶ Return records that match raw search text
-
update(key, values)¶ Update indexed record values
-
-
class
zoom.collect.SilentCollection(fields, **kwargs)¶ Bases:
zoom.collect.CollectionA collection of Records where we do not audit “View” events
-
verbose= False¶
-
-
zoom.collect.as_tokens(values, max_len=20)¶ Return values as a set of tokens
>>> sorted(list(as_tokens(['this is a test', 'other', 'tokentoolongtobecapturedasis']))) ['a', 'is', 'other', 'test', 'this', 'tokentoolongtobecapt']
-
zoom.collect.image_response(name, data)¶ provide an image response based on the file extension
-
zoom.collect.locate(collection, key)¶ locate a record
Authourization policy for a shared collection
zoom.component module¶
zoom.component
Components encapsulate all of the parts that are required to make a component appear on a page. This can include HTML, CSS and Javascript parts and associated libraries.
Components parts are assembled in the way that kind of part needs to be treated. For example HTML parts are simply joined together in order and returned. CSS parts on the other hand are joined together but any duplicate parts are ignored.
When a caller supplies JS or CSS as part of the component being assembled these extra parts are submitted to the system to be included in thier proper place within a response (typically a page template).
The Component object is currently experimental and is intended to be used in future releases.
-
class
zoom.component.Component(*args, **kwargs)¶ Bases:
objectcomponent of a page response
>>> c = Component() >>> c <Component: {'html': []}>
>>> c += 'test' >>> c <Component: {'html': ['test']}>
>>> c += dict(css='mycss') >>> c <Component: {'css': OrderedSet(['mycss']), 'html': ['test']}>
>>> c += dict(css='mycss') >>> c <Component: {'css': OrderedSet(['mycss']), 'html': ['test']}>
>>> c += 'test2' >>> sorted(c.parts.items()) [('css', OrderedSet(['mycss'])), ('html', ['test', 'test2'])]
>>> Component() + 'test1' + 'test2' <Component: {'html': ['test1', 'test2']}>
>>> Component() + 'test1' + dict(css='mycss') <Component: {'css': OrderedSet(['mycss']), 'html': ['test1']}>
>>> Component('test1', Component('test2')) <Component: {'html': ['test1', 'test2']}>
>>> Component( ... Component('test1', css='css1'), ... Component('test2', Component('test3', css='css3')), ... ) <Component: {'css': OrderedSet(['css1', 'css3']), 'html': ['test1', 'test2', 'test3']}>
>>> Component((Component('test1', css='css1'), Component('test2', css='css2'))) <Component: {'css': OrderedSet(['css1', 'css2']), 'html': ['test1', 'test2']}>
>>> Component(Component('test1', css='css1'), Component('test2', css='css2')) <Component: {'css': OrderedSet(['css1', 'css2']), 'html': ['test1', 'test2']}>
>>> zoom.system.parts = Component() >>> c = Component(Component('test1', css='css1'), Component('test2', css='css2')) >>> c.render() 'test1test2'
>>> page2 = \ ... Component() + \ ... '<h1>Title</h1>' + \ ... dict(css='mycss') + \ ... dict(js='myjs') + \ ... 'page body goes here' >>> t = ( ... "<Component: {'css': OrderedSet(['mycss']), " ... "'html': ['<h1>Title</h1>', 'page body goes here'], " ... "'js': OrderedSet(['myjs'])}>" ... ) >>> #print(repr(page2) + '\n' + t) >>> repr(page2) == t True
-
render()¶ renders the component
-
-
zoom.component.component¶ alias of
zoom.component.Component
-
zoom.component.compose(*args, **kwargs)¶ Compose a response - DEPRECATED
-
zoom.component.handler(request, handler, *rest)¶ Component handler
zoom.components module¶
zoom.components
-
class
zoom.components.HeaderBar(model=None, **k)¶ Bases:
zoom.mvc.DynamicViewHeader Bar
A horizontal header bar with a left and right content sections. Useful for section headers that may contain actions or other features.
>>> content = HeaderBar(left='Left Part', right='Right Part') >>> print(content) <div class="header-container"> <div class="header-bar clearfix"> <div class="header-bar-left"> Left Part </div> <div class="header-bar-right"> Right Part </div> </div> </div>
-
left= ''¶
-
right= ''¶
-
-
class
zoom.components.Link(**kwargs)¶ Bases:
object
-
zoom.components.as_actions(items)¶ returns actions
>>> from zoom.context import context as ctx >>> ctx.site = lambda: None >>> ctx.site.url = ''
>>> as_actions(['New']) '<div class="actions"><ul><li><a class="action" href="<dz:request_path>/new" id="new-action">New</a></li></ul></div>'
>>> as_actions(['New','Delete']) '<div class="actions"><ul><li><a class="action" href="<dz:request_path>/delete" id="delete-action">Delete</a></li><li><a class="action" href="<dz:request_path>/new" id="new-action">New</a></li></ul></div>'
-
zoom.components.as_links(items, select=None, filter=None)¶ generate an unordered list of links
>>> as_links(['one', 'two']) '<ul><li><a href="<dz:app_url>">one</a></li><li><a href="<dz:app_url>/two">two</a></li></ul>'
>>> as_links([('one', '/1'), 'two']) '<ul><li><a href="/1">one</a></li><li><a href="<dz:app_url>/two">two</a></li></ul>'
>>> as_links([('uno', 'one', '/1'), 'two'], select=lambda a: a.name=='uno') '<ul><li class="active"><a class="active" href="/1">one</a></li><li><a href="<dz:app_url>/two">two</a></li></ul>'
>>> as_links(['one', 'two'], select=lambda a: a.name=='two') '<ul><li><a href="<dz:app_url>">one</a></li><li class="active"><a class="active" href="<dz:app_url>/two">two</a></li></ul>'
-
zoom.components.dropzone(url, **kwargs)¶ Dropzone component
A basic dropzone component that supports drag and drop uploading of files which are posted to the URL provided.
>>> zoom.system.site = zoom.sites.Site() >>> zoom.system.site.packages = {} >>> zoom.system.request = zoom.utils.Bunch(app=zoom.utils.Bunch(name='hello', packages={})) >>> c = dropzone('/app/files') >>> isinstance(c, zoom.Component) True
-
zoom.components.error(message)¶
-
zoom.components.spinner()¶ A progress spinner
>>> isinstance(spinner(), str) True
-
zoom.components.success(message)¶
-
zoom.components.warning(message)¶
zoom.config module¶
zoom.config
-
class
zoom.config.Config(directory, name, alternate=None)¶ Bases:
objectConfig file parser
The Config class looks in two places for config settings. First it looks in the site.ini file corresponding to the current site. If the value being read is not defined there it falls back to the site.ini in the default site. If the value is not found there then it returns the default value provided in the parameter list.
If no value is found it raises and exception.
>>> from zoom.tools import zoompath >>> config = Config(zoompath('web/sites/default'), 'site.ini') >>> config.get('site', 'name') 'ZOOM'
>>> config.get('site', 'value_missing', 'Got Default!') 'Got Default!'
>>> missing = False >>> try: ... config.get('site', 'value_missing') ... except Exception as e: ... missing = True >>> missing True
>>> config.has_option('site', 'name') True
>>> config.has_option('section_missing', 'name') False
>>> missing = False >>> try: ... config.get('section_missing', 'name') ... except Exception as e: ... missing = True >>> missing True
>>> target = [ ... ('administrator_group', 'administrators'), ... ('default', 'guest'), ... ('developer_group', 'developers') ... ] >>> sorted(config.items('users')) == target True
-
get(section, option, default=None)¶ Return a configuration value
-
has_option(section, option)¶
-
items(section)¶ Return a list of (name, value) tuples for each option in a section.
Both the site config and the default sites config files are read and the results combined to produce the list of tuples.
-
-
zoom.config.get_config(pathname)¶ Read a config file into a Config parser
zoom.context module¶
zoom.context
zoom.cookies module¶
zoom.cookies
The following test is a bit lame because the timestamp makes it tricky to test. Ideally we’d pass in a timer somehow but the cookie module is handling the time calculation so without diving into the innards of the http.cookies module this is what we have right now.
>>> cookie = SimpleCookie()
>>> add_value(cookie, 'name1', 'value1', 60, True)
>>> v = get_value(cookie)
>>> v.startswith('name1=value1; expires=')
True
>>> v.endswith('; Secure')
True
>>> len(v)
77
add a value to a cookie
extract cookies from raw cookie data
get the value portion of a cookie
Cookie handler
>>> request = zoom.utils.Bunch( ... cookies=None, ... session_timeout=1, ... site=zoom.sites.Site(), ... ) >>> response = handler(request, lambda a: zoom.response.Response()) >>> 'zoom_session=' in str(response.cookie) True
generate a new subject ID
construct a session cookie
>>> response = zoom.response.HTMLResponse('my page') >>> set_session_cookie(response, 'sessionid', 'subjectid', 60) >>> 'zoom_session=sessionid' in str(response.cookie) True >>> 'Secure' in str(response.cookie) True
zoom.database module¶
zoom.database
a database that does less
-
class
zoom.database.Database(factory, *args, **keywords)¶ Bases:
objectdatabase object
>>> import sqlite3 >>> db = database('sqlite3', database=':memory:') >>> db('drop table if exists person') >>> db(""" ... create table if not exists person ( ... id integer primary key autoincrement, ... name varchar(100), ... age smallint, ... kids smallint, ... birthdate date, ... salary decimal(8,2) ... ) ... """)
>>> db("insert into person (name, age) values ('Joe',32)") 1
>>> db('select * from person') [(1, 'Joe', 32, None, None, None)]
>>> print(db('select * from person')) id name age kids birthdate salary -- ---- --- ---- --------- ------ 1 Joe 32 None None None
>>> create_person_table = """ ... create table if not exists person ( ... id integer primary key autoincrement, ... name varchar(100), ... age smallint, ... kids smallint, ... birthdate date, ... salary decimal(8,2) ... ) ... """ >>> insert_person = "insert into person (name, age) values (%s, %s)" >>> with database('sqlite3', database=':memory:') as db: ... db(create_person_table) ... db(insert_person, 'Joe', 32) ... db('select * from person') 1 [(1, 'Joe', 32, None, None, None)]
-
database¶ Returns an object containing database parameters
-
debug= False¶
-
execute(command, *args)¶ execute a SQL command with optional parameters
-
execute_many(command, sequence)¶ execute a SQL command with a sequence of parameters
-
classmethod
get_stats()¶ Return the stats to the caller, clearing the list of what is returned
We use a classmethod to support inheritance (over staticmethod)
-
get_tables()¶ get a list of database tables
-
paramstyle= 'pyformat'¶
-
report()¶ produce a SQL log report
-
stats= []¶
-
translate(command, *args)¶ translate sql dialects
The Python db API standard does not attempt to unify parameter passing styles for SQL arguments. This translate routine attempts to do that for each database type. For databases that use the preferred pyformat paramstyle nothing needs to be done. Databases requiring other paramstyles should override this method to translate the command to the required style.
-
use(name)¶ use another database on the same instance
-
-
exception
zoom.database.DatabaseException¶ Bases:
Exceptionexception raised when a database server error occurs
-
exception
zoom.database.EmptyDatabaseException¶ Bases:
Exceptionexception raised when a database is empty
-
class
zoom.database.MySQLDatabase(*args, **kwargs)¶ Bases:
zoom.database.DatabaseMySQL Database
-
connect_string¶ Return a string representation of the connection parameters
-
create_site_tables()¶ create the tables for a site in a mysql server
-
create_test_tables()¶ create the extra test tables
-
delete_test_tables()¶ drop the extra test tables
-
get_column_names(table)¶ return column names for a table
-
get_databases()¶ return database names
-
get_tables()¶ return table names
-
paramstyle= 'pyformat'¶
-
transaction()¶
-
-
class
zoom.database.MySQLDatabaseTransaction(db)¶ Bases:
zoom.database.Database
-
class
zoom.database.MySQLdbDatabase(*args, **kwargs)¶ Bases:
zoom.database.DatabaseMySQLdb Database
deprecated - not avaialble for Python 3.6
use MySQLDatabase instead
-
paramstyle= 'pyformat'¶
-
-
class
zoom.database.Result(cursor, array_size=1000)¶ Bases:
objectdatabase query result
-
first()¶ return first item in result
-
-
class
zoom.database.Sqlite3Database(*args, **kwargs)¶ Bases:
zoom.database.DatabaseSqlite3 Database
-
create_site_tables(filename=None)¶
-
create_test_tables()¶ create the extra test tables
-
delete_test_tables()¶ drop the extra test tables
-
get_tables()¶ return table names
-
paramstyle= 'qmark'¶
-
transaction()¶
-
-
class
zoom.database.Sqlite3DatabaseTransaction(db)¶ Bases:
zoom.database.Database
-
exception
zoom.database.UnknownDatabaseException¶ Bases:
Exceptionexception raised when the database is unknown
-
zoom.database.connect_database(config)¶ establish a database connection
-
zoom.database.database(engine, *args, **kwargs)¶ create a database object
-
zoom.database.handler(request, handler, *rest)¶ Connect a database to the site if specified
-
zoom.database.obfuscate(text)¶ obfuscate text so it is recognizable without divulging it
>>> obfuscate('12345') '1***5'
>>> obfuscate('') ''
-
zoom.database.setup_test(engine=None)¶ create a set of test tables
zoom.exceptions module¶
zoom.exceptions
System wide exceptions
-
exception
zoom.exceptions.DatabaseException¶ Bases:
Exception
-
exception
zoom.exceptions.DatabaseMissingException¶ Bases:
ExceptionDatabase not found
-
exception
zoom.exceptions.PageMissingException¶ Bases:
Exception
-
exception
zoom.exceptions.SiteMissingException¶ Bases:
ExceptionSite directory not found
-
exception
zoom.exceptions.SystemException¶ Bases:
Exception
-
exception
zoom.exceptions.ThemeTemplateMissingException¶ Bases:
ExceptionTheme template missing
-
exception
zoom.exceptions.TypeException¶ Bases:
Exceptionunsupported type
Bases:
Exception
-
exception
zoom.exceptions.ValidException¶ Bases:
Exceptioninvalid record
zoom.fields module¶
zoom.Fields
-
class
zoom.fields.BasicImageField(label='', *validators, **keywords)¶ Bases:
zoom.fields.FieldImage Field
>>> f = BasicImageField('Photo') >>> f.initialize(None) >>> f.value >>> f.name 'photo'
>>> i = BasicImageField('Photo') >>> i.initialize({'photo': b'data blob', 't':12}) >>> i.value b'data blob' >>> i.display_value() '<img alt="Photo" class="image-field-image" src="image?name=photo" />'
-
alt= None¶
-
assign(value)¶ Assign a value to a BasicImageField
-
css_class= 'image-field'¶
-
default= None¶
-
display_value()¶ Display BasicImageField value
BasicImageFields rely on the controller of the current resource providing an image method so that when it wants to display the associted image, it uses a standard img field which calls back to the app to get the image.
-
evaluate()¶ Evaluate a BasicImageField
-
no_image_url= '/static/zoom/images/no_image.png'¶
-
requires_multipart_form()¶ Returns True because images require multipart forms
-
update(**values)¶ Update the ImageField field values
We override the superclass here because we need behaviour specific to how image fields arrive from forms.
-
updated_value= None¶
-
url= None¶
-
value= None¶
-
widget()¶ Returns the BasicImageField widget
BasicImageField use an HTML input of type “file” to collect the filename of the image to be uploaded.
If the field aready has a value, the BasicImageField also provides a view of the current image with a link for deleting the current image. BasicImageField relies on the current controller to provide the delete-image method.
-
-
class
zoom.fields.BirthdateField(label='', *validators, **keywords)¶ Bases:
zoom.fields.DateField-
css_class= 'birthdate_field'¶
-
maxlength= 12¶
-
size= 12¶
-
-
class
zoom.fields.Button(caption='Save', **keywords)¶ Bases:
zoom.fields.FieldButton field.
>>> Button('Save').show() ''
>>> Button('Save').edit() '<input class="button" type="submit" id="save_button" name="save_button" value="Save" />'
>>> Button('Save', cancel='/app/cancel').edit() '<input class="button" type="submit" id="save_button" name="save_button" value="Save" /> <a href="/app/cancel">cancel</a>'
-
as_searchable()¶ Return searchable parts of field
>>> name_field = Field('Name', default='default test') >>> name_field.as_searchable() {'default test'}
>>> name_field = Field('Name', value='test') >>> name_field.as_searchable() {'test'}
>>> name_field = Field('Age', value=10) >>> name_field.as_searchable() {'10'}
>>> name_field = Field('Name', value='こんにちは') >>> name_field.as_searchable() {'こんにちは'}
>>> name_field.visible = False >>> name_field.as_searchable() set()
>>> EmailField('Email', value='test@testco.com').as_searchable() {'test@testco.com'}
-
edit()¶ edit the field
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
show()¶ show the field
-
-
class
zoom.fields.ButtonField(caption='Save', **keywords)¶ Bases:
zoom.fields.ButtonButton field.
>>> ButtonField('Save').show() ''
>>> print(ButtonField('Save').edit()) <div class="field"> <div class="field_label"> </div> <div class="field_edit"><input class="button" type="submit" id="save_button" name="save_button" value="Save" /></div> </div>
-
edit()¶ edit the field
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
-
class
zoom.fields.Buttons(captions=['Save'], **keywords)¶ Bases:
zoom.fields.Field>>> Buttons(['Save','Publish','Delete']).show() ''
>>> Buttons(['Save','Publish']).widget() '<input class="button" type="submit" id="save_button" name="save_button" value="Save" /> <input class="button" type="submit" id="publish_button" name="publish_button" value="Publish" />'
>>> Buttons(['Save'], cancel='/app/id').widget() '<input class="button" type="submit" id="save_button" name="save_button" value="Save" /> <a href="/app/id">cancel</a>'
-
as_searchable()¶ Return searchable parts of field
>>> name_field = Field('Name', default='default test') >>> name_field.as_searchable() {'default test'}
>>> name_field = Field('Name', value='test') >>> name_field.as_searchable() {'test'}
>>> name_field = Field('Age', value=10) >>> name_field.as_searchable() {'10'}
>>> name_field = Field('Name', value='こんにちは') >>> name_field.as_searchable() {'こんにちは'}
>>> name_field.visible = False >>> name_field.as_searchable() set()
>>> EmailField('Email', value='test@testco.com').as_searchable() {'test@testco.com'}
-
edit()¶ edit the field
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
show()¶ show the field
-
widget()¶ returns the field widget
-
-
class
zoom.fields.ButtonsField(captions=['Save'], **keywords)¶ Bases:
zoom.fields.ButtonsButtons field.
>>> ButtonsField('Save').show() ''
>>> print(ButtonsField(['Save','Publish']).edit()) <div class="field"> <div class="field_label"> </div> <div class="field_edit"><input class="button" type="submit" id="save_button" name="save_button" value="Save" /> <input class="button" type="submit" id="publish_button" name="publish_button" value="Publish" /></div> </div>
-
edit()¶ edit the field
-
-
class
zoom.fields.CheckboxField(label='', *validators, **keywords)¶ Bases:
zoom.fields.TextFieldCheckbox Field
>>> CheckboxField('Done').display_value() 'no'
>>> CheckboxField('Done', value=True).display_value() 'yes'
>>> CheckboxField('Done').widget() '<input class="checkbox_field" type="checkbox" id="done" name="done" />'
>>> f = CheckboxField('Done', value=True) >>> f.widget() '<input checked class="checkbox_field" type="checkbox" id="done" name="done" />' >>> f.validate(**{'DONE': 'on'}) True >>> f.evaluate() {'done': True}
>>> f = CheckboxField('Done') >>> f.widget() '<input class="checkbox_field" type="checkbox" id="done" name="done" />' >>> f.evaluate() {'done': None} >>> f.validate(**{}) True >>> f.evaluate() {'done': None}
>>> f = CheckboxField('Done') >>> f.widget() '<input class="checkbox_field" type="checkbox" id="done" name="done" />' >>> f.evaluate() {'done': None} >>> f.validate(**{'DONE': 'on'}) True >>> f.evaluate() {'done': True}
>>> f = CheckboxField('Done', options=['yes','no'], value=False) >>> f <Field name='done' value=False> >>> f.validate(**{'done': True}) True >>> f <Field name='done' value=True> >>> f.validate(**{'DoNE': False}) True >>> f <Field name='done' value=False> >>> f.validate(**{'done': 'on'}) True >>> f <Field name='done' value='on'> >>> f.display_value() 'yes' >>> f.evaluate() {'done': True}
>>> f = CheckboxField('Done', options=['yep','nope'], default=True) >>> f.evaluate() {'done': True} >>> f.widget() '<input checked class="checkbox_field" type="checkbox" id="done" name="done" />'
>>> f.update(other='test') >>> f.widget() '<input class="checkbox_field" type="checkbox" id="done" name="done" />'
>>> f = CheckboxField('Done', options=['yep','nope']) >>> f.evaluate() {'done': None} >>> f.validate(**{'OTHERDATA': 'some value'}) True >>> f.evaluate() {'done': False}
>>> CheckboxField('Done', options=['yep','nope']).display_value() 'nope'
>>> CheckboxField('Done', options=['yep','nope'], default=False).display_value() 'nope'
>>> CheckboxField('Done', options=['yep','nope'], default=True).display_value() 'nope'
>>> CheckboxField('Done', options=['yep','nope'], default=True).evaluate() {'done': True}
>>> CheckboxField('Done', options=['yep','nope'], default=True, value=False).display_value() 'nope'
>>> CheckboxField('Done', options=['yep','nope'], value=True).display_value() 'yep'
>>> CheckboxField('Done', options=['yep','nope'], value=False).evaluate() {'done': False}
>>> CheckboxField('Done', options=['yep','nope'], value='True').value 'True'
-
assign(value)¶ assign a value to the field
-
default= None¶
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
options= ['yes', 'no']¶
-
show()¶ show the field
-
truthy= [True, 'True', 'yes', 'on']¶
-
update(**values)¶ Update field.
>>> name_field = Field('Name', value='Sam') >>> name_field.value 'Sam' >>> name_field.update(city='Vancouver') >>> name_field.value 'Sam' >>> name_field.update(name='Joe') >>> name_field.value 'Joe' >>> name_field.update(NaMe='Adam') >>> name_field.value 'Adam'
-
value= None¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.CheckboxesField(label='', *validators, **keywords)¶ Bases:
zoom.fields.FieldCheckboxes field.
>>> cb = CheckboxesField('Select', value='One', values=['One','Two','Three'], hint='test hint') >>> print(cb.widget()) <ul class="checkbox_field"> <li><input checked class="checkbox_field" type="checkbox" id="select" name="select" value="One" /><div>One</div></li> <li><input class="checkbox_field" type="checkbox" id="select" name="select" value="Two" /><div>Two</div></li> <li><input class="checkbox_field" type="checkbox" id="select" name="select" value="Three" /><div>Three</div></li> </ul>
-
show()¶ show the field
-
widget()¶ returns the field widget
-
-
class
zoom.fields.ChosenMultiselectField(*a, **k)¶ Bases:
zoom.fields.MultiselectFieldChosen Multiselect field.
>>> from zoom.component import Component >>> f = ChosenMultiselectField('Choose', options=['One','Two','Three'], hint='test hint') >>> print(f.widget()) <select data-placeholder="Select Choose" multiple="multiple" class="chosen" name="choose" id="choose"> <option value="One">One</option> <option value="Two">Two</option> <option value="Three">Three</option> </select>
>>> f = ChosenMultiselectField('Choose', options=['One','Two','Three'], hint='test hint', placeholder='my placeholder') >>> print(f.widget()) <select data-placeholder="my placeholder" multiple="multiple" class="chosen" name="choose" id="choose"> <option value="One">One</option> <option value="Two">Two</option> <option value="Three">Three</option> </select>
>>> f = ChosenMultiselectField('Choose', value='2', options=['One', 'Two', 'Three']) >>> print(f.widget()) <select data-placeholder="Select Choose" multiple="multiple" class="chosen" name="choose" id="choose"> <option value="One">One</option> <option value="Two">Two</option> <option value="Three">Three</option> </select>
>>> f = ChosenMultiselectField('Choose', value='Two', options=['One', 'Two', 'Three']) >>> print(f.widget()) <select data-placeholder="Select Choose" multiple="multiple" class="chosen" name="choose" id="choose"> <option value="One">One</option> <option value="Two" selected>Two</option> <option value="Three">Three</option> </select>
>>> f = ChosenMultiselectField('Choose', value='2', options=[('One', '1'), ('Two', '2'), ('Three', '3')]) >>> print(f.widget()) <select data-placeholder="Select Choose" multiple="multiple" class="chosen" name="choose" id="choose"> <option value="1">One</option> <option value="2" selected>Two</option> <option value="3">Three</option> </select>
>>> f = ChosenMultiselectField('Choose', value='Two', options=[('One', '1'), ('Two', '2'), ('Three', '3')]) >>> print(f.widget()) <select data-placeholder="Select Choose" multiple="multiple" class="chosen" name="choose" id="choose"> <option value="1">One</option> <option value="2" selected>Two</option> <option value="3">Three</option> </select>
>>> f = ChosenMultiselectField('Choose', value=['Two', 3], options=[('One', '1'), ('Two', '2'), ('Three', '3')]) >>> print(f.widget()) <select data-placeholder="Select Choose" multiple="multiple" class="chosen" name="choose" id="choose"> <option value="1">One</option> <option value="2" selected>Two</option> <option value="3" selected>Three</option> </select>
>>> f = ChosenMultiselectField('Choose', value=['One', 3], options=[('One', 1), ('Two', 2), ('Three', 3)]) >>> print(f.widget()) <select data-placeholder="Select Choose" multiple="multiple" class="chosen" name="choose" id="choose"> <option value="1" selected>One</option> <option value="2">Two</option> <option value="3" selected>Three</option> </select>
-
css_class= 'chosen'¶
-
select_layout= '<select data-placeholder="{}" multiple="multiple" class="{}" name="{}" id="{}">\n'¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.ChosenSelectField(*a, **k)¶ Bases:
zoom.fields.PulldownField-
css_class= 'chosen'¶
-
libs= ['/static/zoom/chosen/chosen.jquery.js']¶
-
select_layout= '<select data-placeholder="{place}" class="{classed}" name="{name}" id="{name}">\n'¶
-
styles= ['/static/zoom/chosen/chosen.css']¶
-
-
class
zoom.fields.DataURIAttachmentsField(label='', *validators, **keywords)¶ Bases:
zoom.fields.FieldAn Attachments field - DEPRECATED
this field stores the data within the database this field uses dropzone.js heavily the results are shown via a Data URI
this field stores the data within the database this field uses dropzone.js heavily the results are shown via a Data URI multiple dropzones supported by assuming you will bind ONLY one to the form
and the others to an element via the “selector” configuration optionTODO: with multiple dropzones, support submit when the master/form is empty This field makes some assumptions about what you want todo:
- this field uses dropzone.js
- the field expects you want todo a native form submission (once vs. multiple ajax calls)
- this field stores the data within the database
- the results are shown via a Data URI which is not always optimal
- it looks like dropzone.js only adds the form fields when dropzone is bound
- to a form (i.e. binding to dropzone within a form skips this - assumes xhr)
- due to assumption to mimic native form, the data makes round trips to/from server
>>> icon = DataURIAttachmentsField('Icon') >>> icon.requires_multipart_form() True >>> icon.assign(None) >>> assert icon.value == icon.default >>> class PsuedoFile(object): ... @property ... def name(self): ... return 'field_name' ... @property ... def filename(self): ... return 'filename.png' ... @property ... def value(self): ... return b'' >>> icon.assign([PsuedoFile(), PsuedoFile()]) >>> assert isinstance(icon.value, list) >>> icon.value [['field_name', ['filename.png', '']], ['field_name', ['filename.png', '']]]
-
as_searchable()¶ Return searchable parts of field
>>> name_field = Field('Name', default='default test') >>> name_field.as_searchable() {'default test'}
>>> name_field = Field('Name', value='test') >>> name_field.as_searchable() {'test'}
>>> name_field = Field('Age', value=10) >>> name_field.as_searchable() {'10'}
>>> name_field = Field('Name', value='こんにちは') >>> name_field.as_searchable() {'こんにちは'}
>>> name_field.visible = False >>> name_field.as_searchable() set()
>>> EmailField('Email', value='test@testco.com').as_searchable() {'test@testco.com'}
-
assign(value={})¶ assign a value to the field
-
capitalize¶ return the field id capitalized
-
classed= 'dropzone nojs'¶
-
configuration¶ configure the Dropzone .js assets
this field is designed to work within an existing/native form. As such, we turn off the auto processing of the queue (AJAX push) to bulk send the form all at once.
-
css= '<link href="/static/zoom/dropzone/dropzone.min.css" rel="stylesheet" type="text/css" />'¶
-
datauri(image)¶ return the data URI string
-
default= []¶
-
display_value()¶ web based display view of the field
-
edit()¶ edit the field
-
maximum_files= 5¶
-
mockFile¶ return the saved file - this is a .js call and injected into the .js
-
no_image_url= 'https://placehold.it/350x150'¶
-
requires_multipart_form()¶ return True if a multipart form is required for this field
-
script= ['<script type="text/javascript" src="/static/zoom/dropzone/dropzone.min.js"></script>', '<script type="text/javascript">Dropzone.autoDiscover = false;</script>']¶
-
selector= '#zoom_form'¶
-
update(**values)¶ update the field
-
widget()¶ return the dropzone widget
-
class
zoom.fields.DataURIImageField(label='', *validators, **keywords)¶ Bases:
zoom.fields.DataURIAttachmentsFieldAn Attachments field making use of a Data URI where we limit to a single file
-
maximum_files= 1¶
-
-
zoom.fields.DataURIImagesField¶ alias of
zoom.fields.DataURIAttachmentsField
-
class
zoom.fields.DateField(label='', *validators, **keywords)¶ Bases:
zoom.fields.FieldDate Field
DatField values can be either actual dates (datetime.date) or string representations of dates. Values coming from databases or from code will typically be dates, while dates coming in from forms will typically be strings.
DateFields always evaluate to date types and always display as string representations of those dates formatted according to the specified format.
>>> DateField("Start Date").widget() '<input class="date_field" type="text" id="start_date" maxlength="12" name="start_date" value="" />'
>>> from datetime import date, datetime
>>> f = DateField("Start Date") >>> f.display_value() '' >>> f.assign('') >>> f.display_value() ''
>>> f = DateField("Start Date", value=date(2015,1,1)) >>> f.value datetime.date(2015, 1, 1)
>>> f = DateField("Start Date", value=datetime(2015,1,1)) >>> f.value datetime.datetime(2015, 1, 1, 0, 0) >>> f.evaluate() {'start_date': datetime.date(2015, 1, 1)}
>>> f.assign('Jan 01, 2015') # forms assign with strings >>> f.display_value() 'Jan 01, 2015' >>> f.evaluate() {'start_date': datetime.date(2015, 1, 1)}
>>> f.assign('2015-12-31') # forms assign with strings >>> f.display_value() 'Dec 31, 2015' >>> f.evaluate() {'start_date': datetime.date(2015, 12, 31)}
>>> f.assign(date(2015,1,31)) >>> f.display_value() 'Jan 31, 2015'
>>> f.assign('TTT 01, 2015') >>> f.display_value() 'TTT 01, 2015' >>> failed = False >>> try: ... f.evaluate() ... except ValueError: ... failed = True >>> failed True
>>> DateField("Start Date", value=date(2015,1,1)).widget() '<input class="date_field" type="text" id="start_date" maxlength="12" name="start_date" value="Jan 01, 2015" />'
-
alt_input_format= '%Y-%m-%d'¶
-
as_searchable()¶ Return searchable parts of field
>>> from datetime import date, datetime >>> f = DateField("Start Date")
>>> f.assign(date(2015,1,31)) >>> f.display_value() 'Jan 31, 2015' >>> f.as_searchable() {'2015-01-31 01-31-2015 Saturday January 31 2015'}
-
css_class= 'date_field'¶
-
default= None¶
-
display_value(alt_format=None)¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
format= '%b %d, %Y'¶
-
input_format= '%b %d, %Y'¶
-
max= None¶
-
maxlength= 12¶
-
min= None¶
-
search_fmt= '{:%Y-%m-%d %m-%d-%Y %A %B %-d %Y}'¶
-
show()¶ show the field
-
size= 12¶
-
validators= [<zoom.validators.DateValidator object>]¶
-
value= None¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.DecimalField(label='', *validators, **keywords)¶ Bases:
zoom.fields.NumberFieldDecimal Field
>>> DecimalField('Count',value="2.1").display_value() '2.1'
>>> DecimalField('Count', value=Decimal('10.24')).widget() '<input class="decimal_field" type="text" id="count" maxlength="10" name="count" size="10" value="10.24" />'
>>> DecimalField('Count').widget() '<input class="decimal_field" type="text" id="count" maxlength="10" name="count" size="10" value="" />'
>>> n = DecimalField('Size') >>> n.assign('2.1') >>> n.value Decimal('2.1')
>>> n.assign(0) >>> n.value Decimal('0')
>>> n.assign('0') >>> n.value Decimal('0')
>>> n.assign('2.1') >>> n.value Decimal('2.1')
>>> n.assign('') >>> n.evaluate() {'size': None}
>>> DecimalField('Hours').evaluate() {'hours': 0}
-
converter¶ alias of
decimal.Decimal
-
css_class= 'decimal_field'¶
-
maxlength= 10¶
-
size= 10¶
-
value= 0¶
-
-
class
zoom.fields.EditField(label='', *validators, **keywords)¶ Bases:
zoom.fields.MemoFieldLarge textedit.
>>> EditField('Notes').widget() '<textarea class="edit_field" height="6" id="notes" name="notes" size="10"></textarea>'
-
css_class= 'edit_field'¶
-
edit()¶ edit the field
-
height= 6¶
-
size= 10¶
-
value= ''¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.EmailField(label, *validators, **keywords)¶ Bases:
zoom.fields.TextFieldEmail field
>>> EmailField('Email').widget() '<input class="text_field" id="email" maxlength="60" name="email" size="30" type="text" value="" />'
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
maxlength= 60¶
-
size= 30¶
-
-
class
zoom.fields.Field(label='', *validators, **keywords)¶ Bases:
objectField base class
-
as_dict()¶
-
as_searchable()¶ Return searchable parts of field
>>> name_field = Field('Name', default='default test') >>> name_field.as_searchable() {'default test'}
>>> name_field = Field('Name', value='test') >>> name_field.as_searchable() {'test'}
>>> name_field = Field('Age', value=10) >>> name_field.as_searchable() {'10'}
>>> name_field = Field('Name', value='こんにちは') >>> name_field.as_searchable() {'こんにちは'}
>>> name_field.visible = False >>> name_field.as_searchable() set()
>>> EmailField('Email', value='test@testco.com').as_searchable() {'test@testco.com'}
-
assign(value)¶ assign a value to the field
-
browse= True¶
-
clean(*args, **kwargs)¶ Update (sometimes ammended values) and validate a field.
>>> from zoom.validators import Cleaner, required >>> upper = Cleaner(str.upper) >>> name_field = Field('Name', upper, required) >>> name_field.clean(city='Vancouver') False
>>> name_field.validate(name='Vancouver') True >>> name_field.value 'Vancouver'
>>> name_field.clean(name='Vancouver') True >>> name_field.value 'VANCOUVER'
-
default= ''¶
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
edit()¶ edit the field
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
field_layout= <zoom.fields.FieldLayout object>¶
-
hint= ''¶
-
initialize(*a, **k)¶ Initialize field value.
Set field value according to value passed in as parameter or if there is not value for this field, set it to the default value for the field.
>>> f = Field('test', default='zero')
>>> f.initialize(test='one') >>> f.value 'one'
>>> r = dict(test='two') >>> f.initialize(r) >>> f.value 'two'
>>> r = dict(not_test='two') >>> f.initialize(r) >>> f.value 'zero'
-
label= ''¶
-
layout(label, content, edit=True)¶
-
msg= ''¶
-
options= []¶
-
placeholder= None¶
-
render_hint()¶ Render hint.
>>> name_field = Field('Name', hint='Full name') >>> name_field.render_hint() '<span class="hint">Full name</span>'
-
render_msg()¶ Render validation error message.
>>> from zoom.validators import required >>> name_field = Field('Name', required) >>> name_field.update(NAME='') >>> name_field.valid() False >>> name_field.render_msg() '<span class="wrong">required</span>'
-
requires_multipart_form()¶ return True if a multipart form is required for this field
-
show()¶ show the field
-
update(**values)¶ Update field.
>>> name_field = Field('Name', value='Sam') >>> name_field.value 'Sam' >>> name_field.update(city='Vancouver') >>> name_field.value 'Sam' >>> name_field.update(name='Joe') >>> name_field.value 'Joe' >>> name_field.update(NaMe='Adam') >>> name_field.value 'Adam'
-
valid()¶ Validate field value.
>>> from zoom.validators import required >>> name_field = Field('Name',required) >>> name_field.update(NAME='Fred') >>> name_field.valid() True
>>> name_field.update(NAME='') >>> name_field.valid() False >>> name_field.msg 'required'
-
validate(*a, **k)¶ Update and validate a field.
>>> from zoom.validators import required >>> name_field = Field('Name',required) >>> name_field.validate(city='Vancouver') False
>>> name_field.validate(name='Fred') True >>> name_field.value 'Fred'
-
validators= []¶
-
value= ''¶
-
visible= True¶
-
widget()¶ returns the field widget
-
wrap= ' nowrap'¶
-
-
class
zoom.fields.FieldIterator(fields)¶ Bases:
object
-
class
zoom.fields.FieldLayout¶ Bases:
object-
edit(field)¶
-
field_template= '<div class="field">\n <div class="field_label">{label}</div>\n <div class="field_{mode}">{content}</div>\n</div>\n'¶
-
hint_template= '<table class="transparent">\n <tr>\n <td{wrap}>{widget}</td>\n <td>\n <div class="hint">{hints}</div>\n </td>\n </tr>\n</table>\n'¶
-
-
class
zoom.fields.Fields(*args)¶ Bases:
objectA collection of field objects.
>>> fields = Fields(TextField('Name'), PhoneField('Phone')) >>> print(fields.edit()) <div class="field"> <div class="field_label">Name</div> <div class="field_edit"><table class="transparent"> <tr> <td nowrap><input class="text_field" id="name" maxlength="40" name="name" size="40" type="text" value="" /></td> <td> <div class="hint"></div> </td> </tr> </table> </div> </div> <div class="field"> <div class="field_label">Phone</div> <div class="field_edit"><table class="transparent"> <tr> <td nowrap><input class="text_field" id="phone" name="phone" size="20" type="text" value="" /></td> <td> <div class="hint"></div> </td> </tr> </table> </div> </div>
>>> from zoom.utils import pp >>> fields = Fields(TextField('Name', value='Amy'), PhoneField('Phone', value='2234567890')) >>> pp(fields.as_dict()) { 'name' ...........: <Field name='name' value='Amy'> 'phone' ..........: <Field name='phone' value='2234567890'> }
>>> fields = Fields(TextField('Name'), MemoField('Notes')) >>> fields.validate({'name': 'Test'}) True >>> d = fields.evaluate() >>> d['name'] 'Test'
>>> len(d['notes']) 0 >>> fields.validate({'notes': 'here are some notes'}) True >>> d = fields.evaluate() >>> len(d['notes']) 19
>>> pp(fields.as_dict()) { 'name' ...........: <Field name='name' value='Test'> 'notes' ..........: <Field name='notes' value='here are some notes'> }
>>> record = dict(name='Adam', notes='no text here') >>> pp(record) { "name": "Adam", "notes": "no text here" }
>>> record.update(fields) >>> record['name'] 'Test' >>> len(record['notes']) 19
-
as_dict()¶
-
as_list()¶ >>> fields = Fields(TextField('Name', value='Amy'), PhoneField('Phone', value='2234567890')) >>> fields.as_list() [<Field name='name' value='Amy'>, <Field name='phone' value='2234567890'>]
-
as_searchable()¶ Return fields as a set of searchable items
>>> from zoom.utils import pp >>> fields = Fields( ... TextField('Name', value='Amy'), ... PhoneField('Phone', value='2234567890'), ... DateField('Birthdate', value=datetime.date(1980,1,1)), ... MultiselectField( ... 'Type', ... value=['One','dos'], ... options=[('One','uno'),('Two','dos')] ... ) ... )
>>> pp(sorted(map(str, fields.as_searchable()))) [ "1980-01-01 01-01-1980 Tuesday January 1 1980", "2234567890", "Amy", "One", "Two" ]
-
clean(*args, **kwargs)¶
-
display_value()¶ >>> from zoom.utils import pp >>> fields = Fields(TextField('Name', value='Amy'), PhoneField('Phone', value='2234567890')) >>> pp(fields.display_value()) { "name": "Amy", "phone": "2234567890" }
-
edit()¶
-
evaluate()¶ >>> from zoom.utils import pp >>> fields = Fields(TextField('Name', value='Amy'), PhoneField('Phone', value='2234567890')) >>> pp(fields.evaluate()) { "name": "Amy", "phone": "2234567890" }
-
initialize(*a, **k)¶ Initialize Field values
>>> from zoom.utils import pp >>> fields = Fields(TextField('Name', value='Amy'), PhoneField('Phone', value='2234567890')) >>> fields.initialize(phone='987654321') >>> pp(fields.as_dict()) { 'name' ...........: <Field name='name' value=''> 'phone' ..........: <Field name='phone' value='987654321'> }
-
requires_multipart_form()¶
-
show()¶
-
update(*a, **k)¶ Update Field values
>>> from zoom.utils import pp >>> fields = Fields(TextField('Name', value='Amy'), PhoneField('Phone', value='2234567890')) >>> fields.update(phone='987654321') >>> pp(fields.as_dict()) { 'name' ...........: <Field name='name' value='Amy'> 'phone' ..........: <Field name='phone' value='987654321'> }
-
valid()¶
-
validate(*a, **k)¶
-
-
class
zoom.fields.Fieldset(label, fields, hint='')¶ Bases:
zoom.fields.FieldsA collection of field objects with an associated label.
>>> print(Section('Personal',[TextField('Name',value='Joe')]).show()) <h2>Personal</h2> <div class="field"> <div class="field_label">Name</div> <div class="field_show">Joe</div> </div>
-
edit()¶
-
render_hint()¶
-
show()¶
-
-
class
zoom.fields.FileField(label='', *validators, **keywords)¶ Bases:
zoom.fields.TextField>>> FileField('Document').widget() '<input class="file_field" id="document" name="document" type="file" value="None" />'
-
assign(value)¶ assign a value to the field
-
css_class= 'file_field'¶
-
default= 'None'¶
-
requires_multipart_form()¶ return True if a multipart form is required for this field
-
value= 'None'¶
-
-
class
zoom.fields.FloatField(label='', *validators, **keywords)¶ Bases:
zoom.fields.NumberFieldFloat Field
>>> FloatField('Count', value=2.1).display_value() '2.1'
>>> FloatField('Count').widget() '<input class="float_field" type="text" id="count" maxlength="10" name="count" size="10" value="" />'
>>> n = FloatField('Size') >>> n.assign(2.1) >>> n.value 2.1
>>> n.assign(0) >>> n.value 0.0
>>> n.assign('0') >>> n.value 0.0
>>> n.assign('2.1') >>> n.value 2.1
>>> n.assign('') >>> n.evaluate() {'size': None}
-
converter¶ alias of
builtins.float
-
css_class= 'float_field'¶
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
maxlength= 10¶
-
size= 10¶
-
value= 0¶
-
-
class
zoom.fields.Hidden(label='', *validators, **keywords)¶ Bases:
zoom.fields.FieldHidden field.
>>> Hidden('Hide Me').show() ''
>>> Hidden('Hide Me', value='test').edit() '<input type="hidden" id="hide_me" name="hide_me" value="test" />'
-
edit()¶ edit the field
-
visible= False¶
-
-
zoom.fields.ImageField¶ alias of
zoom.fields.BasicImageField
-
class
zoom.fields.ImagesField(label='', *validators, **keywords)¶ Bases:
zoom.fields.FieldDisplay a drag and drop multiple image storage field
this field is experimental - may change for a while yet
>>> ImagesField('Photo') <Field name='photo' value=None>
-
default= '0f3c648630874d50adb45308a5300021'¶
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
show()¶ show the images field
-
url= ''¶
-
value= None¶
-
widget()¶ returns the field widget
-
wrap= ''¶
-
-
class
zoom.fields.IntegerField(label='', *validators, **keywords)¶ Bases:
zoom.fields.TextFieldInteger Field
>>> IntegerField('Count', value=2).display_value() '2'
>>> IntegerField('Count').widget() '<input class="number_field" id="count" maxlength="10" name="count" size="10" type="text" value="" />'
>>> n = IntegerField('Size') >>> n.assign('2') >>> n.value 2 >>> n.evaluate() {'size': 2}
>>> n = IntegerField('Size', units='meters') >>> n.assign('22234') >>> n.value 22234 >>> n.display_value() '22,234 meters'
>>> n.assign('') >>> n.evaluate() {'size': ''}
-
as_searchable()¶ Return searchable parts of field
>>> name_field = Field('Name', default='default test') >>> name_field.as_searchable() {'default test'}
>>> name_field = Field('Name', value='test') >>> name_field.as_searchable() {'test'}
>>> name_field = Field('Age', value=10) >>> name_field.as_searchable() {'10'}
>>> name_field = Field('Name', value='こんにちは') >>> name_field.as_searchable() {'こんにちは'}
>>> name_field.visible = False >>> name_field.as_searchable() set()
>>> EmailField('Email', value='test@testco.com').as_searchable() {'test@testco.com'}
-
assign(value)¶ assign a value to the field
-
css_class= 'number_field'¶
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
maxlength= 10¶
-
size= 10¶
-
units= ''¶
-
value= 0¶
-
-
class
zoom.fields.MarkdownEditField(label='', *validators, **keywords)¶ Bases:
zoom.fields.EditFieldLarge markdown edit field
>>> MarkdownEditField('Notes').widget() '<textarea class="edit_field" height="6" id="notes" name="notes" size="10"></textarea>'
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
-
class
zoom.fields.MarkdownField(label='', *validators, **keywords)¶ Bases:
zoom.fields.MemoField>>> f = MarkdownField('Notes', value='test **one** 23') >>> f.display_value() '<p>test <strong>one</strong> 23</p>'
>>> target = ( ... '<div class="field">\n' ... ' <div class="field_label">Notes</div>\n' ... ' <div class="field_edit"><textarea class="memo_field" cols="60" id="notes" name="notes" rows="6" size="10">test **one** 23</textarea></div>\n' ... '</div>\n' ... ) >>> f.edit() == target True
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
-
class
zoom.fields.MarkdownText(text)¶ Bases:
objecta markdown text object that can be placed in a form like a field
>>> f = MarkdownText('One **bold** statement') >>> f.edit() '<p>One <strong>bold</strong> statement</p>'
-
edit()¶ display the markdown as text, even in edit mode
-
evaluate()¶ return the value
Not a field so doesn’t return a value
-
-
class
zoom.fields.MemoField(label='', *validators, **keywords)¶ Bases:
zoom.fields.FieldEdit a paragraph of text.
>>> print(MemoField('Notes').widget()) <textarea class="memo_field" cols="60" id="notes" name="notes" rows="6" size="10"></textarea>
-
cols= 60¶
-
css_class= 'memo_field'¶
-
edit()¶ edit the field
-
height= 6¶
-
rows= 6¶
-
show()¶ show the field
-
size= 10¶
-
value= ''¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.MoneyField(label='', *validators, **keywords)¶ Bases:
zoom.fields.DecimalFieldMoney Field
>>> f = MoneyField("Amount") >>> f.widget() '<div class="input-group"><span class="input-group-addon">$</span><input class="decimal_field" type="text" id="amount" maxlength="10" name="amount" size="10" value="" /></div>' >>> f.display_value() '$0.00' >>> f.assign(Decimal(1000)) >>> f.display_value() '$1,000.00'
>>> from platform import system >>> l = system()=='Windows' and 'eng' or 'en_GB.utf8' >>> f = MoneyField("Amount", locale=l) >>> f.display_value() '\xa30.00'
>>> f.assign(Decimal(1000)) >>> f.display_value() '\xa31,000.00' >>> print(f.show()) <div class="field"> <div class="field_label">Amount</div> <div class="field_show">£1,000.00</div> </div>
>>> f.widget() '<div class="input-group"><span class="input-group-addon">£</span><input class="decimal_field" type="text" id="amount" maxlength="10" name="amount" size="10" value="1000" /></div>' >>> f.units = 'per month' >>> f.display_value() '\xa31,000.00 per month' >>> f.units = '' >>> f.display_value() '\xa31,000.00' >>> f.assign('') >>> f.display_value() '' >>> f.assign('0') >>> f.display_value() '\xa30.00' >>> f.assign(' ') >>> f.display_value() ''
>>> f = MoneyField("Amount", placeholder='0') >>> f.widget() '<div class="input-group"><span class="input-group-addon">$</span><input class="decimal_field" type="text" id="amount" maxlength="10" name="amount" placeholder="0" size="10" value="" /></div>'
>>> f = MoneyField("Amount", symbol='£', value=1) >>> f.widget() '<div class="input-group"><span class="input-group-addon">£</span><input class="decimal_field" type="text" id="amount" maxlength="10" name="amount" size="10" value="1" /></div>'
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
locale= None¶
-
symbol= '$'¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.MultiselectField(label='', *validators, **keywords)¶ Bases:
zoom.fields.TextFieldMultiselect Field
>>> MultiselectField('Type',value='One',options=['One','Two']).display_value() 'One'
>>> f = MultiselectField('Type', default='One', options=['One','Two']) >>> f.evaluate() {'type': []} >>> f.display_value() '' >>> print(f.widget()) <select multiple="multiple" class="multiselect" name="type" id="type"> <option value="One" selected>One</option> <option value="Two">Two</option> </select>
>>> f.value >>> f.assign([]) >>> f.value [] >>> f.evaluate() {'type': []} >>> print(f.widget()) <select multiple="multiple" class="multiselect" name="type" id="type"> <option value="One">One</option> <option value="Two">Two</option> </select>
>>> f= MultiselectField('Type',value='One',options=['One','Two']) >>> print(f.widget()) <select multiple="multiple" class="multiselect" name="type" id="type"> <option value="One" selected>One</option> <option value="Two">Two</option> </select>
>>> f = MultiselectField('Type',value=['One','Three'],options=['One','Two','Three']) >>> print(f.widget()) <select multiple="multiple" class="multiselect" name="type" id="type"> <option value="One" selected>One</option> <option value="Two">Two</option> <option value="Three" selected>Three</option> </select>
>>> f = MultiselectField('Type',default=['One'],options=['One','Two','Three']) >>> print(f.widget()) <select multiple="multiple" class="multiselect" name="type" id="type"> <option value="One" selected>One</option> <option value="Two">Two</option> <option value="Three">Three</option> </select>
>>> f = MultiselectField('Type',default=['One','Two'],options=['One','Two','Three']) >>> print(f.widget()) <select multiple="multiple" class="multiselect" name="type" id="type"> <option value="One" selected>One</option> <option value="Two" selected>Two</option> <option value="Three">Three</option> </select>
>>> f = MultiselectField('Type',value='One',options=[('One','uno'),('Two','dos')]) >>> print(f.widget()) <select multiple="multiple" class="multiselect" name="type" id="type"> <option value="uno" selected>One</option> <option value="dos">Two</option> </select> >>> f.value ['uno'] >>> f.evaluate() {'type': ['uno']} >>> f.value = ['One'] >>> f.value ['One'] >>> f.evaluate() {'type': ['uno']} >>> f.update(**{'type':['dos']}) >>> f.value ['dos'] >>> f.evaluate() {'type': ['dos']}
>>> f = MultiselectField('Type',value='uno',options=[('One','uno'),('Two','dos')]) >>> f.display_value() 'One'
>>> f = MultiselectField('Type',value='uno',options=[('One','uno'),('One','dos')]) >>> f.display_value() 'One' >>> print(f.widget()) <select multiple="multiple" class="multiselect" name="type" id="type"> <option value="uno" selected>One</option> <option value="dos">One</option> </select>
>>> f = MultiselectField('Type',value=['One','dos'],options=[('One','uno'),('Two','dos')]) >>> f.display_value() 'One; Two' >>> f.evaluate() {'type': ['uno', 'dos']} >>> sorted(f.as_searchable()) ['One', 'Two']
>>> f = MultiselectField('Type',value=['One'],options=[('One','uno'),('Two','dos')]) >>> f.display_value() 'One' >>> f.evaluate() {'type': ['uno']}
>>> f = MultiselectField('Type', options=[('One','uno'),('Two','dos')]) >>> f.initialize({'type': 'One'}) >>> f.evaluate() {'type': ['uno']}
>>> f = MultiselectField('Type',value=['uno','dos'],options=[('One','uno'),('Two','dos')]) >>> f.display_value() 'One; Two' >>> f.evaluate() {'type': ['uno', 'dos']} >>> f.option_style('zero','nada') ''
>>> s = lambda label, value: value.startswith('d') and 's1' or 's0' >>> f = MultiselectField('Type',value=['uno','dos'],options=[('One','uno'),('Two','dos')], styler=s) >>> print(f.widget()) <select multiple="multiple" class="multiselect" name="type" id="type"> <option class="s0" value="uno" selected>One</option> <option class="s1" value="dos" selected>Two</option> </select>
>>> f.styler('test','dos') 's1' >>> f.option_style('zero','nada') 'class="s0" '
# test for iterating over a string vs. a sequence type (iteration protocol) >>> m1 = MultiselectField(‘Type’, default=‘11’, options=[(‘One’,‘1’),(‘Two’,‘2’),(‘Elves’,‘11’),]).widget() >>> m2 = MultiselectField(‘Type’, default=(‘11’,), options=[(‘One’,‘1’),(‘Two’,‘2’),(‘Elves’,‘11’),]).widget() >>> assert m1 == m2
-
as_searchable()¶ Return searchable parts of field
>>> name_field = Field('Name', default='default test') >>> name_field.as_searchable() {'default test'}
>>> name_field = Field('Name', value='test') >>> name_field.as_searchable() {'test'}
>>> name_field = Field('Age', value=10) >>> name_field.as_searchable() {'10'}
>>> name_field = Field('Name', value='こんにちは') >>> name_field.as_searchable() {'こんにちは'}
>>> name_field.visible = False >>> name_field.as_searchable() set()
>>> EmailField('Email', value='test@testco.com').as_searchable() {'test@testco.com'}
-
assign(new_value)¶ assign a value to the field
-
css_class= 'multiselect'¶
-
default= []¶
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
option_style(label, value)¶
-
styler= None¶
-
update(**values)¶ Update field.
>>> name_field = Field('Name', value='Sam') >>> name_field.value 'Sam' >>> name_field.update(city='Vancouver') >>> name_field.value 'Sam' >>> name_field.update(name='Joe') >>> name_field.value 'Joe' >>> name_field.update(NaMe='Adam') >>> name_field.value 'Adam'
-
value= None¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.NumberField(label='', *validators, **keywords)¶ Bases:
zoom.fields.TextFieldNumber Field
>>> NumberField('Size', value=2).display_value() '2'
>>> NumberField('Size').widget() '<input class="number_field" type="text" id="size" maxlength="10" name="size" size="10" value="" />'
>>> n = NumberField('Size') >>> n.assign('2') >>> n.value 2
>>> n = NumberField('Size', units='units') >>> n.assign('2,123') >>> n.value 2123 >>> n.evaluate() {'size': 2123} >>> n.display_value() '2,123 units'
>>> n.assign(None) >>> n.value == None True >>> n.display_value() ''
-
as_searchable()¶ Return searchable parts of field
>>> name_field = Field('Name', default='default test') >>> name_field.as_searchable() {'default test'}
>>> name_field = Field('Name', value='test') >>> name_field.as_searchable() {'test'}
>>> name_field = Field('Age', value=10) >>> name_field.as_searchable() {'10'}
>>> name_field = Field('Name', value='こんにちは') >>> name_field.as_searchable() {'こんにちは'}
>>> name_field.visible = False >>> name_field.as_searchable() set()
>>> EmailField('Email', value='test@testco.com').as_searchable() {'test@testco.com'}
-
assign(value)¶ assign a value to the field
-
converter¶ alias of
builtins.int
-
css_class= 'number_field'¶
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
maxlength= 10¶
-
size= 10¶
-
units= ''¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.PasswordField(label='', *validators, **keywords)¶ Bases:
zoom.fields.TextFieldPassword Field
>>> PasswordField('Password').show() ''
>>> PasswordField('Password').widget() '<input class="text_field" id="password" maxlength="40" name="password" size="40" type="password" value="" />'
-
maxlength= 40¶
-
show()¶ show the field
-
size= 40¶
-
-
class
zoom.fields.PhoneField(label='', *validators, **keywords)¶ Bases:
zoom.fields.TextFieldPhone field
>>> PhoneField('Phone').widget() '<input class="text_field" id="phone" name="phone" size="20" type="text" value="" />'
-
size= 20¶
-
validators= [<zoom.validators.RegexValidator object>]¶
-
-
class
zoom.fields.PostalCodeField(label='Postal Code', *validators, **keywords)¶ Bases:
zoom.fields.TextFieldPostal code field
>>> PostalCodeField('Postal Code').widget() '<input class="text_field" id="postal_code" maxlength="7" name="postal_code" size="7" type="text" value="" />'
-
maxlength= 7¶
-
size= 7¶
-
-
class
zoom.fields.PulldownField(*a, **k)¶ Bases:
zoom.fields.TextFieldPulldown Field
>>> from zoom.component import Component >>> PulldownField('Type',value='One',options=['One','Two']).display_value() 'One'
>>> print(PulldownField('Type',value='One',options=['One','Two']).widget()) <select class="pulldown" name="type" id="type"> <option value="One" selected>One</option> <option value="Two">Two</option> </select>
>>> print(PulldownField('Type',options=['One','Two']).widget()) <select class="pulldown" name="type" id="type"> <option value=""></option> <option value="One">One</option> <option value="Two">Two</option> </select>
>>> f = PulldownField('Type', options=[('',''),('One',1),('Two',2)]) >>> print(f.widget()) <select class="pulldown" name="type" id="type"> <option value="" selected></option> <option value="1">One</option> <option value="2">Two</option> </select>
>>> f.assign(2) >>> print(f.widget()) <select class="pulldown" name="type" id="type"> <option value=""></option> <option value="1">One</option> <option value="2" selected>Two</option> </select>
>>> f.assign('2') >>> print(f.widget()) <select class="pulldown" name="type" id="type"> <option value=""></option> <option value="1">One</option> <option value="2" selected>Two</option> </select>
>>> f = PulldownField('Type', options=[('',''),('One','1'),('Two','2')]) >>> print(f.widget()) <select class="pulldown" name="type" id="type"> <option value="" selected></option> <option value="1">One</option> <option value="2">Two</option> </select>
>>> f.assign(2) >>> print(f.widget()) <select class="pulldown" name="type" id="type"> <option value=""></option> <option value="1">One</option> <option value="2" selected>Two</option> </select>
>>> f.assign('2') >>> print(f.widget()) <select class="pulldown" name="type" id="type"> <option value=""></option> <option value="1">One</option> <option value="2" selected>Two</option> </select>
>>> f = PulldownField('Type',value='One',options=[('One','uno'),('Two','dos')]) >>> print(f.widget()) <select class="pulldown" name="type" id="type"> <option value="uno" selected>One</option> <option value="dos">Two</option> </select>
>>> f.value 'uno' >>> f.evaluate() {'type': 'uno'} >>> f.value = 'One' >>> f.value 'One' >>> f.evaluate() {'type': 'uno'} >>> f.update(**{'tYpe':'dos'}) >>> f.value 'dos' >>> f.evaluate() {'type': 'dos'}
>>> f = PulldownField('Type',value='uno',options=[('One','uno'),('Two','dos')]) >>> f.display_value() 'One'
>>> f = PulldownField('Type',default='uno',options=[('One','uno'),('Two','dos')]) >>> f.display_value() 'One' >>> f.evaluate() {'type': 'uno'}
>>> p = PulldownField('Date', name='TO_DATE', options=[('JAN','jan'), ('FEB','feb'),], default='feb') >>> p.evaluate() {'TO_DATE': 'feb'} >>> p.display_value() 'FEB'
-
assign(new_value)¶ assign a value to the field
-
css_class= 'pulldown'¶
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
evaluate()¶ Evaluate field value.
Return the value of the field expressed as key value pair (dict) ususally to be combined with other fields in the native type where the value is the native data type for the field type.
-
libs= []¶
-
select_layout= '<select class="{classed}" name="{name}" id="{name}">\n'¶
-
styles= []¶
-
value= None¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.RadioField(label='', *validators, **keywords)¶ Bases:
zoom.fields.TextFieldRadio Field
>>> RadioField('Choice', value='One', values=['One','Two']).display_value() 'One'
>>> print(RadioField('Choice', value='One', values=['One','Two']).widget()) <span class="radio"><input checked class="radio" name="choice" type="radio" value="One" />One</span> <span class="radio"><input class="radio" name="choice" type="radio" value="Two" />Two</span>
>>> r = RadioField('Choice',value='1',values=[('One','1'),('Two','2')]) >>> print(r.widget()) <span class="radio"><input checked class="radio" name="choice" type="radio" value="1" />One</span> <span class="radio"><input class="radio" name="choice" type="radio" value="2" />Two</span>
>>> r.assign('1') >>> r.evaluate() {'choice': '1'} >>> r.display_value() 'One'
>>> r.assign('2') >>> r.evaluate() {'choice': '2'} >>> r.display_value() 'Two'
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
values= []¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.RangeSliderField(label='', *validators, **keywords)¶ Bases:
zoom.fields.IntegerFieldjQuery UI Range Slider
>>> r = RangeSliderField('Price', min=0, max=1500) >>> r.assign(0) >>> r.value (0, 1500) >>> r.assign((10, 20)) >>> r.value (10, 20) >>> r.assign('10,20') >>> r.value (10, 20) >>> isinstance(r.widget(), zoom.Component) True >>> isinstance(r.display_value(), str) True
-
assign(v)¶ assign a value to the field
-
css_class= 'range-slider'¶
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
js= '\n $( "#%(name)s" ).slider({\n range: true,\n min: %(tmin)s,\n max: %(tmax)s,\n values: [ %(minv)s, %(maxv)s ],\n change: function( event, ui ) {\n var v = ui.values,\n t = v[0] + \',\' + v[1];\n $("input[name=\'%(name)s\']").val(t);\n %(formatter)s\n $( "div[data-id=\'%(name)s\'] span:nth-of-type(1)" ).html( formatter(ui.values[ 0 ]) );\n $( "div[data-id=\'%(name)s\'] span:nth-of-type(2)" ).html( formatter(ui.values[ 1 ]) );\n },\n slide: function( event, ui ) {\n var v = ui.values;\n %(formatter)s\n $( "div[data-id=\'%(name)s\'] span:nth-of-type(1)" ).html( formatter(ui.values[ 0 ]) );\n $( "div[data-id=\'%(name)s\'] span:nth-of-type(2)" ).html( formatter(ui.values[ 1 ]) );\n }\n });\n $("#%(name)s").slider("values", $("#%(name)s").slider("values")); // set formatted label\n '¶
-
js_formatter= 'var formatter = function(v) { return v;};'¶
-
max= 10¶
-
min= 0¶
-
show_labels= True¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.Section(label, fields, hint='')¶ Bases:
zoom.fields.FieldsA collection of field objects with an associated label.
>>> print(Section('Personal',[TextField('Name',value='Joe')]).show()) <h2>Personal</h2> <div class="field"> <div class="field_label">Name</div> <div class="field_show">Joe</div> </div>
-
edit()¶
-
name¶
-
render_hint()¶
-
show()¶
-
-
class
zoom.fields.TextField(label='', *validators, **keywords)¶ Bases:
zoom.fields.FieldText Field
>>> print(TextField('Name', value="John Doe").show()) <div class="field"> <div class="field_label">Name</div> <div class="field_show">John Doe</div> </div>
>>> print(TextField('Name',value='John Doe').widget()) <input class="text_field" id="name" maxlength="40" name="name" size="40" type="text" value="John Doe" />
>>> print(TextField('Name',value="Dan").show()) <div class="field"> <div class="field_label">Name</div> <div class="field_show">Dan</div> </div>
>>> print(TextField('Name',default="Dan").show()) <div class="field"> <div class="field_label">Name</div> <div class="field_show">Dan</div> </div>
>>> TextField('Name', hint="required").widget() '<input class="text_field" id="name" maxlength="40" name="name" size="40" type="text" value="" />'
>>> TextField('Name', placeholder="Jack").widget() '<input class="text_field" id="name" maxlength="40" name="name" placeholder="Jack" size="40" type="text" value="" />'
>>> f = TextField('Title') >>> f.update(**{"TITLE": "Joe's Pool Hall"}) >>> f.value "Joe's Pool Hall" >>> f.evaluate() {'title': "Joe's Pool Hall"}
-
css_class= 'text_field'¶
-
maxlength= 40¶
-
size= 40¶
-
widget()¶ returns the field widget
-
-
class
zoom.fields.TwitterField(label='', *validators, **keywords)¶ Bases:
zoom.fields.TextFieldTwitter field
>>> TwitterField('Twitter').widget() '<input class="text_field" id="twitter" name="twitter" type="text" value="" />'
>>> TwitterField('Twitter', value='dsilabs').display_value() '<a target="_window" href="http://www.twitter.com/dsilabs">@dsilabs</a>'
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
-
class
zoom.fields.URLField(label, *validators, **keywords)¶ Bases:
zoom.fields.TextFieldURL Field
>>> URLField('Website', default='www.google.com').display_value() '<a target="_window" href="http://www.google.com">http://www.google.com</a>'
>>> f = URLField('Website', default='www.google.com') >>> f.assign('www.dsilabs.ca') >>> f.display_value() '<a target="_window" href="http://www.dsilabs.ca">http://www.dsilabs.ca</a>'
>>> f = URLField('Website', default='www.google.com') >>> f.assign('http://www.dsilabs.ca') >>> f.display_value() '<a target="_window" href="http://www.dsilabs.ca">http://www.dsilabs.ca</a>'
>>> f = URLField('Website', default='www.google.com', trim=True) >>> f.assign('http://www.dsilabs.ca/') >>> f.display_value() '<a target="_window" href="http://www.dsilabs.ca">www.dsilabs.ca</a>'
>>> f = URLField('Website', default='www.google.com') >>> f.assign('https://www.dsilabs.ca/') >>> f.display_value() '<a target="_window" href="https://www.dsilabs.ca/">https://www.dsilabs.ca/</a>'
>>> f = URLField('Website', default='www.google.com', trim=True) >>> f.assign('https://www.dsilabs.ca/') >>> f.display_value() '<a target="_window" href="https://www.dsilabs.ca">www.dsilabs.ca</a>'
-
assign(value)¶ assign a value to the field
-
display_value()¶ Display field value.
>>> name_field = Field('Name', default='default test') >>> name_field.display_value() 'default test'
>>> name_field = Field('Name', value='test') >>> name_field.display_value() 'test'
>>> name_field = Field('Name', value='こんにちは') >>> name_field.display_value() 'こんにちは'
>>> name_field.visible = False >>> name_field.display_value() ''
-
maxlength= 120¶
-
size= 60¶
-
trim= False¶
-
-
zoom.fields.args_to_dict(values=None, **kwargs)¶ convert args to a dict
Allows developers to pass field values to fields either as a dict or as a set of keyword arguments, whichever makes the most sense for their code.
This is currently only used for clean() but could potentially be used in a number of other places in this modudle where the same pattern shows up. Erring on the side of caution for now.
>>> args_to_dict() {}
>>> args_to_dict({}) {}
>>> args_to_dict({'name': 'Pat'}) {'name': 'Pat'}
>>> from zoom.utils import pp >>> pp(args_to_dict(**{'name': 'Pat', 'age': 10})) { "age": 10, "name": "Pat" }
>>> try: ... args_to_dict({'name': 'Pat'}, 'bad value', age=10) ... except TypeError as e: ... expected = 'args_to_dict() takes' in str(e) >>> expected True
-
zoom.fields.layout_field(label, content, edit=True)¶ Layout a field (usually as part of a form).
>>> print( ... layout_field( ... 'Name', ... '<input type=text value="John Doe">', ... True ... ) ... ) <div class="field"> <div class="field_label">Name</div> <div class="field_edit"><input type=text value="John Doe"></div> </div>
>>> print(layout_field('Name', 'John Doe', False)) <div class="field"> <div class="field_label">Name</div> <div class="field_show">John Doe</div> </div>
-
zoom.fields.locate_view(name)¶
zoom.fill module¶
fills templates
-
zoom.fill.dzfill(text, callback)¶ fill a tag in the <dz: style
-
zoom.fill.fill(text, callback)¶ fill a tag in the double handlebars style
>>> def filler(name, *args, **kwargs): ... if name == 'name': ... name = kwargs.get('language')=='french' and 'Jacques' or 'James' ... if 'upper' in args: ... return name.upper() ... elif 'lower' in args: ... return name.lower() ... else: ... return name >>> fill('Hello {{name}}!', filler) 'Hello James!' >>> fill('Hello {{name language="french"}}!', filler) 'Hello Jacques!' >>> fill('Hello {{name upper}}!', filler) 'Hello JAMES!' >>> fill('Hello {{name lower language="french"}}!', filler) 'Hello jacques!' >>> fill('Hello {{name lower language=french}}!', filler) 'Hello jacques!' >>> fill('Hello {{name}}!', lambda a: None ) 'Hello {{name}}!'
>>> values = {} >>> fill('Hello {{name}}!', values.get ) 'Hello {{name}}!' >>> fill('Hello {{name "World"}}!', values.get ) 'Hello World!' >>> values['name'] = 'Pat' >>> fill('Hello {{name "World"}}!', values.get ) 'Hello Pat!' >>> del values['name'] >>> fill('Hello{{name ""}}!', values.get ) 'Hello!'
zoom.forms module¶
zoom.forms
-
class
zoom.forms.Form(*args, **kwargs)¶ Bases:
zoom.fields.FieldsAn HTML form
>>> from zoom.fields import TextField >>> form = Form(TextField("Name")) >>> print(form.edit()) <form action="" class="clearfix" enctype="application/x-www-form-urlencoded" id="zoom_form" method="POST" name="zoom_form"> <input name="csrf_token" type="hidden" value="<dz:csrf_token>" /> <div class="field"> <div class="field_label">Name</div> <div class="field_edit"><table class="transparent"> <tr> <td nowrap><input class="text_field" id="name" maxlength="40" name="name" size="40" type="text" value="" /></td> <td> <div class="hint"></div> </td> </tr> </table> </div> </div> </form>
-
edit()¶
-
-
zoom.forms.delete_form(name, cancel=None)¶ produce a delete form
-
zoom.forms.form(content=None, **kwargs)¶ returns the first part of a form
-
zoom.forms.form_for(*args, **kwargs)¶ returns a form with optional hidden values
>>> print(form_for('test')) <form action="<dz:request_path>" class="clearfix" enctype="application/x-www-form-urlencoded" id="zoom_form" method="POST" name="zoom_form"> <input name="csrf_token" type="hidden" value="<dz:csrf_token>" /> test </form>
-
zoom.forms.helpers(request)¶ form helpers
-
zoom.forms.multipart_form(content, **kwargs)¶ Returns a multipart form tag.
-
zoom.forms.multipart_form_for(content, **keywords)¶ Returns a multipart form tag, surrounding specified content.
zoom.helpers module¶
zoom.helpers
-
zoom.helpers.abs_url_for(*a, **k)¶ calculates absolute url
>>> abs_url_for() '<dz:abs_site_url><dz:request_path>'
>>> abs_url_for('') '<dz:abs_site_url><dz:request_path>'
>>> abs_url_for('/') '<dz:abs_site_url>'
>>> abs_url_for('/', 'home') '<dz:abs_site_url>/home'
>>> abs_url_for('/home') '<dz:abs_site_url>/home'
>>> abs_url_for('home') '<dz:abs_site_url><dz:request_path>/home'
>>> abs_url_for('/user', 1234) '<dz:abs_site_url>/user/1234'
>>> abs_url_for('/user', 1234, q='test one', age=15) '<dz:abs_site_url>/user/1234?age=15&q=test+one'
>>> abs_url_for('/user', q='test one', age=15) '<dz:abs_site_url>/user?age=15&q=test+one'
>>> abs_url_for('/', q='test one', age=15) '<dz:abs_site_url>?age=15&q=test+one'
>>> abs_url_for(q='test one', age=15) '<dz:abs_site_url><dz:request_path>?age=15&q=test+one'
>>> abs_url_for('https://google.com', q='test one') 'https://google.com?q=test+one'
-
zoom.helpers.date()¶ Returns the current date in text form.
-
zoom.helpers.include(filename)¶ Return the included file
-
zoom.helpers.link_to(label, *args, **kwargs)¶ produce a link
>>> zoom.system.site = lambda: None >>> zoom.system.site.url = ''
>>> link_to('Company', 'http://company.com') '<a href="http://company.com" name="link-to-company">Company</a>'
>>> link_to('http://company.com') '<a href="http://company.com" name="link-to-http-company-com">http://company.com</a>'
>>> link_to('http://company.com', q='test') '<a href="http://company.com?q=test" name="link-to-http-company-com">http://company.com</a>'
-
zoom.helpers.link_to_page(label, *args, **kwargs)¶
-
zoom.helpers.lorem()¶ Returns some sample latin text to use for prototyping.
-
zoom.helpers.mail_to(name, *args, **kwargs)¶ produce an email link
>>> mail_to('Tester', 'test@testco.com') '<a href="test@testco.com">Tester</a>'
>>> mail_to('test@testco.com') '<a href="test@testco.com">test@testco.com</a>'
-
zoom.helpers.owner_email()¶ Returns the email address of the site owner.
-
zoom.helpers.owner_link()¶ Returns a link for the site owner.
-
zoom.helpers.owner_name()¶ Returns the name of the site owner.
-
zoom.helpers.owner_url()¶ Returns the URL of the site owner.
-
zoom.helpers.tag_for(name, *a, **k)¶ create a zoom tag
>>> tag_for('name') '<dz:name>'
>>> tag_for('name', default=1) '<dz:name default=1>'
-
zoom.helpers.upper(text)¶ Returns the given text in upper case.
-
zoom.helpers.url_for(*a, **k)¶ creates urls
>>> zoom.system.site = lambda: None >>> zoom.system.site.url = ''
>>> url_for() ''
>>> url_for('') ''
# >>> url_for(‘/’) # ‘<dz:site_url>’
>>> url_for('/', 'home') '/home'
>>> url_for('/home') '/home'
>>> url_for('home') 'home'
>>> url_for('/user', 1234) '/user/1234'
>>> url_for('/user', 1234, q='test one', age=15) '/user/1234?age=15&q=test+one'
>>> url_for('/user', q='test one', age=15) '/user?age=15&q=test+one'
>>> url_for('/', q='test one', age=15) '?age=15&q=test+one'
>>> url_for(q='test one', age=15) '?age=15&q=test+one'
>>> url_for('https://google.com', q='test one') 'https://google.com?q=test+one'
-
zoom.helpers.url_for_item(*args, **kwargs)¶ returns a url for an item on the curren page
>>> zoom.system.request = lambda: None >>> zoom.system.request.route = ['myapp', 'mypage']
>>> url_for_item() '/myapp/mypage'
>>> url_for_item(100) '/myapp/mypage/100'
-
zoom.helpers.url_for_page(*args, **kwargs)¶ returns a url for a page of the current app
>>> url_for_page() '<dz:app_url>'
>>> url_for_page('page1') '<dz:app_url>/page1'
-
zoom.helpers.username()¶ Returns the username.
-
zoom.helpers.when(date, since=None)¶ Formats a date
>>> now = datetime.datetime(2018, 2, 24, 1, 2, 42) >>> when(now - zoom.tools.one_day * 2, now) '<span title="2018-02-22 01:02:42">2 days ago</span>'
-
zoom.helpers.who(user_id)¶ Formats a user_id
>>> zoom.system.site = site = zoom.sites.Site() >>> zoom.system.user = site.users.first(username='admin') >>> user_id = site.users.first(username='guest').user_id
>>> zoom.system.user.is_admin = True >>> who(user_id) '<a href="/admin/users/guest" name="link-to-guest">guest</a>' >>> who(100) 'unknown (100)'
>>> zoom.system.user.is_admin = False >>> who(user_id) 'guest' >>> who(100) 'unknown'
-
zoom.helpers.year()¶ Returns the current year in text form.
zoom.html module¶
zoom.html
-
zoom.html.a(content, *args, **kwargs)¶ generate an anchor tag
>>> a('home', href='/home') '<a href="/home">home</a>'
-
zoom.html.div(*content, **kwargs)¶ generates an HTML div tag
Content can be any number of items that support str conversion. Named arguments are used as tag attributes for the div tag.
>>> div('some content') '<div>some content</div>'
>>> div('some', ' content') '<div>some content</div>'
>>> div('') '<div></div>'
>>> div(Class='header') '<div class="header"></div>'
-
zoom.html.glyphicon(icon, **kwargs)¶ generates a glpyhicon span
>>> glyphicon('heart') '<span aria-hidden="true" class="glyphicon glyphicon-heart"></span>'
>>> glyphicon('heart', Class="special") '<span aria-hidden="true" class="glyphicon glyphicon-heart special"></span>'
>>> t = ( ... '<span aria-hidden="true" class="glyphicon ' ... 'glyphicon-heart special" style="color:red"></span>' ... ) >>> glyphicon('heart', Class="special", style="color:red") == t True
-
zoom.html.h1(text)¶ h1 tag
>>> h1('my heading') '<h1>my heading</h1>'
-
zoom.html.h2(text)¶ h2 tag
>>> h2('my subheading') '<h2>my subheading</h2>'
-
zoom.html.h3(text)¶ h3 tag
>>> h3('my subsubheading') '<h3>my subsubheading</h3>'
-
zoom.html.img(src, **kwargs)¶ HTML Image Tag
>>> img('/static/images/no_image.png', typed='standard-image') '<img src="/static/images/no_image.png" type="standard-image" />'
-
zoom.html.input(*args, **kwargs)¶
-
zoom.html.li(items)¶ generate list items
>>> li(['this','that']) '<li>this</li><li>that</li>'
-
zoom.html.ol(items)¶ generate an ordered list
>>> ol(['this','that']) '<ol><li>this</li><li>that</li></ol>'
-
zoom.html.pre(content)¶
-
zoom.html.span(content='', **kwargs)¶ generates an div tag
>>> span('some content') '<span>some content</span>'
>>> span('') '<span></span>'
>>> span(Class='header') '<span class="header"></span>'
-
zoom.html.table(rows)¶ returns rows wrapped in an HTML table
-
zoom.html.tag(element, *args, **kwargs)¶ generates an HTML tag
>>> tag('div', 'some content', classed='content-card') '<div class="content-card">some content</div>'
>>> tag('a', href='http://www.google.com') '<a href="http://www.google.com"></a>'
-
zoom.html.ul(items)¶ generate an unordered list
>>> ul(['this','that']) '<ul><li>this</li><li>that</li></ul>'
zoom.instances module¶
zoom.instances
Mananage zoom instances
Note: Experimental!
-
class
zoom.instances.Instance(path=None)¶ Bases:
objectZoom Instance
A Zoom instance is a directory containing sites, apps and themes. Zoom can host multiples sites using the same configuration under a single Instance.
>>> import tempfile >>> instance_path = os.path.join(tempfile.gettempdir(), 'fakeinstance') >>> instance = Instance(instance_path) >>> instance.create() >>> os.path.exists(instance.path) True >>> os.path.exists(os.path.join(instance.path, 'sites')) True >>> instance.sites == {} True >>> instance.destroy() >>> os.path.exists(instance.path) False
-
create()¶ Create a new instance
-
destroy()¶ Destroy an empty instance
-
run_background_jobs()¶ Run background jobs
Iterates through the sites in the instance and calls run_background_jobs on each one.
>>> instance = Instance() >>> instance.run_background_jobs() localhost
-
sites¶ a dict of sites for the instance
>>> instance = Instance() >>> print(instance.sites) {'localhost': Site('localhost')}
>>> import tempfile >>> instance_path = os.path.join(tempfile.gettempdir(), 'fakeinstance') >>> instance = Instance(instance_path) >>> got_it = False >>> try: ... instance.sites ... except InstanceMissingException: ... got_it = True >>> got_it True
-
sites_path¶ the path to the sites of the instance
>>> instance_directory = zoom.tools.zoompath('web') >>> instance = Instance(instance_directory) >>> instance.sites_path == instance_directory + '/sites' True
-
-
exception
zoom.instances.InstanceExistsException¶ Bases:
ExceptionInstance directory exists
-
exception
zoom.instances.InstanceMissingException¶ Bases:
ExceptionInstance directory is missing
zoom.jsonz module¶
zoom.jsonz
JSON with extra converters
-
zoom.jsonz.dumps(data, *a, **k)¶ Convert to json with support for date and decimal types
>>> dumps('test') '"test"'
>>> loads(dumps('test')) 'test'
>>> loads(dumps(date(2015,1,1))) datetime.date(2015, 1, 1)
>>> loads(dumps(Decimal('20.40'))) Decimal('20.40')
-
zoom.jsonz.loads(text)¶ load JSON from a string
zoom.logging module¶
zoom.logging
-
class
zoom.logging.LogHandler(request, level=20)¶ Bases:
logging.HandlerLog handler
Logs information to the log table in the system database.
-
emit(record)¶ Do whatever it takes to actually log the specified logging record.
This version is intended to be implemented by subclasses and so raises a NotImplementedError.
-
-
zoom.logging.add_entry(request, status, entry)¶ Add an entry to the system log
-
zoom.logging.handler(request, handler, *rest)¶ Handles logging
>>> import zoom.request >>> import zoom.profiler >>> request = zoom.request.build('http://localhost') >>> request.profiler = zoom.profiler.SystemTimer(request.start_time) >>> request.site = zoom.sites.Site() >>> def log_something(request): ... logger = logging.getLogger(__name__) ... logger.debug('hey') >>> response = handler(request, log_something) >>> response is None True
-
zoom.logging.log_activity(message, *args, **kwargs)¶ Log user activity
Use for high level user activity logging, such as editing records.
zoom.mail module¶
zoom.mail
email services
-
zoom.mail.send(recipients, subject, message, attachments=None)¶ send an email
-
zoom.mail.send_as(sender, recipients, subject, message, attachments=None)¶ send an email as a specific sender
-
zoom.mail.deliver()¶ deliver mail
-
class
zoom.mail.Attachment(pathname, data=None, mime_type=None)¶ Bases:
objectEmail attachment
provide either a pathname, or a filename and a pathname, or if sending directly a filename and a file-like object.
-
as_tuple()¶ partilars required for delivery
-
read¶ provides a reader for the data
if the data is not open, it will be because the user provided only a pathanme so we open the file at the pathname and return it
-
zoom.middleware module¶
zoom.middleware
A set of functions that can be placed between the HTTP server and the application layer. These functions can provide various services such as content serving, caching, error trapping, security, etc..
-
zoom.middleware.capture_stdout(request, handler, *rest)¶ Capture printed output for debugging purposes
>>> request = zoom.request.build('http://localhost') >>> def get_content(request): ... print('hey') ... return zoom.response.HTMLResponse('I said {*stdout*}') >>> response = capture_stdout(request, get_content) >>> response.content 'I said hey\n'
-
zoom.middleware.check_csrf(request, handler, *rest)¶ Check csrf token
>>> zoom.system.providers = [] >>> data = dict(csrf_token='1234', name='Pat') >>> request = zoom.request.build('http://localhost/', data) >>> request.session = zoom.utils.Bunch() >>> request.site = zoom.sites.Site() >>> result = check_csrf(request, lambda a: False) >>> isinstance(result, zoom.response.RedirectResponse) True
>>> data = dict(csrf_token='1234', name='Pat') >>> request = zoom.request.build('http://localhost/', data) >>> request.session = zoom.utils.Bunch(csrf_token='4321') >>> request.site = zoom.sites.Site() >>> result = check_csrf(request, lambda a: False) >>> isinstance(result, zoom.response.RedirectResponse) True
>>> data = dict(csrf_token='1234', name='Pat') >>> request = zoom.request.build('http://localhost/', data) >>> request.session = zoom.utils.Bunch(csrf_token='1234') >>> request.site = zoom.sites.Site() >>> result = check_csrf(request, lambda a: False) >>> isinstance(result, zoom.response.RedirectResponse) False
-
zoom.middleware.debug(request)¶ Debugging page
>>> type(debug(zoom.request.build('http://localhost/'))) <class 'zoom.response.HTMLResponse'>
-
zoom.middleware.display_errors(request, handler, *rest)¶ Display errors for developers
>>> request = zoom.request.build('http://localhost') >>> request.app = zoom.utils.Bunch(theme='default', templates_paths=[]) >>> request.host = 'localhost' >>> request.site = zoom.sites.Site() >>> request.site.theme = 'default' >>> request.site.request = request >>> zoom.system.request = request >>> zoom.system.site = request.site >>> zoom.system.user = request.site.users.first(username='admin') >>> zoom.system.user.is_admin = True >>> def throw(request): ... raise Exception('ouch!') >>> response = display_errors(request, throw) >>> isinstance(response, HTMLResponse) True >>> zoom.system.user.is_admin = False >>> response = display_errors(request, throw) >>> isinstance(response, HTMLResponse) True
-
zoom.middleware.get_csrf_token(session)¶ generate a csrf token
>>> zoom.system.request.session = session = zoom.utils.Bunch() >>> hasattr(session, 'csrf_token') False >>> bool(get_csrf_token(session)) True >>> hasattr(session, 'csrf_token') False >>> _ = zoom.forms.form_for('test') >>> hasattr(session, 'csrf_token') True
-
zoom.middleware.handle(request, handlers=None)¶ handle a request
-
zoom.middleware.not_found(request)¶ return a 404 page for site
>>> zoom.system.site = site = zoom.sites.Site() >>> site.theme = 'default' >>> site.title = 'My Site' >>> request = zoom.request.build('http://localhost') >>> request.app = zoom.utils.Bunch(theme='default') >>> request.site = site >>> response = not_found(request) >>> response.status '404 Not Found'
-
zoom.middleware.reset_modules(request, handler, *rest)¶ reset the modules to a known starting set
Memorizes the modules in use on the first round. Then on every subsequent round, it removes any extra modules before passing the request on.
>>> def loader(request): ... import zoom.audit
>>> def not_a_loader(request): ... pass
>>> if 'zoom.audit' in sys.modules: ... del sys.modules['zoom.audit'] >>> fresh = list(sys.modules) >>> reset_modules(zoom.request.build('http://localhost'), loader) >>> fresh == list(sys.modules) False
>>> reset_modules(zoom.request.build('http://localhost'), not_a_loader) >>> fresh == list(sys.modules) True
-
zoom.middleware.serve_favicon(request, handler, *rest)¶ Serve a favicon file
This function only handles the case where the favicon reference is /favicon.ico, as would be typical in a local dev environment. For production environments the favicon would typically be either part of the theme or would be stored statically, both of which would typically be served up by your proxy or your web server depending on your config.
If your web sever is not configured to handle static or themes for you, Zoom will happily serve them up via the serve_theme or serve_static middleware found elsewhere in this module.
>>> from zoom.request import Request >>> def content_handler(request, *rest): ... return '200 OK', [], 'nuthin'
>>> request = Request( ... dict(REQUEST_URI='/favicon.ico'), ... ) >>> response = serve_favicon( ... request, ... content_handler, ... ) >>> isinstance(response, ICOResponse) True
>>> request = Request( ... dict(REQUEST_URI='/'), ... ) >>> status, _, content = serve_favicon( ... request, ... content_handler, ... ) >>> content 'nuthin'
-
zoom.middleware.serve_html(request, handler, *rest)¶ Serve HTML from the Content app
Direct a request for an HTML page to the content app
>>> site = zoom.sites.Site() >>> url = 'http://localhost/index.html' >>> request = zoom.request.build(url) >>> request.path == '/index.html' True >>> response = serve_html(request, lambda a: None) >>> request.path == '/content/index.html' True
>>> url = 'http://localhost/index.css' >>> request = zoom.request.build(url) >>> request.path == '/index.css' True >>> response = serve_html(request, lambda a: None) >>> request.path == '/index.css' True
-
zoom.middleware.serve_images(request, handler, *rest)¶ Serve an image file
>>> url = 'http://localhost/images/banner_logo.png' >>> request = zoom.request.build(url) >>> request.site = zoom.sites.Site() >>> result = serve_images(request, lambda a: False) >>> isinstance(result, PNGResponse) True
>>> url = 'http://localhost/notimages/banner_logo.png' >>> request = zoom.request.build(url) >>> serve_images(request, lambda a: False) False
-
zoom.middleware.serve_redirects(request, handler, *rest)¶ Serves redirects
>>> request = zoom.request.build('http://localhost') >>> result = serve_redirects(request, lambda a: False) >>> print(result) False
>>> request.site = zoom.utils.Bunch(abs_url='http://localhost') >>> redirect_home = zoom.response.RedirectResponse('/home') >>> result = serve_redirects(request, lambda a: redirect_home) >>> print(result.headers) OrderedDict([('Location', '/home')])
-
zoom.middleware.serve_response(*path)¶ Serve up various respones with their correct response type
>>> zoom_js = zoom.tools.zoompath('web/www/static/zoom/zoom.js') >>> response = serve_response(zoom_js) >>> isinstance(response, JavascriptResponse) True
>>> zoom_path = zoom.tools.zoompath('web') >>> response = serve_response(zoom_path, 'www/static/zoom/nada.js') >>> isinstance(response, JavascriptResponse) False
>>> response.content "file not found: 'www/static/zoom/nada.js'" >>> response.status '404 Not Found'
>>> zoom_path = zoom.tools.zoompath('web') >>> response = serve_response(zoom_path, 'www/static/zoom/images') >>> isinstance(response, JavascriptResponse) False
>>> response.content "unknown file type ''" >>> response.status '415 Unsupported Media Type'
-
zoom.middleware.serve_static(request, handler, *rest)¶ Serve a static file
Static files can be served in serveral ways. This particular middleware intended to be inserted into the middleware stack near the front before most other things. The reason being is that in many cases the static files are not site specific or app specific but rather are shared by the entire instance. In addition, many times static files require no authorization or special rights. This means that in many cases static files can be served without knowing who is asking or what site they are for. That is what this middleware does.
This handler is mainly intended for development purposes as in a production evironment this type of content would typically be served up by the HTTP server or a caching layer.
Note: This layer looks in four separate places for static files to serve. Three related to the zoom instance, and one, as a last resort, from the zoom library itself. If you are concerned about exposing the wrong files, be careful what you put in those directories or better yet, use a proxy.
In addition to this instance wide static serving Sites and Apps may implement static file serving. If they do, this layer is unaware of that fact.
The locations this handler will look are relative to the zoom instance. They are:
<instance>/static <instance>/www/static <instance>/../static zoom/web/www/static>>> url = 'http://localhost/static/zoom/zoom.js' >>> request = zoom.request.build(url) >>> result = serve_static(request, lambda a: False) >>> isinstance(result, JavascriptResponse) True
>>> url = 'http://localhost/notstatic/zoom/zoom.js' >>> request = zoom.request.build(url) >>> result = serve_static(request, lambda a: False) >>> isinstance(result, JavascriptResponse) False
-
zoom.middleware.serve_themes(request, handler, *rest)¶ Serve a theme file
>>> url = 'http://localhost/themes/default/css/style.css' >>> request = zoom.request.build(url) >>> request.site = zoom.sites.Site() >>> result = serve_themes(request, lambda a: False) >>> isinstance(result, CSSResponse) True
>>> url = 'http://localhost/notthemes/default/default.html' >>> request = zoom.request.build(url) >>> serve_themes(request, lambda a: False) False
-
zoom.middleware.trap_errors(request, handler, *rest)¶ Trap exceptions and raise a server error
>>> def exception_handler(request, *rest): ... raise Exception('error!') >>> def content_handler(request, *rest): ... return HTMLResponse('nuthin') >>> request = {} >>> response = trap_errors(request, content_handler) >>> status, headers, content = response.as_wsgi() >>> content b'nuthin' >>> status '200 OK' >>> response = trap_errors(request, exception_handler) >>> status, headers, content = response.as_wsgi() >>> status '500 Internal Server Error' >>> 'Exception: error!' in str(content) True
zoom.migrations module¶
zoom.migrations
Work in progress - experimental
-
class
zoom.migrations.Migration(db)¶ Bases:
objectProvies the methods to apply or revert transformations to get system to a desired state.
-
apply()¶ apply changes to the database
-
name¶
-
revert()¶ Revert changes to the database
-
-
class
zoom.migrations.Migrations(db, steps)¶ Bases:
objectperforms the migration steps needed to get to the target version
Systems are migrated from one state to another by providing a sequence of steps typically subclassed from the Migration class. Migrations should provide both an apply method to peform a transformation to take a system to a desired state and, where possible, a revert method to undo the transformation to transform the sytem back to its original state.
As they are applied and reverted, the migrations are tracked in a data store including the name of the object peforming the migration ( usually a subclass of Migration) the version of the system that was attained by applying or reverting the migration, the revision number of the migration (an integer representing the application or reversion of a transformation), the method used (apply or revert) and the timestamp of when the migration took place.
>>> class AddFaxColumnToUser(Migration): ... def apply(self): ... self.db('alter table users add column fax char(30)') ... def revert(self): ... self.db('alter table users drop column fax')
>>> steps = [ ... StartMigration, ... AddFaxColumnToUser, ... ]
>>> zoom.system.site = site = zoom.sites.Site() >>> site.db = zoom.database.setup_test()
>>> print(site.db('describe users')) Field Type Null Key Default Extra ---------- ---------------- ---- --- ------- -------------- id int(10) unsigned NO PRI None auto_increment username char(50) NO UNI None password varchar(125) YES None first_name char(40) YES None last_name char(40) YES None email char(60) YES MUL None phone char(30) YES None created datetime YES None updated datetime YES None last_seen datetime YES MUL None created_by int(10) unsigned YES None updated_by int(10) unsigned YES None status char(1) YES None
>>> migrations = Migrations(site.db, steps) >>> migrations.migrate()
>>> print(site.db('describe users')) Field Type Null Key Default Extra ---------- ---------------- ---- --- ------- -------------- id int(10) unsigned NO PRI None auto_increment username char(50) NO UNI None password varchar(125) YES None first_name char(40) YES None last_name char(40) YES None email char(60) YES MUL None phone char(30) YES None created datetime YES None updated datetime YES None last_seen datetime YES MUL None created_by int(10) unsigned YES None updated_by int(10) unsigned YES None status char(1) YES None fax char(30) YES None
>>> migrations.migrate(0) >>> print(site.db('describe users')) Field Type Null Key Default Extra ---------- ---------------- ---- --- ------- -------------- id int(10) unsigned NO PRI None auto_increment username char(50) NO UNI None password varchar(125) YES None first_name char(40) YES None last_name char(40) YES None email char(60) YES MUL None phone char(30) YES None created datetime YES None updated datetime YES None last_seen datetime YES MUL None created_by int(10) unsigned YES None updated_by int(10) unsigned YES None status char(1) YES None
>>> migrations.revisions.zap()
-
migrate(target=None)¶ migrate to a target version
Target is the desired version. If no target is supplied the migrations required to get to the most up to date version are applied.
-
-
class
zoom.migrations.StartMigration(db)¶ Bases:
zoom.migrations.MigrationStart Migration
This is a starting state migration. It serves as a starting point for the system before any migrations were applied and does not itself apply any data transformations. This migration should be used as the first element of all migration sequences.
In theory, migrating back to this state should put the database back into its original state. By “in theory” we mean that assuming all of the applied migrations are completely revertable which may not be the case in all cases.
-
class
zoom.migrations.SystemMigrationRecord¶ Bases:
zoom.utils.RecordMigration Record
zoom.models module¶
zoom.models
common models
-
zoom.models.Attachment¶ alias of
zoom.models.SystemAttachment
-
class
zoom.models.Group¶ Bases:
zoom.utils.RecordZoom Users Group
>>> zoom.system.site = site = zoom.sites.Site() >>> groups = Groups(site.db) >>> group = groups.first(name='users')
>>> user = site.users.first(username='admin') >>> group.allows(user, 'edit') True
>>> group.key '2'
>>> group.url '/admin/groups/2'
>>> group.link '<a href="/admin/groups/2" name="link-to-users">users</a>'
>>> group.roles {4}
>>> zoom.utils.pp(group.apps) { 10, 12, 20, 28, 29 }
>>> groups.first(name='everyone').subgroups {2, 3}
>>> groups.first(name='users').user_ids [2] >>> {u.username for u in site.users.get(groups.first(name='users').user_ids)} {'user'}
-
add_user(user)¶
-
allows(user, action)¶
-
apps¶ Return set of apps that group can access
-
get_users()¶
-
key¶
-
link¶ user as link
-
roles¶
-
subgroups¶ Return set of subgroups that are part of this group
-
url¶ user view url
-
user_ids¶ Return list of user IDs of users that are in the group
-
users¶ Return list of users that are part of this group
-
-
class
zoom.models.Groups(db, entity=<class 'zoom.models.Group'>)¶ Bases:
zoom.records.RecordStore-
locate(locator)¶ locate a group whether it is referred to by reference, id or name
-
-
class
zoom.models.Member¶ Bases:
zoom.utils.Record
-
class
zoom.models.Members(db, entity=<class 'zoom.models.Member'>)¶ Bases:
zoom.records.RecordStore
-
class
zoom.models.Model¶ Bases:
zoom.utils.DefaultRecordModel Superclass
Provide basic model properties and functions.
Subclass this to create a Model that can be stored in a RecordStore, EntityStore or some other type of store.
Assumes every record has an id attribute. If not, you will need to provide one via an additional property defined in the subclass.
The key can end up being just the str of the id, however it is provided separately to make it easy to provide human friendly keys typically used in REST style URLs. If used this way the key should generated such that it is unique for each record.
>>> zoom.system.site = site = zoom.sites.Site() >>> zoom.system.request = zoom.utils.Bunch(route=[]) >>> class MyModel(Model): ... pass >>> thing = MyModel(name='Pat Smith')
>>> thing.name 'Pat Smith'
>>> thing.key 'pat-smith'
>>> url_for_item('pat-smith') '/pat-smith'
>>> thing.url '/pat-smith'
>>> thing.link '<a href="/pat-smith" name="link-to-pat-smith">Pat Smith</a>'
>>> thing.allows('user', 'edit') False
-
allows(user, action)¶
-
key¶ Return the key
-
link¶ Return a link
-
url¶ Return a valid URL
-
-
class
zoom.models.SystemAttachment¶ Bases:
zoom.utils.Record
-
zoom.models.get_users(db, group)¶ Get users of a Group
Gets the users that are members of a group from a given database.
>>> site = zoom.sites.Site() >>> users_group = Groups(site.db).first(name='users') >>> get_users(site.db, users_group) {2}
-
zoom.models.handler(request, handler, *rest)¶
zoom.mvc module¶
zoom.mvc
classes to support the model, view, controller pattern
-
class
zoom.mvc.Controller(model=None, **kwargs)¶ Bases:
zoom.mvc.DispatcherControls a Model
Use this class when an action is going to change the state of the model.
-
class
zoom.mvc.Dispatcher(model=None, **kwargs)¶ Bases:
objectdispatches actions to a method
Accepts incoming user input actions and calls the appropriate method to handle the request. Unlike the Controller and the View, the Dispatcher doesn’t alter the incoming input in any way, but rather passes it along verbatim to the method handling the request.
>>> class MyDispatcher(Dispatcher): ... def add(self, a, b): ... return a + b >>> dispatcher = MyDispatcher() >>> dispatcher('add', 1, 2) 3
-
home= None¶
-
-
class
zoom.mvc.DynamicView(model=None, **k)¶ Bases:
zoom.mvc.ViewDynamic View - experimental (may change)
A decorator class that provides views of objects dynamically loading its own templates in the process.
Within templates the object being decorated is referred to as self. Any attribtues or properties can be simply accessed using self.<name> for whatever the name is. Templates are rendered using python format() function so object structures can be taversed in the usual way within templates.
The object optionally passed as the first parameter upon construction is referred to as self.model. Additional objects can be added as keyword parameters, which can then also be referenced with self.<name>.
-
asset_types= ['html', 'css', 'js']¶
-
fill_js(script, obj)¶ Fill js tags
DynamicView object attributes and properties can be accessed from their accompanying .js content via a {self.<name>} reference.
This method is responsible for filling in these tags and can be overridden by subclasses of DynamicView if a different behaviour is desired.
-
get_assets(name=None)¶ Get view assets
-
index()¶ return the default rendered view
-
render(view=None)¶ Render the view
-
-
class
zoom.mvc.View(model=None, **kwargs)¶ Bases:
zoom.mvc.DispatcherViews a model
Use to view a model without altering it.
>>> class MyView(View): ... def index(self): ... return 'index page' ... def show(self, item): ... return 'showing %s' % item ... def throw(self, item): ... raise Exception('thrown') >>> view = MyView() >>> view() 'index page' >>> view('100') 'showing 100' >>> view('100', data=dict(d='extra')) 'showing 100'
>>> thrown = False >>> try: ... view('throw') ... except Exception: ... thrown = True >>> thrown True
-
show(*args, **kwargs)¶ View a specific item (stub)
-
-
zoom.mvc.as_attr(text)¶ Replace hyphens with underscores
>>> as_attr('this-page') 'this_page'
-
zoom.mvc.dispatch(*args)¶ Create and call dispatchers in order
Returns a function that will handle a request by trying each argument in succession. If the argument is a Dispatcher it will be created before being called. If it is a callable, it will be called as-is. As soon as one of them returns a response we exit. If none of the returns a response we return None, which generally results in a 404.
>>> class MyView(View): ... def index(self): ... return 'home page' ... def show(self, key): ... return 'showing %s' % key >>> main = zoom.dispatch(MyView)
>>> main((), zoom.utils.Bunch(data={})) 'home page'
>>> main(('100',), zoom.utils.Bunch(data={})) 'showing 100'
-
zoom.mvc.evaluate(obj, name, route, data)¶ Get the value of an attribute
>>> thing = zoom.utils.Bunch(name='Thing', show=lambda a, name: 'showing %s' % name) >>> route, data = ('app',), {'name': 'one'} >>> evaluate(thing, 'name', route, data) 'Thing' >>> evaluate(thing, 'show', route, data) 'showing one'
Remove buttons from input data
>>> data = dict(name='Pat', age=20, save_button='Save') >>> zoom.utils.pp(remove_buttons(data)) [ { "save_button": "Save" }, { "age": 20, "name": "Pat" } ]
zoom.packages module¶
zoom.packages
Provide a simple shorthand way to include external components in projects.
-
zoom.packages.get_registered_packages()¶ Returns the list of packages known to the site
>>> import zoom.request >>> zoom.system.request = zoom.request.Request(dict(PATH_INFO='/')) >>> zoom.system.site = zoom.site.Site(zoom.system.request) >>> zoom.system.request.app = zoom.utils.Bunch(packages={})
>>> packages = get_registered_packages() >>> 'c3' in packages True
-
zoom.packages.load(pathname)¶ Load a packages file into a dict
-
zoom.packages.requires(*package_names)¶ Inform framework of the packages required for rendering
>>> import zoom.request >>> request = zoom.request.Request(dict(PATH_INFO='/')) >>> zoom.system.site = zoom.site.Site(request) >>> zoom.system.parts = zoom.Component()
>>> requires('c3') >>> libs = zoom.system.parts.parts['libs'] >>> print('\n'.join(list(libs))) https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.15/c3.min.js
>>> zoom.system.parts = zoom.Component() >>> requires('jquery-ui') >>> libs = zoom.system.parts.parts['libs'] >>> print('\n'.join(list(libs))) //code.jquery.com/jquery-3.3.1.min.js //code.jquery.com/ui/1.12.1/jquery-ui.min.js
>>> try: ... requires('d4') ... except Exception as e: ... 'Missing required' in str(e) and 'raised!' 'raised!'
zoom.page module¶
zoom.page
-
class
zoom.page.ClearSearch(model=None, **k)¶ Bases:
zoom.mvc.DynamicView
-
class
zoom.page.Page(content, *args, **kwargs)¶ Bases:
objecta web page
-
header()¶ return page header
-
helpers(request)¶ provide page helpers
-
render(request)¶ render page
-
-
class
zoom.page.PageHeader(model=None, **k)¶ Bases:
zoom.mvc.DynamicViewpage header
-
action_items¶
-
search_box¶
-
subtitle¶
-
title¶
-
-
class
zoom.page.SearchBox(model=None, **k)¶ Bases:
zoom.mvc.DynamicView-
clear¶
-
clear_url= '<dz:request_path>/clear'¶
-
request_path= '<dz:request_path>'¶
-
-
zoom.page.page¶ alias of
zoom.page.Page
zoom.profiler module¶
performance profiler
-
class
zoom.profiler.SystemTimer(start_time=None)¶ Bases:
objecttime system events
>>> timer = SystemTimer() >>> timer.add('got here') >>> timer.add('got there')
>>> import time >>> timer.time('slow step', time.sleep, 0.1)
>>> report = timer.report() >>> len(report.splitlines()) 7
>>> len(timer.data) 5
-
add(comment)¶ add a measure to the system timer log
-
data¶
-
labels¶
-
report()¶ print a report of the timed events
-
time(name, function, *args, **kwargs)¶
-
-
zoom.profiler.get_profile_data(profiler)¶ Capture the stdout printout of the code profiler
>>> class Profiler(object): ... def print_stats(self): ... print('the stats!') >>> get_profile_data(Profiler()) 'the stats!\n'
-
zoom.profiler.handler(request, handler, *rest)¶ Handle profiled requests
-
zoom.profiler.profiled(request, handler, *rest)¶
-
zoom.profiler.round(value)¶ Round a decimal value
>>> round(Decimal(1.23422)) Decimal('1.234')
zoom.queues module¶
zoom.queues
message queues
-
class
zoom.queues.Queues(db=None)¶ Bases:
objectmessages
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> t.peek() 'hey!'
-
clear()¶
-
get(name, newest=None)¶
-
stats()¶
-
topic(name, newest=None)¶
-
topics()¶
-
-
class
zoom.queues.Topic(name, newest=None, db=None)¶ Bases:
objectmessage topic
-
call(*messages, delay=0.1, timeout=15)¶ send messages and wait for responses
-
clear()¶ clear the topic
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> t.send('hey!', 'you!') [1, 2] >>> len(t) 2 >>> t.clear() >>> len(t) 0
-
handle(f, timeout=0, delay=0.1, one_pass=False)¶ respond to and consume messages
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> def echo(m): ... if m == 'quit': raise StopHandling ... print('got', repr(m)) >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> t.put('quit') 3 >>> t.handle(echo) got 'hey!' got 'you!' 2
-
join(jobs, delay=0.1, timeout=15)¶ wait for responses for consumers
NOTE: the assumption at this point is that any provided delay or timeout applies to all jobs. If jobs need varying arguments then mutliple calls to join should be considered.
-
last()¶ get row_id of the last (newest) message in the topic
-
len(newest=None)¶ return the number of messages in the topic
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> t.len() 2
-
listen(f, delay=0.1, meta=False)¶ observe but don’t consume messages
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> def echo(m): ... print(m) ... return m == 'you!' >>> t.listen(echo) hey! you! 2
>>> t1 = messages.topic('test_topic1') >>> t2 = messages.topic('test_topic2') >>> t3 = messages.topic(None)
>>> t1.put('hey!') 3 >>> t2.put('you!') 4 >>> def echo(m): ... print(m) ... return m == 'you!' >>> t3.listen(echo) hey! you! 2
-
peek(newest=None)¶ return the next message but don’t remove it
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> t.peek() >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> t.peek() 'hey!' >>> t.peek() 'hey!'
-
perform(task, *args, **kwargs)¶ consume a single message and perform task with it
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> def echo(m): ... print('got', repr(m)) >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> t.perform(echo) got 'hey!' True >>> t.perform(echo) got 'you!' True >>> t.perform(echo) False
-
poll(newest=None)¶ peek at the next message and increment internal pointer
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> t.newest -1 >>> t.poll() 'hey!' >>> t.newest 1 >>> t.poll() 'you!'
>>> raised = False >>> try: ... t.poll() ... except EmptyException: ... raised = True >>> raised True
>>> t.newest = -1 >>> t.poll() 'hey!'
-
pop()¶ read next message and remove it from the topic
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> t.len() 2 >>> t._peek() (1, 'test_topic', 'hey!') >>> t.pop() 'hey!' >>> t.len() 1 >>> t.pop() 'you!' >>> t.len() 0 >>> t.pop() >>> t.newest = -1 >>> raised = False >>> try: ... t._pop() ... except EmptyException: ... raised = True >>> raised True
-
process(f)¶ respond to and consume current messages
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> def echo(m): ... if m == 'quit': raise StopProcessing ... print('got', repr(m)) >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> t.put('quit') 3 >>> t.process(echo) got 'hey!' got 'you!' 2 >>> t.process(echo) 0
-
put(message)¶ put a message in the topic
-
send(*messages)¶ send list of messages
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> t.send('hey!', 'you!') [1, 2] >>> t.peek() 'hey!' >>> t.peek() 'hey!'
-
wait(delay=0.1, timeout=15)¶ wait for a message to arrive and return it
>>> messages = setup_test() >>> t = messages.get('test_topic') >>> t.put('hey!') 1 >>> t.put('you!') 2 >>> t.wait() 'hey!' >>> t.wait() 'you!'
-
-
exception
zoom.queues.EmptyException¶ Bases:
Exception
-
exception
zoom.queues.WaitException¶ Bases:
Exception
-
exception
zoom.queues.StopListening¶ Bases:
Exception
-
exception
zoom.queues.StopHandling¶ Bases:
Exception
-
exception
zoom.queues.StopProcessing¶ Bases:
Exception
zoom.records module¶
zoom.records
record store
-
class
zoom.records.RecordStore(db, record_class=<class 'dict'>, name=None, key='id')¶ Bases:
zoom.store.Storestores records
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> people.kind 'person' >>> joe = Person(name='Joe', age=20, birthdate=datetime.date(1992,5,5)) >>> repr(joe) == ( ... "<Person {'name': 'Joe', 'age': 20, " ... "'birthdate': datetime.date(1992, 5, 5)}>" ... ) True >>> people.put(joe) 1 >>> person = people.get(1) >>> repr(person) == ( ... "<Person {'name': 'Joe', 'age': 20, " ... "'birthdate': datetime.date(1992, 5, 5)}>" ... ) True
>>> sally = Person(name='Sally', kids=0, ... birthdate=datetime.date(1992,5,5)) >>> people.put(sally) 2
>>> sally = people.find(name='Sally') >>> repr(sally) == ( ... "[<Person {'name': 'Sally', " ... "'kids': 0, 'birthdate': datetime.date(1992, 5, 5)}>]" ... ) True
>>> sally = people.first(name='Sally') >>> repr(sally) == ( ... "<Person {'name': 'Sally', " ... "'kids': 0, 'birthdate': datetime.date(1992, 5, 5)}>" ... ) True
>>> sally.kids += 1 >>> people.put(sally) 2
>>> repr(people.first(name='Sally')) == ( ... "<Person {'name': 'Sally', " ... "'kids': 1, 'birthdate': datetime.date(1992, 5, 5)}>" ... ) True
>>> sally = people.first(name='Sally') >>> sally.kids += 1 >>> people.put(sally) 2
>>> repr(people.first(name='Sally')) == ( ... "<Person {'name': 'Sally', " ... "'kids': 2, 'birthdate': datetime.date(1992, 5, 5)}>" ... ) True >>> sally = people.first(name='Sally') >>> sally.kids += 1 >>> people.put(sally) 2
>>> repr(people.first(name='Sally')) == ( ... "<Person {'name': 'Sally', " ... "'kids': 3, 'birthdate': datetime.date(1992, 5, 5)}>" ... ) True
>>> class Account(Record): pass >>> class Accounts(RecordStore): pass >>> accounts = Accounts(db, Account, key='account_id') >>> accounts.kind 'account'
>>> account = Account(name='Joe', added=datetime.date(1992,5,5)) >>> repr(account) == ( ... "<Account {'name': 'Joe', 'added': datetime.date(1992, 5, 5)}>" ... ) True >>> id = accounts.put(account) >>> id 1 >>> accounts.put(Account(name='Sam', added=datetime.date(2001,1,1))) 2 >>> accounts.put(Account(name='Sal', added=datetime.date(2001,1,1))) 3
>>> account = accounts.get(1) >>> print(accounts) account account_id name added ---------- ---- ---------- 1 Joe 1992-05-05 2 Sam 2001-01-01 3 Sal 2001-01-01 3 account records
>>> print(accounts.first(name='Sam')) Account account_id ..........: 2 name ................: 'Sam' added ...............: datetime.date(2001, 1, 1)
>>> print(accounts.find(added=datetime.date(2001, 1, 1))) account account_id name added ---------- ---- ---------- 2 Sam 2001-01-01 3 Sal 2001-01-01 2 account records
>>> accounts.delete(2) [2] >>> print(accounts) account account_id name added ---------- ---- ---------- 1 Joe 1992-05-05 3 Sal 2001-01-01 2 account records
-
all()¶ Retrieves all entities
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sally', age=25)) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Joe', age=25)) >>> repr(people.all()) == ( ... "[<Person {'name': 'Sally', 'age': 25}>, " ... "<Person {'name': 'Sam', 'age': 25}>, " ... "<Person {'name': 'Joe', 'age': 25}>]" ... ) True
-
delete(*args, **kwargs)¶ delete a record
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sally', age=25)) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Joe', age=25)) >>> joe = people.get(id) >>> id 3 >>> bool(joe) True >>> joe <Person {'name': 'Joe', 'age': 25}> >>> people.delete(id) [3] >>> joe = people.get(id) >>> joe >>> bool(joe) False
>>> bool(people.find(name='Sally')) True >>> people.delete(name='Sallie') >>> bool(people.find(name='Sally')) True >>> people.delete() >>> people.delete(name='Sally') [1] >>> bool(people.find(name='Sally')) False
>>> db.close()
-
exists(keys=None)¶ tests for existence of a record
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sally', age=25)) >>> id 1 >>> sally = people.get(id) >>> sally <Person {'name': 'Sally', 'age': 25}> >>> people.exists(1) True >>> people.exists(2) False >>> people.exists([1, 2]) [True, False] >>> id = people.put(Person(name='Sam', age=25)) >>> people.exists([1, 2]) [True, True]
-
filter(function)¶ finds records that satisfiy filter
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sam Adam Jones', age=25)) >>> id = people.put(Person(name='Sally Mary Smith', age=55)) >>> id = people.put(Person(name='Bob Marvin Smith', age=25)) >>> list(people.filter(lambda a: 'Mary' in a.name)) [<Person {'name': 'Sally Mary Smith', 'age': 55}>] >>> repr(list(people.filter(lambda a: a.age < 40))) == ( ... "[<Person {'name': 'Sam Adam Jones', 'age': 25}>, " ... "<Person {'name': 'Bob Marvin Smith', 'age': 25}>]" ... ) True
-
find(**kwargs)¶ finds entities that meet search criteria
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Sally', age=55)) >>> id = people.put(Person(name='Bob', age=25))
>>> print(people.find(age=25)) person _id name age --- ---- --- 1 Sam 25 3 Bob 25 2 person records
>>> people.find(name='Sam') [<Person {'name': 'Sam', 'age': 25}>] >>> len(people.find(name='Sam')) 1
-
first(**kwargs)¶ finds the first record that meet search criteria
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Sally', age=55)) >>> id = people.put(Person(name='Bob', age=25)) >>> people.first(age=5) >>> people.first(age=25) <Person {'name': 'Sam', 'age': 25}>
-
get(keys)¶ retrives records
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(**{'name': 'Sam', 'age':15})) >>> sam = people.get(id) >>> sam <Person {'name': 'Sam', 'age': 15}> >>> people.put(Person(name='Jim',age=21)) 2 >>> print(people) person _id name age --- ---- --- 1 Sam 15 2 Jim 21 2 person records
>>> people.put(Person(name='Alice',age=29)) 3 >>> print(people.get([1, 3])) person _id name age --- ----- --- 1 Sam 15 3 Alice 29 2 person records
-
get_attributes()¶ get complete set of attributes for the record type
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> sam = Person(**{'name': 'Sam', 'age':15}) >>> sorted(sam.keys()) ['age', 'name'] >>> id = people.put(sam) >>> people.get_attributes() ['name', 'age', 'kids', 'birthdate']
-
id_name¶
-
last(**kwargs)¶ finds the last record that meet search criteria
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Sally', age=55)) >>> id = people.put(Person(name='Bob', age=25)) >>> people.last(age=5) >>> people.last(age=25) <Person {'name': 'Bob', 'age': 25}>
-
put(record)¶ stores a record
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> sally = Person(name='Sally', age=25) >>> sally <Person {'name': 'Sally', 'age': 25}> >>> id = people.put(Person(name='Sally', age=25)) >>> id 1 >>> sally <Person {'name': 'Sally', 'age': 25}> >>> sally = people.get(id) >>> sally <Person {'name': 'Sally', 'age': 25}> >>> sally.age = 35 >>> people.put(sally) 1 >>> person = people.get(id) >>> person <Person {'name': 'Sally', 'age': 35}> >>> id = people.put({'name':'James', 'age':15}) >>> id 2 >>> people.get(id) <Person {'name': 'James', 'age': 15}>
-
search(text)¶ search for records that match text
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sam Adam Jones', age=25)) >>> id = people.put(Person(name='Sally Mary Smith', age=55)) >>> id = people.put(Person(name='Bob Marvin Smith', age=25))
>>> repr(list(people.search('smi'))) == ( ... "[<Person {'name': 'Sally Mary Smith', 'age': 55}>, " ... "<Person {'name': 'Bob Marvin Smith', 'age': 25}>]" ... ) True
>>> list(people.search('bo smi')) [<Person {'name': 'Bob Marvin Smith', 'age': 25}>]
>>> list(people.search('smi 55')) [<Person {'name': 'Sally Mary Smith', 'age': 55}>]
-
zap()¶ deletes all entities of the given kind
>>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sally', age=25)) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Joe', age=25)) >>> repr(people.all()) == ( ... "[<Person {'name': 'Sally', 'age': 25}>, " ... "<Person {'name': 'Sam', 'age': 25}>, " ... "<Person {'name': 'Joe', 'age': 25}>]" ... ) True
>>> people.zap() >>> people.all() []
-
-
class
zoom.records.Result(rows, storage)¶ Bases:
objectrows resulting from a method call
-
zoom.records.get_result_iterator(rows, storage)¶ returns an iterator that iterates over the rows and zips the names onto the items being iterated so they come back as dicts
-
zoom.records.table_of(klass, db=None)¶ Return a table of Records of the given class
The klass parameter can be a subclass of zoom.Model or a table name. If a zoom.Model is provided the actual table name is derived from the class name. If the table name is provivded then it’s taken as-is.
Uses the current site database if none is provided.
>>> site = zoom.sites.Site() >>> users = table_of('users', site.db) >>> user = users.first(username='admin') >>> user['first_name'] 'Admin'
zoom.render module¶
zoom.render
rendering tools
-
zoom.render.add_helpers(*providers)¶ Add helpers to the helpers registry
-
zoom.render.apply_helpers(template, obj, providers)¶ employ helpers to fill in a template
>>> class User(object): pass >>> user = User() >>> user.name = 'World' >>> apply_helpers('Hello {{name}}!', user, {}) 'Hello World!'
>>> apply_helpers('Hello <dz:other>!', user, [{'other': 'Sam'}]) 'Hello Sam!'
>>> apply_helpers('Hello <dz:other>!', user, {}) 'Hello <dz:other>!'
>>> apply_helpers('Hello {{other}}!', user, {}) 'Hello {{other}}!'
-
zoom.render.handler(request, handle, *rest)¶ Render handler
-
zoom.render.render(template, *providers, **helpers)¶ Render a template
Applies providers and helpers to the template to fill in the tags creating completed content.
>>> zoom.system.providers = [] >>> render('test') 'test'
>>> name = 'Sally' >>> render('Hello {{name}}!', name=name) 'Hello Sally!'
>>> def name(): return 'Joe' >>> render('Hello {{name}}!', dict(name=name)) 'Hello Joe!'
zoom.request module¶
zoom.request
Web requsets.
-
class
zoom.request.Request(env=None, instance=None, start_time=None, username=None)¶ Bases:
objectA web request
>>> url = 'http://localhost/test?name=joe&age=40' >>> request = build(url) >>> request.body_consumed False >>> request.data == {'age': '40', 'name': 'joe'} True >>> request.path == '/test' True >>> request.route == ['test'] True >>> request.helpers()['host'] 'localhost' >>> request.method 'GET' >>> request.port '80'
>>> request = build(url) >>> request.body == sys.stdin True >>> request.body_consumed True >>> request.data == {} True
-
body¶ access the body in raw form
-
data¶ access the body as data
-
elapsed¶ Elapsed time
-
helpers()¶ provide helpers
-
json_body¶ access and parse the body as json
-
parent_path¶ Path of resource parent
-
-
zoom.request.build(url, data=None, instance_path=None)¶ Build a request object
>>> request = build('http://localhost') >>> request.path '' >>> request.host 'localhost'
>>> request = build('http://testsite.local:8000/info') >>> request.host 'testsite.local' >>> request.port 8000 >>> request.path '/info'
>>> request = build('http://localhost/hello') >>> request.path '/hello'
>>> build('https://localhost/hello?name=Sally').data {'name': 'Sally'}
-
zoom.request.calc_domain(host)¶ calculate just the high level domain part of the host name
Remove the port and the www. if it exists.
>>> calc_domain('www.dsilabs.ca:8000') 'dsilabs.ca'
>>> calc_domain('test.dsilabs.ca:8000') 'test.dsilabs.ca'
-
zoom.request.get_instance(directory)¶ Figures out which instance to run
This function will first check to see if the instance directory passed contains a sites directory, the miniumum bar to be considered an instance directory. If so, it returns it’s absolute path.
If not, it will attempt to locate a Zoom configuration file which specifies the instance path.
If none of the above methods succeed it raises an exception.
-
zoom.request.get_library_instance()¶ get the location of the library instance
If the user doesn’t provide an instance whith which to run the server then the request assumes the user wants to run using the built-in instance. This is most common in development environments.
-
zoom.request.get_parent_dir()¶ get the directory above the current directory
-
zoom.request.get_web_vars(env)¶ return web parameters as a dict
-
zoom.request.handler(request, handle, *rest)¶ request handler
-
zoom.request.make_request_id()¶ make a unique request id
-
zoom.request.strim(url)¶ trim off the trailing ‘/’ character if there is one
>>> strim('http://localhost/') 'http://localhost'
zoom.response module¶
zoom.response
Various common web responses.
Note: We have chosen to use a dict for the headers even though technically the HTTP spec allows for multiple values by the same name because the uses cases for this seem to be very obscure and the benefits of not duplicating header entries that the dict provides seem to outweigh supporting obscure and generally not recommend use cases. The only use case where this is more commonly used is in cookies, but we deal with that special case in the cookie module.
-
class
zoom.response.BinaryResponse(content, max_age=86400)¶ Bases:
zoom.response.ResponseGeneric binary response
use max_age=0 to avoid caching
>>> response = BinaryResponse(b'binary data') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: application/octet-stream\n' ... b'Cache-Control: max-age=86400\n' ... b'ETag: e1a49b59e\n' ... b'Content-length: 11\n\n' ... b'binary data' ... ) >>> response.render() == expected True
-
class
zoom.response.CSSResponse(content, max_age=86400)¶ Bases:
zoom.response.ResponseCSS response
>>> response = CSSResponse(b'mycss') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: text/css;charset=utf-8\n' ... b'Cache-Control: max-age=86400\n' ... b'ETag: 12a586855\n' ... b'Content-length: 5\n\n' ... b'mycss' ... ) >>> response.render() == expected True
-
class
zoom.response.FileResponse(filename, content=None)¶ Bases:
zoom.response.ResponseFile download response
>>> response = FileResponse('file.txt', content=b'mydata') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: application/octet-stream\n' ... b'Content-Disposition: attachment; filename="file.txt"\n' ... b'Cache-Control: no-cache\n' ... b'Content-length: 6\n\n' ... b'mydata' ... ) >>> response.render() == expected True
-
class
zoom.response.GIFResponse(content)¶ Bases:
zoom.response.ResponseGIF image response
>>> response = GIFResponse(b'myimage') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: image/gif\n' ... b'Content-length: 7\n\n' ... b'myimage' ... ) >>> response.render() == expected True
-
class
zoom.response.HTMLResponse(content='', status='200 OK')¶ Bases:
zoom.response.TextResponseHTML response
>>> HTMLResponse('test123').render() == ( ... b'Status: 200 OK\n' ... b'Content-type: text/html\n' ... b'Cache-Control: no-cache\n' ... b'X-FRAME-OPTIONS: DENY\n' ... b'Content-length: 7\n\n' ... b'test123' ... ) True
>>> HTMLResponse('test123').as_wsgi() == ( ... '200 OK', ... [ ... ('Content-type', 'text/html'), ... ('Cache-Control', 'no-cache'), ... ('X-FRAME-OPTIONS', 'DENY'), ... ('Content-length', '7') ... ], ... b'test123' ... ) True
-
class
zoom.response.ICOResponse(content, max_age=86400)¶ Bases:
zoom.response.ResponseICO image response
>>> response = ICOResponse(b'myicon') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: image/x-icon\n' ... b'Cache-Control: max-age=86400\n' ... b'ETag: 78d2485ff\n' ... b'Content-length: 6\n\n' ... b'myicon' ... ) >>> response.render() == expected True
-
render_doc()¶ Renders the payload
-
-
class
zoom.response.JPGResponse(content)¶ Bases:
zoom.response.ResponseJPG image response
>>> response = JPGResponse(b'myimage') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: image/jpeg\n' ... b'Content-length: 7\n\n' ... b'myimage' ... ) >>> response.render() == expected True
-
class
zoom.response.JSONResponse(content, indent=4, sort_keys=True, ensure_ascii=False, **kwargs)¶ Bases:
zoom.response.TextResponseJSON response
>>> response = JavascriptResponse(b'myjson') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: application/javascript\n' ... b'Cache-Control: max-age=86400\n' ... b'ETag: f97258d47\n' ... b'Content-length: 6\n\n' ... b'myjson' ... ) >>> response.render() == expected True
-
class
zoom.response.JavascriptResponse(content, max_age=86400)¶ Bases:
zoom.response.ResponseJavascript response
>>> response = JavascriptResponse(b'myjs') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: application/javascript\n' ... b'Cache-Control: max-age=86400\n' ... b'ETag: 8be4a11f3\n' ... b'Content-length: 4\n\n' ... b'myjs' ... ) >>> response.render() == expected True
-
class
zoom.response.PDFResponse(filename, content=None)¶ Bases:
zoom.response.FileResponsePDF file download response
>>> response = PDFResponse('file.pdf', content=b'mydata') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: application/pdf\n' ... b'Cache-Control: no-cache\n' ... b'Content-length: 6\n\n' ... b'mydata' ... ) >>> response.render() == expected True
-
class
zoom.response.PNGResponse(content, max_age=86400)¶ Bases:
zoom.response.ResponsePNG image response
>>> response = PNGResponse(b'myimage') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: image/png\n' ... b'Cache-Control: max-age=86400\n' ... b'ETag: b1a9acaf2\n' ... b'Content-length: 7\n\n' ... b'myimage' ... ) >>> response.render() == expected True
-
class
zoom.response.RedirectResponse(url)¶ Bases:
zoom.response.TextResponseRedirect response
>>> response = RedirectResponse('/') >>> response.as_wsgi() ('302 Found', [('Location', '/'), ('Content-length', '0')], b'')
-
class
zoom.response.Response(content=b'', status='200 OK', headers=None)¶ Bases:
objectweb response
>>> response = Response(b'this is it') >>> response.render() b'Status: 200 OK\nContent-length: 10\n\nthis is it' >>> response.as_wsgi() ('200 OK', [('Content-length', '10')], b'this is it')
-
as_wsgi()¶ Render the entire response
-
render()¶ Renders the entire response
-
render_doc()¶ Renders the payload
-
-
class
zoom.response.SiteNotFoundResponse(request)¶ Bases:
zoom.response.HTMLResponseSite 404 Not Found response
>>> request = zoom.utils.Bunch( ... protocol='http', ... host='localhost', ... path='/', ... ip_address='127.0.0.1', ... module='index', ... request_id=1234, ... ) >>> response = SiteNotFoundResponse(request) >>> 'ZOOM' in str(response.render()) True
-
class
zoom.response.TTFResponse(content, max_age=86400)¶ Bases:
zoom.response.ResponseTrue Type Font response
>>> response = TTFResponse(b'myfont') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: application/font-sfnt\n' ... b'Cache-Control: max-age=86400\n' ... b'ETag: 794c8f9c8\n' ... b'Content-length: 6\n\n' ... b'myfont' ... ) >>> response.render() == expected True
-
class
zoom.response.TextResponse(content='', status='200 OK')¶ Bases:
zoom.response.ResponsePlan text response
>>> response = TextResponse('mytext') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: text\n' ... b'Cache-Control: no-cache\n' ... b'Content-length: 6\n\n' ... b'mytext' ... ) >>> response.render() == expected True
-
render_doc()¶ Renders the payload
-
-
class
zoom.response.WOFF2Response(content, max_age=86400)¶ Bases:
zoom.response.ResponseWeb Open Font 2 Format response
>>> response = WOFF2Response(b'myfont') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: font/woff2\n' ... b'Cache-Control: max-age=86400\n' ... b'ETag: 794c8f9c8\n' ... b'Content-length: 6\n\n' ... b'myfont' ... ) >>> response.render() == expected True
-
class
zoom.response.WOFFResponse(content, max_age=86400)¶ Bases:
zoom.response.ResponseWeb Open Font Format response
>>> response = WOFFResponse(b'myfont') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: application/font-woff\n' ... b'Cache-Control: max-age=86400\n' ... b'ETag: 794c8f9c8\n' ... b'Content-length: 6\n\n' ... b'myfont' ... ) >>> response.render() == expected True
-
class
zoom.response.XMLResponse(content='')¶ Bases:
zoom.response.ResponseXML response
>>> response = XMLResponse('myxml') >>> expected = ( ... b'Status: 200 OK\n' ... b'Content-type: text/xml\n' ... b'Cache-Control: no-cache\n' ... b'Content-length: 26\n\n' ... b'<?xml version="1.0"?>myxml' ... ) >>> response.render() == expected True
-
render_doc()¶ Renders the payload
-
zoom.server module¶
zoom.server
runs an instance of Zoom using the builtin Python WSGI server.
>>> server = WSGIApplication()
-
class
zoom.server.WSGIApplication(instance='.', handlers=None, username=None)¶ Bases:
objecta WSGI Application wrapper
-
class
zoom.server.ZoomWSGIRequestHandler(request, client_address, server)¶ Bases:
wsgiref.simple_server.WSGIRequestHandler-
log_message(fmt, *args)¶ Log an arbitrary message.
This is used by all other logging functions. Override it if you have specific logging wishes.
The first argument, FORMAT, is a format string for the message to be logged. If the format string contains any % escapes requiring parameters, they should be specified as subsequent arguments (it’s just like printf!).
The client ip and current date/time are prefixed to every message.
-
logger= <Logger zoom.server (WARNING)>¶
-
-
zoom.server.application(environ, start_response)¶ run Zoom using external WSGI Server
Assumes that the WSGI script is located one directory below the instance directory. In an typical installation the instance directory would be /work/web and the WSGI script would be located in /work/web/www.
If you need to launch from somewhere else just build a function like this of your own and create the WSGIApplication instance using a path of your choosing.
>>> save_dir = os.getcwd() >>> try: ... env = dict(DOCUMENT_ROOT=zoom.tools.zoompath('web', 'www')) ... response = application(env, lambda a, b: None) ... finally: ... os.chdir(save_dir) >>> len(response) 1
-
zoom.server.debug(environ, start_response)¶ Configuration Debugging App
-
zoom.server.reset_modules()¶ reset the modules to a known starting set
memorizes the modules currently in use and then removes any other modules when called again
-
zoom.server.run(port=80, instance=None, handlers=None, username=None)¶ run using internal HTTP Server
The instance variable is the path of the directory on the system where the sites folder is located. (e.g. /work/web)
-
zoom.server.run_as_cgi(environ=None, instance=None)¶ Run Zoom as a CGI script
zoom.services module¶
zoom.services
background services
-
zoom.services.run(command, returncode=False, location=None)¶ Run a shell command and return the response as a string
>>> run("echo testing") 'testing\n'
>>> run("echo testing", location="/") 'testing\n'
zoom.session module¶
zoom.session
-
class
zoom.session.Session(request)¶ Bases:
object-
destroy()¶
-
load(db, token)¶ load a session
-
new(db, timeout=60)¶ create a new session
-
save(db, timeout=60)¶ save a session
-
-
class
zoom.session.Sessions¶ Bases:
zoom.utils.Record
-
zoom.session.handler(request, handler, *rest)¶
zoom.settings module¶
zoom.settings
Classes for mananging settings.
-
class
zoom.settings.AppSettings¶ Bases:
zoom.utils.Recordsettings storage class
-
class
zoom.settings.Settings¶ Bases:
objectSettings storage class
-
clear()¶ Clear all settings
-
load()¶ get the stash value
-
save(value)¶ put the stash value
-
-
class
zoom.settings.SettingsController¶ Bases:
zoom.mvc.Controllersettings controller
-
clear()¶ clear settings
-
form= None¶
-
get_fields()¶ Get the settings fields
Override this method to provide settings fields specific to your app.
-
get_form()¶ Get the settings form
Override this method to provide a settings form specific to your app.
-
index(**kwargs)¶ show the settings form
save settings
-
-
class
zoom.settings.SettingsSection¶ Bases:
zoom.utils.Recordsettings section
-
class
zoom.settings.SiteSettings(config)¶ Bases:
objectSite Settings
-
clear()¶ Clear all settings
-
get(section, name, default=None)¶
-
items(section)¶
-
load()¶ load the settings values
-
save()¶ save the settings values
-
section(name)¶
-
update(section, values)¶
-
values¶
-
-
class
zoom.settings.SystemSettings¶ Bases:
zoom.utils.Recordsite settings
zoom.site module¶
zoom.site
-
class
zoom.site.ConfigSection¶ Bases:
zoom.utils.Recordsite configuration section
-
class
zoom.site.Site(request)¶ Bases:
objecta Zoom site
-
abs_url¶ Calculate an absolute URL for this site
-
apps¶ Return list of apps installed on this site
-
get_owner_link()¶ Returns a link for the site owner.
-
helpers()¶ provide helpers
-
settings¶
-
tracker¶ Returns a Google analytics tracker code snippet
-
-
class
zoom.site.SiteConfig(config)¶ Bases:
objectSite Config Reader
Site configuration is managed with the site.ini files provided in the site directory and the default directory.
The SiteConfig class maps unique config keywords used by the system into the section/name pairs used in the physical configuration files and provides default values in the event that no value is provided in the config files.
>>> site = zoom.sites.Site() >>> site.config.get('site', 'name') # without SiteConfig 'ZOOM' >>> conf = SiteConfig(site.config) # using SiteConfig >>> conf.site.get('name') 'ZOOM'
>>> conf.section('sessions') <ConfigSection {'secure_cookies': True}>
>>> conf.section('notasection') <ConfigSection {}>
>>> conf.site['name'] 'ZOOM'
>>> conf.site.get('notaname', 'Nope') 'Nope'
>>> conf.site.notaname == None True
>>> conf.mail.get('smtp_port') '587'
>>> conf.mail.smtp_port '587'
-
defaults= {'apps': {'index': 'content', 'home': 'home', 'login': 'login', 'path': 'apps;../../apps', 'include_basics': True}, 'error': {'users': False}, 'mail': {'smtp_host': '', 'smtp_port': '587', 'smtp_user': '', 'smtp_passwd': '', 'logo': '', 'from_addr': '', 'from_name': 'ZOOM Support', 'gnupg_home': None}, 'monitoring': {'profiling': False, 'logging': False, 'app_database': False, 'system_database': False}, 'sessions': {'secure_cookies': True}, 'site': {'name': 'ZOOM', 'url': '', 'owner_name': 'Company Name', 'owner_email': '', 'owner_url': 'https://www.dynamic-solutions.com', 'admin_email': '', 'register_email': '', 'support_email': ''}, 'theme': {'name': 'default', 'path': None}, 'users': {'default': 'guest', 'administrators_group': 'administrators', 'developers_group': 'developers', 'override': None}}¶
-
items(section)¶
-
section(name)¶
-
-
zoom.site.handler(request, next_handler, *rest)¶ install site object
zoom.sites module¶
zoom.sites
Updated Zoom sites module. Eventually, the functionality currently in zoom.site will make it’s way here.
Note: experimental
-
class
zoom.sites.BackgroundJob(name, path)¶ Bases:
objectBackground Job
-
class
zoom.sites.Site(path=None)¶ Bases:
zoom.site.Sitea Zoom site
A zoom site can be completely determined by the path to the site directory. That directory may contain a config file, apps, and other assets. If any assets are required that are not found in the site directory, the system will look in the default site as a fallback. Any site setttings not found in the site config file will be obtained from the default site. Any settings not found there will rely on built-in defaults.
This Site object is not to be confused with the zoom.site.Site object, renamed here as BasicSite, which will eventually be phased out as that functionality is brought into this module.
>>> site = Site() >>> site.name 'localhost'
>>> 'users' in site.db.get_tables() True
-
get_background_jobs()¶ Returns a dict of background jobs
>>> site = Site() >>> site.name 'localhost' >>> site.get_background_jobs() [BackgroundJob('hello')]
-
-
class
zoom.sites.SiteProxy(path)¶ Bases:
objectSite proxy
-
run_background_jobs()¶ Run background jobs
Iterates through the apps in the site and calls run_background_jobs on each one.
>>> import zoom >>> site_directory = zoom.tools.zoompath('web/sites/localhost') >>> site = SiteProxy(site_directory) >>> site.run_background_jobs() localhost
-
zoom.snippets module¶
zoom.snippets
-
zoom.snippets.Snippet¶ alias of
zoom.snippets.SystemSnippet
-
class
zoom.snippets.SystemSnippet¶ Bases:
zoom.utils.RecordA chunk of text (usually HTML) that can be rendered by placing the {{snippet}} tag in a document or template.
>>> db = zoom.database.setup_test() >>> snippets = get_snippets(db) >>> snippets.delete(name='test') >>> snippets.find(name='test') []
>>> t = snippets.put(Snippet(name='test', body='some text')) >>> snippets.find(name='test') [<SystemSnippet {'key': 'test', 'name': 'test', 'url': '/content/snippets/test', 'body': 'some text', 'link': '<a href="/content/snippets/test">test</a>'}>]
-
allows(user, action)¶ Item level policy
-
key¶
-
link¶ Return a link
-
url¶
-
-
zoom.snippets.get_snippets(db=None)¶
-
zoom.snippets.snippet(name, default='', variant=None)¶
zoom.sqltools module¶
zoom.sql
sql utilities
-
zoom.sqltools.setup_test()¶ setup test
-
zoom.sqltools.summarize(table, dimensions, metrics=None)¶ summarize data
>>> from zoom.records import Record, RecordStore >>> from decimal import Decimal >>> db = setup_test() >>> class Person(Record): pass >>> class People(RecordStore): pass >>> people = People(db, Person) >>> put = people.put >>> id = put(Person(name='Sam', age=25, kids=1, salary=Decimal('40000'))) >>> id = put(Person(name='Sally', age=55, kids=4, salary=Decimal('80000'))) >>> id = put(Person(name='Bob', age=25, kids=2, salary=Decimal('70000'))) >>> id = put(Person(name='Jane', age=25, kids=2, salary=Decimal('50000'))) >>> id = put(Person(name='Alex', age=25, kids=3, salary=Decimal('50000'))) >>> print(people) person _id name age kids salary --- ----- --- ---- ------ 1 Sam 25 1 40,000 2 Sally 55 4 80,000 3 Bob 25 2 70,000 4 Jane 25 2 50,000 5 Alex 25 3 50,000 5 person records
>>> print(summarize('person', ['age'])) select "*" age, count(*) n from person group by 1 union select age age, count(*) n from person group by 1
>>> print(db(summarize('person', ['age']))) age n --- - 25 4 55 1 * 5
>>> print(db(summarize('person', ['age','kids']))) age kids n --- ---- - 25 1 1 25 2 2 25 3 1 25 * 4 55 4 1 55 * 1 * 1 1 * 2 2 * 3 1 * 4 1 * * 5
>>> print(db(summarize('person', ['age','kids'], ['salary']))) age kids n salary --- ---- - ------- 25 1 1 40,000 25 2 2 120,000 25 3 1 50,000 25 * 4 210,000 55 4 1 80,000 55 * 1 80,000 * 1 1 40,000 * 2 2 120,000 * 3 1 50,000 * 4 1 80,000 * * 5 290,000
>>> people.zap() >>> print(people) Empty list
zoom.store module¶
zoom.store
key value store
-
class
zoom.store.EntityStore(db, klass=<class 'dict'>, kind=None)¶ Bases:
zoom.store.Storestores entities
>>> db = setup_test()
>>> stuff = EntityStore(db) >>> stuff.put(dict(name='Joe', age=14)) 1 >>> stuff.put(dict(name='Sally', age=34)) 2 >>> stuff.put(dict(name='Sam', age=34)) 3 >>> print(zoom.utils.RecordList(stuff.find(name='Joe'))) dict _id name age --- ---- --- 1 Joe 14 1 dict records >>> s = stuff.find(age=34) >>> print(s) dict _id name age --- ----- --- 2 Sally 34 3 Sam 34 2 dict records
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> people.kind 'person' >>> joe = Person(name='Joe', age=20, birthdate=datetime.date(1992,5,5)) >>> joe <Person {'name': 'Joe', 'age': 20, 'birthdate': datetime.date(1992, 5, 5)}> >>> people.put(joe) 1 >>> person = people.get(1) >>> person <Person {'name': 'Joe', 'age': 20, 'birthdate': datetime.date(1992, 5, 5)}> >>> sally = Person(name='Sally', kids=0, birthdate=datetime.date(1992,5,5)) >>> people.put(sally) 2 >>> sally = people.find(name='Sally') >>> sally [<Person {'name': 'Sally', 'kids': 0, 'birthdate': datetime.date(1992, 5, 5)}>] >>> sally = people.first(name='Sally') >>> sally <Person {'name': 'Sally', 'kids': 0, 'birthdate': datetime.date(1992, 5, 5)}> >>> sally.kids += 1 >>> people.put(sally) 2 >>> people.first(name='Sally') <Person {'name': 'Sally', 'kids': 1, 'birthdate': datetime.date(1992, 5, 5)}> >>> sally = people.first(name='Sally') >>> sally.kids += 1 >>> people.put(sally) 2 >>> people.first(name='Sally') <Person {'name': 'Sally', 'kids': 2, 'birthdate': datetime.date(1992, 5, 5)}> >>> sally = people.first(name='Sally') >>> sally.kids += 1 >>> people.put(sally) 2 >>> people.first(name='Sally') <Person {'name': 'Sally', 'kids': 3, 'birthdate': datetime.date(1992, 5, 5)}>
>>> class Misc(EntityStore): pass >>> misc = Misc(db, dict) >>> config_info = dict(host='database', name='somename') >>> id = misc.put(config_info) >>> x = misc.put(dict(other='this', stuff='that')) >>> my_info = misc.get(id) >>> Record(my_info) <Record {'name': 'somename', 'host': 'database'}> >>> Record(misc.get(x)) <Record {'other': 'this', 'stuff': 'that'}>
>>> people = EntityStore(db, 'person') >>> people.klass <class 'dict'> >>> people.kind 'person' >>> print(sorted(people.first(name='Sally').items())) [('__store', <EntityStore(dict)>), ('_id', 2), ('birthdate', datetime.date(1992, 5, 5)), ('kids', 3), ('name', 'Sally')] >>> print(Person(people.first(name='Sally'))) Person name ................: 'Sally' kids ................: 3 birthdate ...........: datetime.date(1992, 5, 5) >>> EntityStore(db, 'person').first(name='Joe')['age'] 20 >>> >>> name = 'somename' >>> id = misc.put(dict(host='database', name=name)) >>> my_info = misc.get(id) >>> assert type(my_info['name'])==type(name)
-
all()¶ Retrieves all entities
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sally', age=25)) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Joe', age=25)) >>> people.all() [<Person {'name': 'Sally', 'age': 25}>, <Person {'name': 'Sam', 'age': 25}>, <Person {'name': 'Joe', 'age': 25}>] >>> db.close()
-
delete(*args, **kwargs)¶ delete entities
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sally', age=25)) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Joe', age=25)) >>> joe = people.get(id) >>> id 3 >>> bool(joe) True >>> joe <Person {'name': 'Joe', 'age': 25}> >>> people.delete(id) [3] >>> joe = people.get(id) >>> joe >>> bool(joe) False
>>> bool(people.find(name='Sally')) True >>> people.delete(name='Sallie') >>> bool(people.find(name='Sally')) True >>> people.delete() >>> people.delete(name='Sally') [1] >>> bool(people.find(name='Sally')) False
>>> db.close()
-
exists(keys=None)¶ tests for existence of an entity
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sally', age=25)) >>> sally = people.get(id) >>> sally <Person {'name': 'Sally', 'age': 25}> >>> people.exists(1) True >>> people.exists(2) False >>> people.exists([1, 2]) [True, False] >>> id = people.put(Person(name='Sam', age=25)) >>> people.exists([1, 2]) [True, True] >>> db.close()
-
find(**kv)¶ finds entities that meet search criteria
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Sally', age=55)) >>> id = people.put(Person(name='Bob', age=25))
>>> print(people.find(age=25)) person _id name age --- ---- --- 1 Sam 25 3 Bob 25 2 person records
>>> len(people.find(name='Sam')) 1
>>> db.close()
-
first(**kv)¶ finds the first entity that meet search criteria
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Sally', age=55)) >>> id = people.put(Person(name='Bob', age=25)) >>> people.first(age=5) >>> people.first(age=55) <Person {'name': 'Sally', 'age': 55}> >>> people.first() <Person {'name': 'Sam', 'age': 25}> >>> db.close()
-
get(keys)¶ retrives entities
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> id = people.put(Person(**{'name': 'Sam', 'age':15, ... 'salary': decimal.Decimal('100.00')})) >>> sam = people.get(id) >>> sam <Person {'name': 'Sam', 'age': 15, 'salary': Decimal('100.00')}> >>> people.put(Person(name='Jim', age=21, ... salary=decimal.Decimal('50'))) 2 >>> people.put(Person(name='Alice', age=29)) 3 >>> print(people) person _id name age salary --- ----- --- ------ 1 Sam 15 100.00 2 Jim 21 50 3 Alice 29 None 3 person records
>>> print(people.get([1, '3'])) person _id name age salary --- ----- --- ------ 1 Sam 15 100.00 3 Alice 29 None 2 person records
>>> db.close()
-
get_attributes()¶ get complete set of attributes for the entity type
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> sam = Person(**{'name': 'Sam', 'age':15}) >>> sorted(sam.keys()) ['age', 'name'] >>> id = people.put(sam) >>> sorted(people.get_attributes()) ['age', 'name'] >>> db.close()
-
last(**kv)¶ finds the last entity that meet search criteria
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Sally', age=55)) >>> id = people.put(Person(name='Bob', age=25)) >>> people.last(age=5) >>> people.last(age=25) <Person {'name': 'Bob', 'age': 25}> >>> db.close()
-
put(entity)¶ stores an entity
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> sally = Person(name='Sally', age=25) >>> sally <Person {'name': 'Sally', 'age': 25}> >>> id = people.put(Person(name='Sally', age=25)) >>> id 1 >>> sally <Person {'name': 'Sally', 'age': 25}> >>> sally = people.get(id) >>> sally <Person {'name': 'Sally', 'age': 25}> >>> sally.age = 35 >>> people.put(sally) 1 >>> person = people.get(id) >>> person <Person {'name': 'Sally', 'age': 35}> >>> id = people.put({'name':'James', 'age':15}) >>> id 2 >>> people.get(id) <Person {'name': 'James', 'age': 15}> >>> classes = ['one', 'Not this one'] >>> grades = (('one', 'A'), ('Not this one', 'C+'), ) >>> id = people.put({'name':'James', 'classes':classes, 'grades': grades}) >>> assert classes == people.get(id).classes >>> assert len(people.get(id).grades) == 2 # json dump/load will bring back all tuples as lists >>> db.close()
-
search(text)¶ search for entities that match text
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Sally', age=55)) >>> id = people.put(Person(name='Bob', age=25))
>>> list(people.search('bob')) [<Person {'name': 'Bob', 'age': 25}>]
>>> for r in list(people.search(25)): print(r) Person name ................: 'Sam' age .................: 25 Person name ................: 'Bob' age .................: 25
>>> list(people.search('Bill')) [] >>> db.close()
-
zap()¶ deletes all entities of the given kind
>>> db = setup_test() >>> class Person(Entity): pass >>> class People(EntityStore): pass >>> people = People(db, Person) >>> id = people.put(Person(name='Sally', age=25)) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Joe', age=25)) >>> people.all() [<Person {'name': 'Sally', 'age': 25}>, <Person {'name': 'Sam', 'age': 25}>, <Person {'name': 'Joe', 'age': 25}>] >>> people.zap() >>> people.all() [] >>> db.close()
-
-
class
zoom.store.Store¶ Bases:
object-
after_delete(record)¶
-
after_insert(record)¶
-
after_update(record)¶
-
before_delete(record)¶
-
before_insert(record)¶
-
before_update(record)¶
-
-
zoom.store.entify(rs, storage)¶ converts query result into an EntityList
-
zoom.store.store_of(klass, db=None)¶ Returns a store of the given entity class
The klass parameter can be a subclass of zoom.Model or an entity kind. If a zoom.Model is provided the actual entity kind is derived from the class name. If the entity kind is provivded as a string then it’s taken as-is.
Uses the current site database if none is provided.
>>> site = zoom.sites.Site() >>> class Person(Entity): pass >>> people = store_of(Person, site.db) >>> id = people.put(Person(name='Sam', age=25)) >>> id = people.put(Person(name='Sally', age=55)) >>> id = people.put(Person(name='Bob', age=25)) >>> person = people.first(name='Sally') >>> person['age'] 55
zoom.templates module¶
templates.zoom
zoom.tools module¶
zoom.tools
-
zoom.tools.ensure_listy(obj)¶ ensure object is wrapped in a list if it can’t behave like one
>>> ensure_listy('not listy') ['not listy']
>>> ensure_listy(['already listy']) ['already listy']
>>> ensure_listy([]) []
-
zoom.tools.first_day_of_last_month(any_date)¶ Returns the first day of last month for any date
>>> first_day_of_last_month(datetime.date(2016, 1, 21)) datetime.date(2015, 12, 1)
-
zoom.tools.first_day_of_next_month(any_date)¶ returns the first day of next month for any date
>>> first_day_of_next_month(datetime.date(2016, 2, 1)) datetime.date(2016, 3, 1)
-
zoom.tools.first_day_of_the_month(any_date)¶ returns the first day of the month for any date
>>> first_day_of_the_month(datetime.date(2016, 12, 31)) datetime.date(2016, 12, 1)
-
zoom.tools.get_markdown_converter()¶ Return a configured markdown converter
>>> markdown("a [[wikilink]] test") '<p>a <a class="wikilink" href="wikilink.html">wikilink</a> test</p>'
>>> markdown("a [[wikilink.html]] test") '<p>a [[wikilink.html]] test</p>'
-
zoom.tools.get_template(template_name='default', theme='default')¶ Get site page template
-
zoom.tools.hide_helpers(content)¶ prevent helper requests from being filled
-
zoom.tools.home(view=None)¶ Redirect to application home.
-
zoom.tools.how_long(time1, time2)¶ Returns a string that describes the difference between two times.
>>> import time >>> now = now()
>>> how_long(now, now) 'a moment'
>>> how_long(now, now + one_minute / 3) '20 seconds'
>>> how_long(now, now + one_hour / 3) '20 minutes'
>>> how_long(now, now + one_day / 3) '8 hours'
>>> how_long(now, now + one_day) '1 day'
>>> how_long(now, now + 2 * one_day) '2 days'
>>> how_long(now, now + 15 * one_day) '2 weeks'
>>> how_long(now, now + 35 * one_day) 'over a month'
>>> how_long(now, now + 65 * one_day) 'over 2 months'
>>> how_long(now, now + 361 * one_day) 'almost a year'
>>> how_long(now, now + 20 * one_minute) '20 minutes'
>>> how_long(now, now + 2 * 365 * one_day) 'almost two years'
>>> how_long(now, now + 3.25 * 365 * one_day) 'over 3 years'
>>> how_long(now, now + 1.25 * 365 * one_day) 'over a year'
>>> how_long(today(), tomorrow(today())) '1 day'
>>> how_long(today(), now + one_week) '7 days'
>>> how_long(now, time.time()) 'a moment'
>>> failed = False >>> try: ... how_long(now, None) ... except TypeError: ... failed = True >>> failed True
-
zoom.tools.how_long_ago(anytime, since=None)¶ Returns a string that describes the difference between any time and now.
>>> now = now()
>>> how_long_ago(now - datetime.timedelta(1) * 2) '2 days ago'
>>> how_long_ago(now + 20 * one_minute) '19 minutes from now'
>>> how_long_ago(now - 20 * one_minute) '20 minutes ago'
>>> how_long_ago(now - 20 * one_minute, now - 10 * one_minute) '10 minutes ago'
-
zoom.tools.htmlquote(text)¶ Encodes text for raw use in HTML.
>>> htmlquote(u"<'&\">") '<'&">'
>>> htmlquote("<'&\">") '<'&">'
-
zoom.tools.is_listy(obj)¶ test to see if an object will iterate like a list
>>> is_listy([1,2,3]) True
>>> is_listy(set([3,4,5])) True
>>> is_listy((3,4,5)) True
>>> is_listy(dict(a=1, b=2)) False
>>> is_listy('123') False
-
zoom.tools.last_day_of_last_month(any_date)¶ Returns the first day of last month for any date
>>> last_day_of_last_month(datetime.date(2016, 1, 21)) datetime.date(2015, 12, 31)
-
zoom.tools.last_day_of_next_month(any_date)¶ returns the last day of next month for any date
>>> last_day_of_next_month(datetime.date(2016, 2, 1)) datetime.date(2016, 3, 31)
-
zoom.tools.last_day_of_the_month(any_date)¶ returns the last day of the month for any date
>>> last_day_of_the_month(datetime.date(2016, 2, 1)) datetime.date(2016, 2, 29)
>>> last_day_of_the_month(datetime.datetime(2016, 2, 1, 1, 1, 1)) datetime.date(2016, 2, 29)
-
zoom.tools.last_month(any_date)¶ Returns date range for last month for any date
>>> last_month(datetime.date(2016, 1, 21)) (datetime.date(2015, 12, 1), datetime.date(2015, 12, 31))
-
zoom.tools.load(pathname, encoding='utf-8')¶ Read a file and return the contents
-
zoom.tools.load_content(pathname, *args, **kwargs)¶ Load a content file and use it to format parameters
-
zoom.tools.load_template(name, default=None)¶ Load a template from the theme folder.
Templates usually have .html file extensions and this module will assume that’s what is desired unless otherwise specified.
-
zoom.tools.markdown(content)¶ Transform content with markdown
>>> markdown('this **is** bold') '<p>this <strong>is</strong> bold</p>'
-
zoom.tools.next_month(any_date)¶ Returns date range for next month for any date
>>> next_month(datetime.date(2016, 1, 21)) (datetime.date(2016, 2, 1), datetime.date(2016, 2, 29))
-
zoom.tools.now()¶ Return the current datetime
-
zoom.tools.redirect_to(*args, **kwargs)¶ Return a redirect response for a URL.
-
zoom.tools.restore_helpers(content)¶ Restores content helpers to their usual form
-
zoom.tools.this_month(any_date)¶ Returns date range for last month for any date
>>> this_month(datetime.date(2016, 1, 21)) (datetime.date(2016, 1, 1), datetime.date(2016, 1, 31))
-
zoom.tools.today()¶ Return the current date
>>> today() == datetime.date.today() True
-
zoom.tools.tomorrow(any_date=None)¶ Return date for tomorrow
>>> tomorrow(datetime.date(2017, 12, 3)) datetime.date(2017, 12, 4)
>>> tomorrow(datetime.date(2016, 12, 31)) datetime.date(2017, 1, 1)
-
zoom.tools.unisafe(val)¶ safely convert to unicode
>>> unisafe(None) ''
>>> unisafe(b'123') '123'
>>> unisafe( ... b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81' ... b'\xa1\xe3\x81\xaf\xe4\xb8\x96\xe7\x95\x8c' ... ) 'こんにちは世界'
>>> unisafe(1) '1'
-
zoom.tools.websafe(content)¶ Return htmlquoted version of content
>>> websafe(b'This could be <problematic>') 'This could be <problematic>'
-
zoom.tools.yesterday(any_date=None)¶ Return date for yesterday
>>> yesterday(datetime.date(2017, 12, 4)) datetime.date(2017, 12, 3)
>>> yesterday(datetime.date(2017, 1, 1)) datetime.date(2016, 12, 31)
-
zoom.tools.zoompath(*args)¶ Returns the location of a standard Zoom asset
zoom.users module¶
zoom.users
-
class
zoom.users.User(*args, **kwargs)¶ Bases:
zoom.utils.RecordZoom User
-
activate()¶ Activate the user
-
add_group(group)¶ Make user a member of the group
-
allows(user, action)¶
-
apps¶ Returns the names of the apps the user can access
-
authenticate(password)¶ authenticate user credentials
authorize a user to perform an action on thing
If user is not allowed to perform the action an exception is raised. Object thing must provide allows(user, action) method.
-
can(action, thing)¶ test to see if user can action a thing object.
Object thing must provide allows(user, action) method.
-
can_run(app)¶ test if user can run an app
-
deactivate()¶ Deactivate the user
-
default_app¶ returns the default app for the user
-
full_name¶ user full name
-
get_groups()¶ get groups this user belongs to
>>> from zoom.database import setup_test >>> users = Users(setup_test()) >>> user = users.first(username='guest') >>> user.get_groups()[-4:] ['a_passreset', 'a_signup', 'everyone', 'guests']
>>> user = users.first(username='admin') >>> user.get_groups()[:2] ['a_admin', 'a_apps']
-
get_memberships()¶
-
groups¶ Returns the groups the user belongs to
-
groups_ids¶ Returns the IDs for the groups the user belongs to
-
helpers()¶ provide user helpers
-
initialize(request)¶ Initialize user based on a request
-
is_active¶ get user active status
-
is_member(group)¶ determine if user is a member of a group
-
key¶
-
link¶ user as link
-
login(request, password, remember_me=False)¶ log user in
-
logout()¶ log user out
-
memberships¶
-
name¶ user full name
-
remove_groups()¶ Remove user membership in the group
-
set_password(password)¶ set the user password
-
status_text¶ Return status as human friendly text
-
update_last_seen()¶ Record the latest activity time for the user
avoid the record store put so as not to update the updated timestamp
-
updated_by_link¶ Human friendly user account
-
url¶ user view url
-
user_id¶ Return user record id
-
when_last_seen¶
-
when_updated¶ Human friendly updated timestamp
-
-
class
zoom.users.Users(db, entity=<class 'zoom.users.User'>)¶ Bases:
zoom.records.RecordStoreZoom Users
>>> import datetime >>> from zoom.database import setup_test >>> db = setup_test() >>> users = Users(db) >>> user = users.first(username='guest') >>> user.created = datetime.datetime(2017, 3, 30, 17, 23, 43) >>> user.updated = datetime.datetime(2017, 3, 30, 17, 23, 43) >>> user.now = datetime.datetime(2017, 4, 30, 17, 23, 43) >>> print(user) User user_id .............: 3 key .................: 'guest' name ................: 'Guest User' first_name ..........: 'Guest' last_name ...........: 'User' now .................: datetime.datetime(2017, 4, 30, 17, 23, 43) url .................: '/admin/users/guest' apps ................: ['content', 'forgot', 'login', 'passreset', 'signup'] link ................: 'guest' email ...............: 'guest@datazoomer.com' phone ...............: '' groups ..............: ['everyone', 'guests'] status ..............: 'A' created .............: datetime.datetime(2017, 3, 30, 17, 23, 43) request .............: None updated .............: datetime.datetime(2017, 3, 30, 17, 23, 43) is_admin ............: False password ............: '' username ............: 'guest' full_name ...........: 'Guest User' is_active ...........: True created_by ..........: 1 groups_ids ..........: [4, 3] updated_by ..........: 1 default_app .........: '/home' memberships .........: {3} status_text .........: 'active' is_developer ........: False when_updated ........: 'over a month ago' when_last_seen ......: 'never' updated_by_link .....: 'admin' is_authenticated ....: False
-
after_insert(user)¶ Things to do right after inserting a new user
-
before_delete(user)¶ Things to do right before deleting a user
-
before_insert(user)¶ Things to do just before inserting a new User record
-
before_update(user)¶ Things to do just before updating a User record
-
locate(key)¶
-
Decorator that authorizes (or not) the current user
Raises an exception if the current user does not have at least one of the listed roles.
-
zoom.users.get_current_username(request)¶ get current user username
-
zoom.users.get_groups(db, user)¶ get groups for a user
>>> from zoom.database import setup_test >>> db = setup_test() >>> users = Users(db) >>> guest = users.first(username='guest') >>> guest.username 'guest' >>> guest._id 3
>>> groups = get_groups(db, guest) >>> len(groups) 7 >>> 'everyone' in groups True >>> 'a_login' in groups True >>> 'managers' in groups False >>> 'administrators' in groups False
>>> admin = users.first(username='admin') >>> groups = get_groups(db, admin) >>> 'everyone' in groups True >>> 'a_login' in groups False >>> 'managers' in groups True >>> 'administrators' in groups True
-
zoom.users.handler(request, next_handler, *rest)¶ handle user
-
zoom.users.key_for(username)¶ Calculates a valid HTML tag id given an arbitrary string.
>>> key_for('Test 123') 'test-123' >>> key_for('New Record') 'new-record' >>> key_for('New "special" Record') 'new-special-record' >>> key_for("hi test") 'hi-test' >>> key_for("hi-test") 'hi-test' >>> key_for(1234) '1234' >>> key_for('this %$&#@^is##-$&*!it') 'this-is-it' >>> key_for('test-this') 'test-this' >>> key_for('test.this') 'test.this' >>> key_for('test\\this') 'test-this'
-
zoom.users.link_to_user(username)¶
-
zoom.users.set_current_user(request)¶ Set current user
Set the current user based on the current username.
zoom.utils module¶
zoom.utils
-
class
zoom.utils.Bunch(**kwargs)¶ Bases:
objecta handy bunch of variables
-
class
zoom.utils.Config(filename)¶ Bases:
objectConfig File Reader
A Config with a handy get method.
>>> config = Config(zoom.tools.zoompath('web','sites','default','site.ini')) >>> config.get('site', 'name') 'ZOOM'
>>> config.has_option('site', 'name') True
>>> config.get('site', 'size', 100) 100
>>> try: ... config.get('site', 'size') ... except (configparser.NoOptionError, configparser.NoSectionError): ... error = True >>> error True
-
get(section, option, default=None)¶ Get a config file value supplying an optional defalt value.
-
has_option(section, option)¶ Return True if config file option exists.
-
has_section(section)¶ Return True if config file section exists.
-
-
class
zoom.utils.DefaultRecord¶ Bases:
zoom.utils.RecordA Record with default values
>>> class Foo(DefaultRecord): pass >>> foo = Foo(name='Sam') >>> foo.name 'Sam' >>> foo.phone ''
-
class
zoom.utils.ItemList(*args, **kwargs)¶ Bases:
listlist of data items
>>> items = ItemList() >>> items.append(['Joe', 12, 125]) >>> items [['Joe', 12, 125]] >>> print(items) Column 0 Column 1 Column 2 -------- -------- -------- Joe 12 125
>>> items.insert(0, ['Name', 'Score', 'Points']) >>> print(items) Name Score Points ---- ----- ------ Joe 12 125
>>> data = [ ... ['Joe', 12, 125], ... ['Sally', 13, 1354], ... ] >>> items = ItemList(data) >>> print(items) Column 0 Column 1 Column 2 -------- -------- -------- Joe 12 125 Sally 13 1,354
>>> data = [ ... ['Joe', 12, 125], ... ['Sally', 13, 135], ... ] >>> items = ItemList(data, labels=['Name', 'Score', 'Points']) >>> print(items) Name Score Points ----- ----- ------ Joe 12 125 Sally 13 135
-
class
zoom.utils.OrderedSet(iterable=None)¶ Bases:
collections.abc.MutableSetA set that preserves the order of the elements
>>> s = OrderedSet('abracadaba') >>> t = OrderedSet('simsalabim') >>> print(s | t) OrderedSet(['a', 'b', 'r', 'c', 'd', 's', 'i', 'm', 'l']) >>> print(s & t) OrderedSet(['a', 'b']) >>> print(s - t) OrderedSet(['r', 'c', 'd']) >>> print(OrderedSet(reversed(s - t))) OrderedSet(['d', 'c', 'r']) >>> OrderedSet(['d', 'c', 'd']) == OrderedSet(['c', 'd', 'd']) False
credit: http://code.activestate.com/recipes/576694/ Licensed under MIT License
-
add(key)¶ add an item
>>> s = OrderedSet([1, 2, 3]) >>> s.add(4) >>> s OrderedSet([1, 2, 3, 4])
-
discard(key)¶ discard an item by key
>>> s = OrderedSet([1, 2, 3]) >>> s.discard(1) >>> s OrderedSet([2, 3])
-
pop(last=True)¶ pop an item
>>> s = OrderedSet([1, 2, 3]) >>> s.pop(2) 3 >>> s OrderedSet([1, 2])
-
-
class
zoom.utils.Record¶ Bases:
zoom.utils.StorageA dict with attribute access to items, attributes and properties
>>> class Foo(Record): ... full = property(lambda a: a.fname + ' ' + a.lname) ... >>> f = Foo(fname='Joe', lname='Smith') >>> f.full 'Joe Smith' >>> f['full'] 'Joe Smith' >>> 'The name is %(full)s' % f 'The name is Joe Smith' >>> print(f) Foo fname ...............: 'Joe' lname ...............: 'Smith' full ................: 'Joe Smith'
>>> f.attributes() ['fname', 'lname', 'full']
>>> class FooBar(Record): ... full = property(lambda a: a.fname + ' ' + a.lname) ... >>> o = FooBar(a=2) >>> kind(o) 'foo_bar' >>> o.a 2 >>> o['a'] 2 >>> o.double = property(lambda o: 2*o.a) >>> o.double 4 >>> o['double'] 4 >>> del o.a >>> print(o.a) None
>>> class Foo(Record): ... full = property(lambda a: a.fname + ' ' + a.lname) ... >>> f = Foo(fname='Joe', lname='Smith') >>> f.full 'Joe Smith' >>> f['full'] 'Joe Smith' >>> 'The name is %(full)s' % f 'The name is Joe Smith' >>> getattr(f,'full') 'Joe Smith'
>>> print(Foo(_id=1, fname='Jane', lname='Smith')) Foo fname ...............: 'Jane' lname ...............: 'Smith' full ................: 'Jane Smith'
>>> o = Record(a=2) >>> o.a 2 >>> o.valid() 1 >>> o.attributes() ['a'] >>> o['a'] 2 >>> o.double = property(lambda o: 2*o.a) >>> o.double 4 >>> o['double'] 4 >>> del o.a >>> o.a
-
allows(user, action)¶
-
attributes()¶
-
get(name, *default)¶ Return the value for key if key is in the dictionary, else default.
-
save()¶ save record
-
valid()¶
-
-
class
zoom.utils.RecordList(*a, **k)¶ Bases:
lista list of Records
-
class
zoom.utils.Storage¶ Bases:
dictA Storage object is like a dictionary except obj.foo can be used in addition to obj[‘foo’].
>>> o = Storage(a=1) >>> o.a 1 >>> o['a'] 1 >>> o.a = 2 >>> o['a'] 2 >>> del o.a >>> o.a
-
zoom.utils.dedup(seq)¶ Remove duplicates while retaining order
-
zoom.utils.dictify(item)¶ prepare an object for transmission by marshalling it’s members
Marshals only members that json can handle.
>>> class Thing(object): pass >>> pp(dictify(Bunch(name='Terry', age=21, funky_type=Thing()))) { "age": 21, "name": "Terry" }
-
zoom.utils.existing(path, subdir=None)¶ Returns existing directories only
-
zoom.utils.generate_key()¶ make a new key
>>> len(generate_key()) 40
-
zoom.utils.get_attributes(obj)¶
-
zoom.utils.get_config(filename)¶ load a config file into a Config object
>>> get_config('doesnt_exist.conf')
-
zoom.utils.id_for(*args)¶ Calculates a valid HTML tag id given an arbitrary string.
>>> id_for('Test 123') 'test-123' >>> id_for('New Record') 'new-record' >>> id_for('New "special" Record') 'new-special-record' >>> id_for("hi", "test") 'hi~test' >>> id_for("hi test") 'hi-test' >>> id_for("hi-test") 'hi-test' >>> id_for(1234) '1234' >>> id_for('this %$&#@^is##-$&*!it') 'this-is-it' >>> id_for('test-this') 'test-this'
-
zoom.utils.kind(o)¶ returns a suitable table name for an object based on the object class
-
zoom.utils.locate_config(filename='zoom.conf', start='.')¶ locate a config file
First look in the current directory or above and then look in the user root directory and above.
-
zoom.utils.matches(item, terms)¶ Returns True if an item matches search terms
-
zoom.utils.name_for(text)¶ Calculates a valid HTML field name given an arbitrary string.
>>> name_for('Test 123') 'test_123' >>> name_for('New Record') 'new_record' >>> name_for('New "special" Record') 'new_special_record' >>> name_for("hi test") 'hi_test' >>> name_for("hi-test") 'hi_test' >>> name_for(1234) '1234' >>> name_for('this %$&#@^is##-$&*!it') 'this_is_it' >>> name_for('test-this') 'test_this'
-
zoom.utils.parents(path)¶
-
zoom.utils.pp(obj)¶ pretty print an object
>>> obj = dict(name='Joe', age=25)
>>> pp(obj) { "age": 25, "name": "Joe" }
-
zoom.utils.pretty(obj)¶ return an object in a pretty form
>>> obj = dict(name='Joe', age=25) >>> pretty(obj) '{\n "age": 25,\n "name": "Joe"\n}'
-
zoom.utils.search(items, text)¶ Returns items that match search terms
>>> items = [ ... {'name': 'Terry', 'instrument': 'guitar, drums, picolo', 'age': 25}, ... {'name': 'Pat', 'instrument': 'drums, vocals', 'age': 29}, ... {'name': 'Francis', 'instrument': 'saxophone, piano', 'age': 35}, ... ]
>>> pp(list(search(items, 'drums'))) [ { "age": 25, "instrument": "guitar, drums, picolo", "name": "Terry" }, { "age": 29, "instrument": "drums, vocals", "name": "Pat" } ]
>>> pp(list(search(items, 'drums pat'))) [ { "age": 29, "instrument": "drums, vocals", "name": "Pat" } ]
>>> pp(list(search(items, ''))) [ { "age": 25, "instrument": "guitar, drums, picolo", "name": "Terry" }, { "age": 29, "instrument": "drums, vocals", "name": "Pat" }, { "age": 35, "instrument": "saxophone, piano", "name": "Francis" } ]
>>> pp(list(search(items, None))) [ { "age": 25, "instrument": "guitar, drums, picolo", "name": "Terry" }, { "age": 29, "instrument": "drums, vocals", "name": "Pat" }, { "age": 35, "instrument": "saxophone, piano", "name": "Francis" } ]
>>> sorted(list(search((list(item.values()) for item in items), '35'))[0], key=str) [35, 'Francis', 'saxophone, piano']
-
zoom.utils.sorted_column_names(names)¶
-
zoom.utils.trim(text)¶ Remove the left most spaces for markdown
>>> trim('remove right ') 'remove right'
>>> trim(' remove left') 'remove left'
>>> print(trim(' remove spaces\n from block\n of text')) remove spaces from block of text
>>> print( ... trim( ... ' \n' ... ' remove spaces\n' ... ' from block\n' ... ' of text\n' ... ' \n' ... '\n' ... ) ... ) remove spaces from block of text
>>> print(trim(' remove spaces\n from block\n of text\n ')) remove spaces from block of text
>>> print(trim(' remove spaces\n from block\n of text')) remove spaces from block of text
>>> print(trim('\n remove spaces\n from block\n of text')) remove spaces from block of text
>>> text = '\nremove spaces \n from block\nof text' >>> print('\n'.join(repr(t) for t in trim(text).splitlines())) 'remove spaces ' ' from block' 'of text'
>>> text = ( ... '\nremove spaces' ... '\n from block' ... ) >>> print(trim(text)) remove spaces from block
zoom.validators module¶
zoom.validators
-
class
zoom.validators.Cleaner(transformer)¶ Bases:
objectA content cleaner.
>>> Cleaner(str.lower).clean('Test') 'test'
>>> import decimal >>> Cleaner(decimal.Decimal).clean('10') Decimal('10')
-
clean(value)¶ cleans up a value
-
valid(value)¶ tests validity of a value
-
-
class
zoom.validators.DateValidator(date_format='%b %d, %Y')¶ Bases:
zoom.validators.ValidatorDate validator
>>> v = DateValidator() >>> v.valid('asdf') False >>> v.msg 'enter valid date in "Jan 31, 2016" format'
>>> v.valid('Jan 1, 2016') True
>>> v.valid('Jan 41, 2016') False
>>> v.valid('2016-01-14') True
>>> v.valid('2016-01-41') False
>>> v.valid(datetime.date(2016, 1, 14)) True
-
class
zoom.validators.MaximumValue(max_value, empty_allowed=True)¶ Bases:
zoom.validators.ValidatorMaximum value validator
>>> v = MaximumValue(100) >>> v.valid(50) True >>> v.valid(120) False
>>> from datetime import date >>> v = MaximumValue(date(2015,1,1)) >>> v.valid(date(2015,1,1)) True >>> v.valid(date(2015,1,2)) False >>> v.msg 'value must be at most 2015-01-01'
-
class
zoom.validators.MinimumLength(min_length, empty_allowed=False)¶ Bases:
zoom.validators.ValidatorA minimum length validator
>>> v = MinimumLength(2) >>> v.test('') False >>> v.test(' ') False >>> v.test(' ') False >>> v.test('t') False >>> v.msg 'minimum length 2' >>> v.test('te') True
>>> v = MinimumLength(2, True) >>> v.test('') True >>> v.test(' ') True >>> v.test(' ') True >>> v.test('t') False >>> v.test('te') True
-
class
zoom.validators.MinimumValue(min_value, empty_allowed=True)¶ Bases:
zoom.validators.ValidatorMinimum value validator
>>> v = MinimumValue(100) >>> v.valid(50) False >>> v.valid(120) True
-
class
zoom.validators.PostalCodeValidator¶ Bases:
zoom.validators.RegexValidatorA Postal Code Validator
>>> validator = PostalCodeValidator() >>> validator.valid('V8X 1G1') True
>>> validator = PostalCodeValidator() >>> validator.valid('V8X1G1') True
>>> validator = PostalCodeValidator() >>> validator.valid('V8X XG1') False
>>> validator = PostalCodeValidator() >>> validator.valid('8X XG1') False
>>> validator = PostalCodeValidator() >>> validator.valid('V8X 1g1') True
-
class
zoom.validators.RegexValidator(msg, regex, options=0)¶ Bases:
zoom.validators.ValidatorA regular expression validator
>>> validator = RegexValidator('invalid input', r'^[a-zA-Z0-9]+$') >>> validator.valid('1') True
>>> validator = RegexValidator('invalid input', r'^[a-zA-Z0-9]+$') >>> validator.valid('') True
>>> is_valid = RegexValidator('invalid input', r'^[a-zA-Z0-9]+$') >>> is_valid('') True >>> is_valid('*') False
>>> validator = RegexValidator('invalid input', r'^[a-zA-Z0-9]+$') >>> validator.valid('-') False >>> validator.msg 'invalid input'
-
valid(value)¶ tests validity of a value
-
-
class
zoom.validators.TimeValidator(time_format='%I:%M %p')¶ Bases:
zoom.validators.ValidatorTime validator
Validates a time in a variety of formats with time_format being the preferred format.
>>> import locale >>> locale.setlocale(locale.LC_ALL, 'C') 'C'
>>> v = TimeValidator() >>> v.valid('asdf') False >>> v.msg 'enter valid time in 12 hour "02:20 PM" format'
>>> v.valid('10:20') True
>>> v.valid('07:20') True
>>> v.valid('7:20') True
>>> v.valid('10:70') False
>>> v.valid('14:20') True
>>> v.valid('10:20 PM') True
>>> v.valid('14:70') False
>>> v.valid('10:20:10') True
>>> v.valid('10:20:70') False
>>> v.valid('10:70:20') False
>>> v.valid(datetime.time(10, 20)) True
>>> v.valid(datetime.time(10, 20, 30)) True
-
valid_formats= ['%I:%M %p', '%I:%M:%S %p', '%H:%M', '%H:%M:%S']¶
-
-
class
zoom.validators.URLValidator¶ Bases:
zoom.validators.RegexValidatorA URL Validator
>>> validator = URLValidator() >>> validator.valid('http://google.com') True
>>> validator = URLValidator() >>> validator.valid('test123') False
-
class
zoom.validators.Validator(msg, test)¶ Bases:
objectA content validator.
>>> is_true = Validator('not true', bool) >>> is_true.valid(1) True
>>> is_true.valid([]) False
>>> is_true.msg 'not true'
>>> is_true.clean({}) {}
-
clean(value)¶ cleans up a value
-
valid(value)¶ tests validity of a value
-
-
zoom.validators.email_valid(email)¶ test for valid email address
>>> email_valid('test@testco.com') True
>>> email_valid('test@@testco.com') False
>>> email_valid('test@testco') False
-
zoom.validators.empty(value)¶ test if a value is empty
>>> empty('') True
>>> empty(' ') True
>>> empty('\n') True
>>> empty('x') False
>>> empty(1) False
-
zoom.validators.image_mime_type_valid(data)¶ check data against the more commonly browser supported mime types
-
zoom.validators.is_present(value)¶ test if a value is present
>>> is_present('') False
>>> is_present('x') True
-
zoom.validators.latitude_valid(value)¶ test for valid latitude
>>> latitude_valid(45) True
>>> latitude_valid(100) False
>>> latitude_valid('x') False
-
zoom.validators.longitude_valid(value)¶ test for valid longitude
>>> longitude_valid(145) True
>>> longitude_valid(200) False
>>> longitude_valid('x') False
-
zoom.validators.number_valid(value)¶ Test for valid number
>>> number_valid(0) True >>> number_valid(-1) True >>> number_valid(1.12039123) True >>> number_valid('1.12039123') True >>> number_valid('x1.12039123') False >>> number_valid('t') False >>> number_valid('') True >>> number_valid(False) # not sure if this is what's we want True
Module contents¶
Zoom Web Framework