Transcription

AtacamaLargeMillimeterArrayALMA SW NNNNRevision: 4.12005 06 20ALMA Common Softwareand PythonDesign and TutorialDavid FugateUniversity of CalgaryKeywords: ACS, acspy, Python, CORBA, IDL, Client, ServantAuthor Signature: David FugateDate: 2003 11 19Approved by:Signature:Institute:Date:Released by:Signature:Institute:Date:

ALMAACS & PythonChange RecordREVISIONDATEAUTHORSECTIONS/PAGES AFFECTEDREMARKS3.02003 11 19D. FugateAllD. FugateAllCreated3.12004 05 10Updated for ACS 3.14.1.02005 06 20D. FugateAllUpdated for ACS 4.1Revision: 4.1Page 2 o23

ALMAACS & PythonTable of Contents1 Overview.41.1 Abbrevations.51.2 References.62 Design.72.1 Requirements.72.2 Package Structure.7Common.7Util.8Clients.8Servants.8Nc package.83 IDL to Python Mapping.93.1 Guidelines.93.2 Simple Types.103.3 Complex Types.103.4 in, out, and inout Parameters.113.5 Narrowing CORBA Objects to their Real Type.124 Utility and Helper Packages.124.1 ACS Configuration Database.124.2 ACS Error System.124.3 ACS Logging System.124.4 ACS Time System.135 Client Tutorial.13Some PySimpleClient Methods/Attributes Available to Developers.13An Example.146 Servant Tutorial.16Revision: 4.1Page 3 o23

ALMAACS & PythonDeveloping an IDL Interface.16The Servants Package.18A Python Implementation for the IDL Interface.18Editing the Configuration Database.21Makefile Support.227 Known Problems and Issues.238 Appendix.23ALMA CVS Repository.231OverviewThis document describes in detail the ALMA Common Software Python API and how touse it. For those unfamiliar with Python, it is a high level, object oriented, interpretedprogramming language that is both dynamically typed and scoped. C and C extensions to Python are very easy to create and it runs incredibly fast for an interpretedlanguage. Python is great for scripting, prototyping, web development, and high levelapplications. It’s also a wonderful language for non programmers to use because of itssimplicity. Most importantly for ALMA, OMG has defined an IDL to Python CORBAmapping and several vendors offer free ORBs. This implies that anything done in C or Java can also be coded in Python! ALMA uses the omniORBPy ORB because of itsstability and performance.Specifically, this document intends to help the reader in four core areas: the IDL toPython mapping, ACS Python utility and helper packages, Python CORBA clients, andPython CORBA servants.Short when compared to other IDL language mappings, it’s still vital to learn thecomplete IDL to Python mapping. The easiest way to do this is using OMG’sspecification document ([R05]), although studying the entire specification is overkill.Revision: 4.1Page 4 o23

ALMAACS & PythonPython helper packages have been contributed by a diverse group including ALMAControl, APEX, and ACS developers. In short, they generally provide the same (if notmore) functionality as the C /Java APIs and are developed in a much shorter time span.These subpackages can be found in the Acspy package located in the src directory of theacspy module (module in the sense of an ALMA Software Engineering module). Theyrange from functions designed to find files located in the ALMA directory structure toclasses capable of reading/parsing XML files from the ACS Configuration Database.Client and servant development run hand in hand so to speak. This document providesstep by step tutorials on developing ACS Python clients and servants by using helperclasses. These helper classes are extremely similar to what’s been developed for C and Java because the helpers are built on common IDL interfaces.Developers without Python programming experience are highly encouraged to readthe first ten chapters of Python Essential Reference ([R03]). This may sound like alarge undertaking, but should take most individuals under a couple of hours to read.Finally, every effort is made to ensure this document is kept up to date for each ACSrelease. However, sometimes things are overlooked and one should always trust thepydoc for the Acspy package over material presented here as it is guaranteed to be morerecent ([R09]).1.1AbbrevationsACSALMA Common SoftwareacspyALMA Common Software Python moduleacspyexmplALMA Common Software Python example moduleALMAAtacama Large Millimeter ArrayAPEXAtacama Pathfinder ExperimentBACIBasic Access and Control InterfacesRevision: 4.1Page 5 o23

ALMAACS & PythonCORBAIDLCommon Object Request Broker ArchitectureInterface Definition LanguageMACIManagement and Control InterfaceOMGObject Management GroupORBObject Request Broker1.2References[R01]ACS Architecture nlineDocs/ACSArchitectureNL.pdf)[R02]ACS CVS Software Modules: “acspy” and on Essential Reference documents/formal/corba iiop.htm)[R05]OMG IDL Python rmal/python.htm)[R06]ALMA Python Coding /alma n Channel (Design & Tutorial)(http://www.eso.org/ gchiozzi/AlmaAcs/OnlineDocs/Notification Channel Module Software Design.pdf)[R08]BACI Specifications Document(http://www.eso.org/ gchiozzi/AlmaAcs/OnlineDocs/ACS Basic Control Interface Specification.pdf)[R09]Acspy /OnlineDocs/ACS docs/py/index.html)[R10]ACS Error System Document neDocs/ACS Error System.pdf)Revision: 4.1Page 6 o23

ALMAACS & Python[R11]ACS Time System Document neDocs/ACSTime.pdf)2Design2.1Requirements2.2 The Acspy package shall abide by the standards set fourth in the ALMA PythonCoding Standards ([R06]). Features implemented in C and Java shall be reimplemented in Python wherefeasible and applicable. XML support shall be provided in some form.Package StructureAll ALMA Common Software Python packages reside in one core package – Acspy.CommonThe Common subpackage provides Python modules which are of use to all developers.This consists of:Revision: 4.1 Callbacks.py – Callback helper classes useful for clients accessingACS::CharacteristicComponent’s CDBAccess.py – provides read only access into the ACS ConfigurationDatabase.Page 7 o23

ALMAACS & Python Err.py – provides the superclass for ACS Error System generated exceptionsand completions. Log.py – ACS Logging System helper class. TimeHelper.py – ACS Time System helper class. EpochHelper.py – provides a wrapper for the acstime::Epoch IDL struct. DurationHelper.py – provides a wrapper for the acstime::Duration IDL struct. QoS.py – sets ORB timeouts for COBRA method callsUtilThe Util subpackage provides Python modules which are generally of use only to ACSdevelopers. Classes and functions found here provide low level access to CORBA andthe host’s filesystem. The entire package can be safely ignored by most developers.ClientsClients consists of a Python module, SimpleClient.py, used by developers to manipulateremote components and access manager services. Also, see ContainerServices.pyServantsThe Servants subpackage provides Python modules containing helper classes for codingPython CORBA servants: ACSComponent.py – an implementation of the ACS::ACSComponent IDLinterface. ComponentLifecycle.py – a concrete implementation of the Lifecycle interfacedefined by the High level Architecture team. ContainerServices.py – common services provided by the container for Pythonservants and clients. CharacteristicComponent.py – a prototype implementation of theACS::CharacteristicComponent IDL interface. Use at your own risk.Nc packageNc subpackage contains Python modules to manipulate notification channels. A fulldescription of all the classes it contains can be found in the Notification Channel Designand Tutorial ([R07]).Revision: 4.1Page 8 o23

ALMAACS & Python3IDL to Python Mapping3.1Guidelines Always define IDL types within a module. Otherwise the global IDL types willbe mapped to a package that is ORB vendor specific. Try to stay away from giving your IDL files the same name as standard Pythonpackages. There’s a slim chance this can cause problems. Do not name IDL modules names that are also standard Python packages orALMA Python packages. For example, defining “module Acspy” in some IDLfile would wreak major havoc. It is recommended that definitions of constants, structures, enumerations, etc. beplaced in the IDL module and not within the definition of an IDL interface. Thissuggestion can make your life much easier. If an enumeration has been declared within an IDL module, treat the values forthat enumeration as if they were reserved words throughout the rest of themodule. Failure to do so can result in all sorts of fun problems. The following are reserved keywords in Python and shall not be used in orpassprintraisereturntrywhilenoneRevision: 4.1Page 9 o23

ALMA3.23.3ACS & PythonSimple TypesOMG IDLPythonoctetInteger ( type 'int' )shortIntegerLongIntegerunsigned shortIntegerunsigned longLong integer( type 'long int' )Long longLong integerunsigned long longLong integerfloatFloating Point Number ( type 'float' )DoubleFloating Point NumberLong doubleCORBA.long doublebooleanInteger (0 or 1)Charstring of length 1wcharWide string of length 1Complex TypesOMG IDLPython((Un)bounded) stringString(Sequences/arrays)Lists or tuplesenumAn enumeration is mapped into a number of constant objects in theRevision: 4.1Page 10 o23

ALMAACS & Pythonnamespace where the enumeration is defined. Please do not use thenative Python copy methods on CORBA enumerations.3.4StructAn IDL struct definition is mapped into a Python class or type. Foreach field in the struct, there is a corresponding attribute in the classwith the same name as the field. The constructor of the class expectsthe field values, from left to right.(Constants)An IDL constant definition maps to a Python variable initialized withthe value of the constant.(Exceptions)An IDL exception is translated into a Python class derived fromCORBA.UserException. System exceptions are derived fromCORBA.SystemException. Both base classes are derived fromCORBA.Exception. The parameters of the exception are mapped in thesame way as the fields of a struct definition. When raising anexception, a new instance of the class is created and the constructorexpects the exception parameters.in, out, and inout Parametersin parameters are mapped as one would expect in Python. That is if some interface Icontains a method, void methodA(in string parameterX), a client would invoke it like this– I. methodA(“not interesting”). However, things get much more interesting with theother two cases.Let’s see another method of the I interface which incorporates in, out, and inoutparameters in addition to a return value:double methodB(in string parameterX, inout boolean isOK, out long someValue);A client would invoke methodB like this:(methodBReturnValue, boolOutValue, longValue) I.methodB(“ ”, 0);Now for the explanation – since every type in Python is an object which is really just apointer, the concept of references to objects does not really exist. In short, parameterspassed to Python functions and methods are complete copies of the objects (i.e., pass byvalue). To deal with this, the CORBA mapping for Python specifies that out parameterswill be returned via a tuple. The first object in this tuple is the return value if the methodhas one, followed by inout/out parameters in the order they were specified from left toright. To make this clearer, the implementation of methodB in a Python servant could bethe following:def methodB(self, parameterX, isOK):# 3.14 corresponds to the return double value# 1 is for ‘inout Boolean isOK’# 34 is ‘out long someValue’return (3.14, 1, 34)Revision: 4.1Page 11 o23

ALMA3.5ACS & PythonNarrowing CORBA Objects to their Real TypeBecause ALMA has chosen to use omniORBPy as our Python ORB, 99 out of 100 times this isnot necessary and the ORB does it automatically. The only time this needs to be done is when anIDL interface uses complex inheritance and the object needs to be narrowed to a base interface.If this is ever the case, all CORBA objects have a “ narrow(I)” method where I is the PythonCORBA stub class for the interface you want to narrow the object to.4Utility and Helper PackagesPrecise examples in this section have yet to be determined. In the meantime, you canlook at the test scripts located in the ALMA CVS repository which should be pretty self explanatory.4.1ACS Configuration DatabaseSee ACS/LGPL/CommonSoftware/acspy/test/acspyTestCDB.py in the ALMA CVSrepository.4.2ACS Error SystemSee the ACS Error System document ([R10]).4.3ACS Logging SystemSee g.py in the ALMACVS repository.Revision: 4.1Page 12 o23

ALMA4.4ACS & PythonACS Time SystemSee the ACS Time System document ([R11]).5Client TutorialAll ACS Python clients must use the Acspy.Clients.SimpleClient module. This moduledefines a single class, PySimpleClient, which implements the Client IDL interface and isresponsible for logging into manager and providing ACS services to the developer.Some PySimpleClient Methods/Attributes Available to DevelopersMethodavailableComponents()Revision: 4.1DescriptionGets a list of ComponentInfo structures (see maci.idl for a definition)about all known components.Page 13 o23

ALMAACS & PythonParameters: NoneReturns: a list consisting of ComponentInfostructures for every component manager knowsof or None if this method fails.Raises: ?getComponent(name)Get a component reference from manager.It’s important to note this method narrows the reference for thedeveloper and even imports the proper IDL Python stub.Parameters: name is the component’s nameReturns: a narrowed reference to the component or None ifthat reference cannot be obtained.Raises: ?releaseComponent(name)Release the component defined by name.Parameters: name is the component’s nameReturns: the number of clients/components attached to thecomponent or None on failure.Raises: ?token.hSecurity token for this client. If PySimpleClient does not provide accessto some manager method that is needed, you can always use thegetManager function of the ACSCorba module directly.An ExampleThe example depicted here consists of a client which logs into manager, accesses anACS::CharacteristicComponent, and then creates a monitor for one of that component’sBACI properties. Please note error handling has been omitted.1:#!/usr/bin/env python2:3:from Acspy.Clients.SimpleClient import PySimpleClientRevision: 4.1Page 14 o23

ALMA4:5:6:7:8:9:10:11:12:13:14:ACS & Pythonimport ACS, ACS POA# class MyMonitor(ACS POA.CBdouble):def working(self, value, completion, desc):print "Working the value is: ", str(value)def done(self, value, completion, desc):print "Done. The value is: ", str(value)def negotiate (self, time to transmit, desc):return 1# simpleClient PySimpleClient()15:16:17:mount simpleClient.getComponent("MOUNT1")actAzProperty mount. get actAz()18:19:20:21:22:cbMon MyMonitor()cbMonServant simpleClient.activateOffShoot(cbMon)desc ACS.CBDescIn(0L, 0L, 0L) # Create the real monitor registered with MOUNT1actMon actAzProperty.create monitor(cbMonServant, desc)23:24:25:26:27:actMon.set timer trigger(10000000)from time import t()3PySimpleClient is the standard Python client capable of logging into manager.4Import the Python CORBA stubs for the BACI module. These are only necessary becausecallbacks are being used.6 15Since an asynchronous monitor will be created for a BACI double property, an implementationof the double callback IDL interface must be defined. The Acspy.Common.Callbacks modulecould have been used, but where’s the fun in that?6Our class must be derived from ACS POA.CBdouble which is generated by the IDL toPython compiler. MyMonitor is actually a servant!7 8The working method is invoked when a value changes for on change monitors or when thetiming trigger has been executed. Developers override this method to do the real monitoringof data values. The value parameter is the real data value (completion and desc parameters arenot too useful except for timestamps).9 10done is essentially identical to the working method except for the fact that done is invokedwhen the monitor is destroyed.Revision: 4.1Page 15 o23

ALMAACS & Python11 12The only useful thing to know about negotiate is that it should normally return a true value(i.e., 1). For developers really interested in understanding this method, please see the BACISpecifications ([R08]).14Standard way of instantiating a client which logs into manager to access common services andcomponents.16getComponent method of PySimpleClient is quite literally used to get a named component,activating it if necessary. Please take special note we never even had to import the CORBAPython stubs for the MOUNT1 component. PySimpleClient does this automatically!17Under the Python mapping, references to attributes of interfaces are obtained by prepending“ get ” to the attribute’s name and invoking that method on the interface.19 20An instance of the callback class is created. On line 20, the subclass becomes a CORBAobject by utilizing the activateOffShoot ContainerService method.21Explaining CBDescIn and similar IDL structs/interfaces is beyond the scope of this document.This line of code can be simply copied without really understanding what it does. Feel free toreview the BACI Specifications document ([R08]) if you’re really interested though.24Override the default monitor time using this method. It now monitors the property once persecond.25 27Allow the monitor to run for ten seconds and then destroy it.29Since we’re done with this component, release it. Depending on whether or not otherclients/components reference MOUNT1, it may or may not be deactivated.30Must always disconnect from manager when we’re through.6Servant TutorialACS provides a full implementation of the Container IDL interface in Python implyingthat any IDL interface derived from ACS::ACSComponent can be implemented inPython. Furthermore, specific support classes have been placed in the Acspy.Servantspackage to make the developers life easier. In this section, the process of creating aPython CORBA servant is covered from the ground up.Developing an IDL InterfaceRegardless of servant implementation language, the first thing that needs to be done is todefine an IDL interface. It’s assumed the developer has some background in CORBAand IDL so we will not go into too much detail here. Besides the guidelines presented inthe IDL to Python mapping section, there is only one rule which must be followed:developer defined IDL interfaces must be derived from the ACS::ACSComponentinterface in some form. This stipulation is imposed on all programming languages ACSRevision: 4.1Page 16 o23

ALMAACS & Pythonsupports! Now an example IDL will be presented which will be used throughout the restof the servant tutorial.1:2:#ifndef HELLODEMO IDL#define HELLODEMO IDL3:4:#include acscomponent.idl 5:6:#pragma prefix "alma"7:8:9:10:11:12:13:14:15:16:17:18:module demo{interface HelloDemo : ACS::ACSComponent{string sayHello();string sayHelloWithParameters(in string inString,inout double inoutDouble,out long outInt);};};#endif1, 2,& 13It is critical that IDL files use include guards.4Used to access the ACSComponent interface.6This line is standard for all ALMA IDL interfaces.8The module’s name is arbitrary except that it should not conflict with Python package names(i.e., “module sys” or “module Acspy” are extremely bad names).10Choose any name you want for the interface. Just make sure it is derived fromACSComponent.Revision: 4.1Page 17 o23

ALMA12 15ACS & PythonTwo methods are defined for this simple example. Both return strings and the differencebetween the two is that one uses parameters.The Servants PackageServant helper classes can be found in Acspy.Servants. They are designed to provideservices to servants, give the developer an implementation of the ACSComponentinterface, as well as provide methods which only the container can invoke when thecomponent is started, stopped, or ends up in some error state (LifeCycle interface). Fordetails, see the pydoc.A Python Implementation for the IDL InterfaceSo far an IDL interface has been defined in the “demo” module. Well the Pythonmapping specifies the IDL compiler will generate a Python package for that IDL moduleand name it “demo POA”. By convention, we will create a Python package which justconsists of “Impl” appended to the IDL module’s name. In our case, this will be the“demoImpl” package. Also by convention, we place the real implementation of the IDLinterface inside a Python module of an identical name. This must sound pretty confusing,but this class diagram should hopefully help some:Revision: 4.1Page 18 o23

ALMAACS & PythonNow the src directory you’re working in should hopefully contain the followingdeveloper defined Python package demoImpl/HelloDemo.py. Now we can finally seewhat the real implementation looks like:1:2:3:4:5:6:7:8:9:10:11:12:13:14:import demo POAfrom Acspy.Servants.ContainerServicesimport ContainerServicesfrom Acspy.Servants.ComponentLifecycle import ComponentLifecyclefrom Acspy.Servants.ACSComponentimport ACSComponent# class HelloDemo(demo nentLifecycle):# def init (self):ACSComponent. init (self)ContainerServices. init (self)# Override ComponentLifecycle methods Revision: 4.1Page 19 o23

ALMAACS & Pythondef initialize(self):try:lamp self.getComponent("LAMP1")self.brightness lamp. get brightness()except Exception, e:print "LAMP1 unavailable:", e# def cleanUp(self):self.releaseComponent("LAMP1")# Implementation of IDL methods def sayHello(self):return "hello"# def sayHelloWithParameters(self, inString, inoutDouble):self.getLogger().logInfo("sayHello called with arguments inString " inString "; inoutDouble " str(inoutDouble) ". Will return 'hello'.")return ("hello", inoutDouble, :31:32:33:34:35:36:37:38:39:# Main defined only for generic testing if name " main ":g HelloDemo()1Must import the package created by the IDL compiler for the IDL interface we will bedeveloping a servant implementation for.2 4ACS servant helper modules are imported.5 35Class HelloDemo is the concrete implementation of the HelloDemo IDL interface. It should benoted that the container requires the implementing Python class to have the same name as theIDL interface (i.e., HelloDemo).6The implementing class must be derived from the CORBA generated class defining theinterface’s methods and attributes.7ACSComponent provides an implementation of the ACS::ACSComponent interface and it ismandatory that components be derived from this class.8Derivation from ContainerServices is highly recommended as this class provides access toother components, ACS services, etc.9The ComponentLifecycle class contains methods (to be overridden) that are only accessible bythe Container. Components should not invoke ComponentLifecycle methods on themselves.Revision: 4.1Page 20 o23

ALMAACS & Python10 13If a developer defines a constructor for the servant implementation, it must callACSComponent and ContainerService’s constructors!14 23Two ComponentLifecycle methods are overridden and show usage of a couple ofContainerServices methods. These are called at object creation and destruction times by thecontainer.15 20In the initialize method, a reference to the “LAMP1” component is obtained and from that weget the “brightness” BACI property.22 23A properly written servant/client will always release other components when done using them.24 35Implementations of the various IDL methods that were defined for the HelloDemo interface.While this should be pretty straightforward, please review the section on parameter ordering inthe Python mapping chapter if any of this seems confusing.37 39Its good practice to ensure your component can at least be instantiated as a Python object.These three lines of code have saved the author an incredible amount of debugging time andshould prove valuable to other developers.Unlike C and Java servants, there are no macros or helper classes that must be created by thedeveloper to make an instance of the servant. In essence, these 38 lines consist of the onlyPython code that needs to be created!Editing the Configuration DatabaseSpecific instructions on creating an ACS Configuration Database can be found in variousother documents, so we will assume only modifications to an existing CDB need to bemade. There is only one file that needs to be modified ACS CDB/CDB/MACI/Components/Components.xml. Here, we just add one entry ofthe “ ” element per component we wish to create:1: Name "HELLODEMO1"2:Code "demoImpl.HelloDemo"3:Type "IDL:alma/demo/HelloDemo:1.0"4:Container "aragornContainer"/ 1Name of the component.2Name of the Python package containing an implementation of the IDL interface defined online 3.Revision: 4.1Page 21 o23

ALMA34ACS & PythonThe interface repository location of the servant’s IDL interface determined from the IDL fileitself. In this case: alma corresponds to #pragma prefix “alma” demo comes from module demo HelloDemo is the IDL interface’s name. For all intensive purposes, the version number will always be 1.0.The name of the Python container responsible for the lifecyle of this component.Makefile SupportThere are several Makefile targets dealing with IDL files, Python packages, etc.developers should familiarize themselves with:TargetIDL FILESDescriptionList of IDL files (without their ‘.idl’ postfix) separated by spaces thatcan be found in the ./idl directory. Specifying this target means thePython CORBA stubs will be created when doing a ‘make all’ from thesr

language. Python is great for scripting, prototyping, web development, and high level applications. It's also a wonderful language for non programmers to use because of its simplicity. Most importantly for ALMA, OMG has defined an IDL to Python CORBA mapping and several vendors offer free ORBs. This implies that anything done in C