Package: pfstate
Table of ContentsOverviewpfstateInstallationPython Virtual EnvironmentUsageCommand line argumentsOverviewThis repository providespfstate– a library / module that maintains state in the object/class definition (and not in a class instance). The module uses the treeC_snodedata abstraction internally (see elsewhere forC_snode) as well as some internal methods to set/get this internal data in various ways.pfstateMost simply,pfstateis a module that keeps state in a class definition (as opposed to a class instance).States are created in the global space typically by deriving a class and calling the state_create() method of the base class. Note that a “derived” class is still only setting state in the same global space – and not in a separate derived-class space.THIS IS IMPORTANT:There is only ever ONE global state in the context of a single system. Thus, if various different modules usepfstateit is probably best practice toalwaysset the**kwargsthat are sent to the derived class with**dict(kwargs, useGlobalState = True)It was primarily created in the context of customThreadedHTTPServerclasses. Creating aThreadedHTTPServerin python involves instantiating theThreadedHTTPServer, and in the constructor providing a derivedBaseHTTPRequestHandlerobject. The design pattern has some structural shortcomings – most notably that the difficulty in setting internalBaseHTTPRequestHandlerdata from the level of theThreadedHTTPServer. One mechanism to overcome this is to share a common singlepfstateobject across the scope of both the server and the handler.Moreover, each call to theThreadedHTTPServerre-initializes the handler object derived fromBaseHTTPRequestHandler, so any state information in that object instance is lost across calls.By using thepfstatemodule, however, in the handler object, state information can be preserved across calls to theThreadedHTTPServerby keeping state in the object and not an instance of the object.In some ways, this can be thought of a cleaner way to avoid using a global variable.Consult the source code for full detail. However, as a simple overview, the recommended method of using this module is to define a subclass containing the state-specific information in a dictionary, and then to initialize the class.Note, it is vitally important that this derived class check the initialization of the base object data so as to not re-initialize an already stateful object and hence lose any additional state information.frompfstateimportSfromargparseimportRawTextHelpFormatterfromargparseimportArgumentParserstr_desc="some program description"str_version="1.0.0"str_name="Example module"parser=ArgumentParser(description=str_desc,formatter_class=RawTextHelpFormatter)parser.add_argument('--msg',action='store',dest='msg',default='',help='Message payload for internalctl control.')# Create a test classclassD(S):"""
    A derived class with problem-specific state

    See https://github.com/FNNDSC/pfstate for more information.

    """def__init__(self,*args,**kwargs):"""
        Constructor
        """self.state_create({'additionalState':{'desc':'Additional state information','theAnswer':42,'theQuestion':'What do you get if you multiple six by nine','foundBy':'Arthur Dent','note':{'additional':'was this really Arthur Dent, though?','action':{'item1':'further research might be needed'}}},'earthState':{'current':'Destroyed','reason':'Facilitate Hyperspace bypass','survivors':{'humans':['Arthur Dent','Ford Prefect','Trillian'],'dolphins':'Most of them','note':{'exception':'Ford Prefect is not a human'}}}},*args,**kwargs)state=D(version=str_version,name=str_name,desc=str_desc,args=vars(args))# Now create a different derived class --# This will still add to the global stateclassE(S):"""
    A new derived class with different state -- this is still
    added to the same global space
    """def__init__(self,arg,*args,**kwargs):"""
        Constructor
        """if'randomFact'notinarg.keys():arg['randomFact']="Vogon poetry is the third worst poetry in the universe."self.state_create({'Vogons':{'desc':'Slug-like but vaguely humanoid','preferredJob':'Galactic bureaucrats','randomFact':arg['randomFact'],'note':{'additional':'Vogons are the worst marksmen in the galaxy.','source':{'name':'Marvin the Paranoid Android'}}}},*args,**kwargs)classdemo:"""Just an example class that as part of its initialization adds to state
    """def__init__(self,arg,*args,**kwargs):"""example class constructor

        Args:
            arg ([type]): some unspecified type arg input
        """self.newState=E(arg,*args,**dict(kwargs,useGlobalState=True))print(self.newState('/this/desc'))example=demo({'randomFact':"Vogon poetry is the third worst poetry in the universe"},name="example")iflen(args.test):ifargs.test=='tree':print(state.T)else:print(json.dumps(state.as_dict(node=args.test)))iflen(args.msg):d_control=state.internalctl_process(request=json.loads(args.msg))print(json.dumps(d_control,indent=4))InstallationInstallation is relatively straightforward, and we recommend using python`pipto simply install the module, preferably in a python virtual environment.Python Virtual EnvironmentOn Ubuntu, install the Python virtual environment creatorpython3 -m venv <virtualEnvPath>Install the modulepipinstallpfstateUsageFor usage ofpstate, consult the relevant wiki pages  <https://github.com/FNNDSC/pfstate/wiki/pfstate-overview>`.Command line arguments[--state<directive>]
If specified, return some state detail. Usually this is some
path into an internal state tree node. If the<directive>is
the actual text 'tree', then return the entre state object
representation

[--msg '<JSON_formatted>']
An optional JSON formatted string exemplifying how to get and
set internal variables.

--msg '
{
    "action": "internalctl",
    "meta": {
                "var":     "/",
                "get":      "value"
            }
}'

--msg '
{   "action": "internalctl",
    "meta": {
                "var":     "/service/megalodon",
                "set":     {
                    "compute": {
                        "addr": "10.20.1.71:5010",
                        "baseURLpath": "api/v1/cmd/",
                        "status": "undefined"
                    },
                    "data": {
                        "addr": "10.20.1.71:5055",
                        "baseURLpath": "api/v1/cmd/",
                        "status": "undefined"
                    }
                }
            }
}'

[--configFileLoad<file>]
Load configuration information from the JSON formatted<file>.

[--configFileSave<file>]
Save configuration information to the JSON formatted<file>.

[-x|--desc]
Provide an overview help page.

[-y|--synopsis]
Provide a synopsis help summary.

[--version]
Print internal version number and exit.

[--debugToDir<dir>]
A directory to contain various debugging output -- these are typically
JSON object strings capturing internal state. If empty string (default)
then no debugging outputs are captured/generated. If specified, then
``pfcon`` will check for dir existence and attempt to create if
needed.

[-v|--verbosity<level>]
Set the verbosity level. "0" typically means no/minimal output. Allows
for more fine tuned output control as opposed to '--quiet' that effectively silences everything.EXAMPLES$>pfstate--state'/earthState'# return a dictionary representation of# this node in the internal test data$>pfstate--state'tree'# return the raw internal test data$>pfstate\--msg'
        {  "action": "internalctl",
        "meta": {
                    "var":     "/service/megalodon",
                    "set":     {
                        "compute": {
                            "addr": "10.20.1.71:5010",
                            "baseURLpath": "api/v1/cmd/",
                            "status": "undefined"
                        },
                        "data": {
                            "addr": "10.20.1.71:5055",
                            "baseURLpath": "api/v1/cmd/",
                            "status": "undefined"
                        }
                    }
                }
        }'