See fluid – Fluid Bindings for an example of a fluid database connection.
Writing to standard output and reading from standard input are good use-cases for fluid bindings. This example implements context managers similar to with-input-from-file / with-output-to-file (defined in R5RS) and with-input-from-string / with-output-to-string (defined in Gambit-C). These allow methods using the dynamically parameterized read() and display() operations to have their input and output redirected by the caller. If __future__.print_function is being used, a better implementation would be to override it instead of defining a display() function.
>>> import os, time, threading
>>> from docs.examples.fluidprint import *
>>> def hello():
... display("Hello, world!")
>>> def capture(thunk):
... with output_to_string():
... thunk()
... return current_output_port().getvalue()
>>> def show():
... port = current_input_port()
... display("showing %s:" % port, read().strip())
>>> hello()
Hello, world!
>>> TEMP = "/tmp/fluid-bindings-example.txt"
>>> with output_to_file(TEMP):
... hello()
>>> capture(hello)
'Hello, world!\n'
>>> with input_from_file(TEMP):
... t1 = threading.Thread(target=lambda: time.sleep(0.01) or show())
... t1.start()
... with input_from_string("main thread has different input"):
... show()
... t1.join()
showing <StringIO.StringIO instance ...>: main thread has different input
showing <open file '/tmp/fluid-bindings-example.txt', ...>: Hello, world!
>>> os.unlink(TEMP)
And the implementation:
from __future__ import print_function
import __builtin__, sys, contextlib, StringIO
from md import fluid
__all__ = (
'display', 'read', 'current_input_port', 'current_output_port',
'output_to_string', 'input_from_string',
'output_to_file', 'input_from_file'
)
## Default to None. This let's the cells play more nicely with code
## that changes sys.stdout/sys.stderr directly (like doctest).
## Binding directly to sys.stdout / sys.stderr is more ideal.
CURRENT_OUTPUT_PORT = fluid.cell(None, type=fluid.acquired)
CURRENT_INPUT_PORT = fluid.cell(None, type=fluid.acquired)
def current_output_port():
return CURRENT_OUTPUT_PORT.value or sys.stdout
def current_input_port():
return CURRENT_INPUT_PORT.value or sys.stdin
def display(*args, **kwargs):
kwargs.setdefault('file', current_output_port())
return __builtin__.print(*args, **kwargs)
def read(*args):
return current_input_port().read(*args)
@contextlib.contextmanager
def output_to_string(*args):
with contextlib.closing(StringIO.StringIO(*args)) as port:
with CURRENT_OUTPUT_PORT.let(port):
yield
@contextlib.contextmanager
def input_from_string(*args):
with contextlib.closing(StringIO.StringIO(*args)) as port:
with CURRENT_INPUT_PORT.let(port):
yield
@contextlib.contextmanager
def output_to_file(filename, mode='w'):
with contextlib.closing(open(filename, mode)) as port:
with CURRENT_OUTPUT_PORT.let(port):
yield
@contextlib.contextmanager
def input_from_file(filename, mode='r'):
with contextlib.closing(open(filename, mode)) as port:
with CURRENT_INPUT_PORT.let(port):
yield
Django views are called with the current request as their first parameter. Sometimes it’s inconvenient to pass this around to every place in your code that needs it. Sometimes it’s even impossible because you’re writing a signal handler or hook for some third-party django plugin that hasn’t anticipated your need to have access to the current request.
Using a fluid cell to track the current request is a simple task using this example middleware:
from md import fluid
CURRENT_REQUEST = fluid.cell(None, type=fluid.private)
current_request = fluid.accessor(CURRENT_REQUEST, 'request')
class RequestMiddleware(object):
def process_request(self, request):
CURRENT_REQUEST.value = request
Here is an example site (run it using django-admin.py runserver --settings='docs.examples.django_request'):
### Settings
ROOT_URLCONF = __name__
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'docs.examples.request_middleware.RequestMiddleware'
)
### Views
from django.http import HttpResponse
def example(request):
return HttpResponse(logic())
### Urls
from django.conf.urls.defaults import patterns
urlpatterns = patterns(
'',
(r'^example', example)
)
### Business Logic
from docs.examples.request_middleware import current_request
def logic():
request = current_request()
return '%s %s' % (request.method, request.get_full_path())
The md.stm module uses fluid bindings to track which journal is currently in scope for a transaction().
from __future__ import absolute_import
import threading
from contextlib import contextmanager
from md import fluid
from .interfaces import *
from .journal import *
__all__ = (
'initialize',
'allocate', 'readable', 'writable', 'delete',
'use', 'transaction', 'transactionally',
'save', 'rollback', 'commit', 'abort',
'saved', 'unsaved'
)
### Transasctional Data Type Operations
def allocate(cursor, state):
return alloc(current_journal(), cursor, state)
def readable(cursor):
return read_unsaved(current_journal(), cursor)
def writable(cursor):
return write(current_journal(), cursor)
def delete(cursor):
return dealloc(current_journal(), cursor)
### Transactions
def use(mem=None):
assert isinstance(mem, Memory)
return current_journal(mem or memory())
@contextmanager
def transaction(name='*nested*', autocommit=True, autosave=True):
try:
with current_journal(journal(name, current_journal())):
yield
if autosave: save()
if autocommit: commit()
except Abort:
pass
def transactionally(proc, *args, **kwargs):
limit = kwargs.pop('__attempts__', 3)
autocommit = kwargs.pop('autocommit', True)
autosave = kwargs.pop('autosave', True)
for attempt in xrange(limit):
try:
with transaction(autocommit=autocommit, autosave=autosave):
return proc(*args, **kwargs)
except CannotCommit as exc:
pass
raise exc
def save(what=None):
change_state(save_state, current_journal(), what or unsaved())
return what
def commit(journal=None):
journal = journal or current_journal()
return commit_changes(journal.source, journal)
def rollback(what=None):
change_state(revert_state, current_journal(), what or unsaved())
return what
def abort():
raise Abort
def saved():
return (c.cursor for c in current_journal().changed())
def unsaved():
return current_journal().unsaved()
### Journal
class acquire_memory(fluid.acquired):
def localize(self, loc):
if isinstance(loc.value, Journal):
return self.make_location(find_memory(loc.value))
else:
return super(acquire_memory, self).localize(loc)
def find_memory(journal):
while journal.source:
journal = journal.source
return journal
JOURNAL = fluid.cell(type=acquire_memory)
current_journal = fluid.accessor(JOURNAL, name='current_journal')
def current_memory():
return find_memory(current_journal())
def initialize(mem=None):
journal = JOURNAL.value
if isinstance(journal, Journal) and not isinstance(journal, Memory):
raise RuntimeError('Cannot uninitialize a transaction', journal)
JOURNAL.value = mem or memory()