This file is mainly examples that I hope will help people better-understand how to use the core library.
The core library's basic principles are division of labor and inheritance of functionality and properties across objects.
To facilitate this, core-based objects (in particular, objects used as "services") should be organized into a single tree with one root object. The core_basic class provides linkage between objects in this tree by way of the core(), root(), and owner() methods.
import core c = core.Core() # the core r = core.core_basic({'core':c}) # root object o = core.core_basic({'owner':r}) # an object # NOTE: o's owner is the root object r o.owner # NOTE: o "inherits" r's core property c r.core o.core # NOTE: o2 searches upward for the root object o2 = core.core_basic({'owner':o}) o2.root
Because the core_basic class is so limited, the next example will use core.Object to demonstrate configuration principles despite that the config() method is defined in core_basic.
Nearly all core-based configuration is the same, though some classes do extend config() if their nature implies alternate configuration schemes.
# Configuration is basically by dict object. o = core.Object({'foo':'bar'}) o.config() # kwargs always override any conf argument keys o = core.Object({'foo':'bar'}, foo='Car') o.config() # Config accepts json or dict representation files. core.util.fwrite('temp.conf',{'foo':'foofoo!'}) o = core.Object('temp.conf') o.config() # kwargs ALWAYS override the conf argument o = core.Object('temp.conf', foo='BABAR!') o.config()
One of the main objectives of the core package is to share time between clients, servers, and other types of object that require periodic passes through a "main loop" kind of function without the need for threading. ORISC objects facilitate this by acting as receivers for calls to such a main loop function.
Override ORISC's io() method to handle any action that needs to be handled periodically.
The run() method loops calling io(). It does not stop until told to. Use Ctrl-C to stop the loop if necessary.
Here are a couple of examples demonstrating the practical (or, in this case impractical) use of an ORISC object.
# import the core package, which defines ORISC import core # create a class called Loopy, based on ORISC class Loopy (core.ORISC): # The io() method will be called repeatedly # when Loopy is running. def io(self): try: if self.loops > 0: print "I'm Loopy!" self.loops = self.loops-1 else: print "I'm out of loops :-/" self.shutdown() except: self.loops = 5 # Create a Loopy and run it. o = Loopy() o.run()
Alternately, you can use the start() method to run Loopy in a new thread. The stop() method stops the run() loop by setting the "active" property to false, then exits the thread.
Be aware that sometimes when working with threads interpreter output can look a bit strange. Also, there may be times when a short "sleep" is required between operations; it's not necessary if you're executing the code line by line, but I've added a call to time.sleep() in at least one place below to prevent errors for those who copy/paste the whole example at once.
# Create a new Loopy since the old one's loops are # already exhausted. o = Loopy() # Start the Loopy o.start() # # You have to wait a bit here so that the # Loopy thread gets a chance to exit! # import time time.sleep(0.1) # now try adding some more loops o.loops = 3 # Remember, running out of loops causes Loopy to # shut down (which stops the object and exists the # thread) so we'll have to start() again. o.start()
When debugging (or when learning the system by example) it can be really useful to call the io() method directly.
# Create a new Loopy since the old one's loops are # already exhausted. o = Loopy() # Give Loopy some loops. o.loops = 11 # Let Loopy do its thing one time... o.io() # ...and again... o.io() # ...Go for it, Loopy! o.run()
The main purpose of the core package's structure is to allow projects to reload while running without losing connections (such as, socket connections). One core.Core object can be created to hold a full tree structure containing all other objects that need to survive a runtime reload.
The Core class constructor will typically receive the file path to a config file, but it can also accept a direct type.
Here's an example of how to run Loopy from within a core object.
# # If you've haven't already done so, import core and # paste the Loopy class code first # # Once core is imported and Loopy defined in the # interpreter, create and start the Core object. c = core.Core(root=Loopy) c.start()
Here are a few more interesting things to note about Core:
import core # # 1: # Any object that implements the ORISC class methods # can be a root object (though usually a root object # will be based on core.service.Service so that it # can hold additional "child" service items). # c = core.Core(root=core.ORISC) c.start() c.root # ORISC PROPERTIES c.running c.threaded c.active # shutdown calls both close and stop c.shutdown() c.running c.threaded c.active # # 2: # There can be only one Core object # c2 = core.Core(root=core.ORISC) # # 3: # Be sure to call shutdown on the old core before # you Nullify it, or the thread will hold the active # Core object open and you won't be able to shut it # down without exiting the interpreter. # c.shutdown() c = None c3 = core.Core(root=core.ORISC) c3.running c3.threaded c3.active # # 3-B: # Though it can be configured differently, the root # object by default is neither running nor threaded. # It simply receives calls to io() from its core. # c3.start() c3.running c3.root.running c3.threaded c3.root.threaded # However, the root object will be active since core, # when it's opened, calls root's open() method. c3.active c3.root.active # # 3-C: # When the Core object is closed, the root object is # released from memory. Note that calling stop() does # not release the root; root is simply denied calls # to its io() method, rendering it active but inert. # c3.stop() c3.root # After closing the Core, its root is released. c3.close() c3.root