7161014 Python client improvements are requested
authorGary Pennington <gary.pennington@oracle.com>
Fri, 04 May 2012 10:14:24 -0700
changeset 849 e46ba1c7ace1
parent 848 d7c7737126e9
child 850 d366f47f3f51
7161014 Python client improvements are requested
usr/src/apis/kstat.xml
usr/src/apis/pam.xml
usr/src/apis/smf.xml
usr/src/apis/zonesbridge.xml
usr/src/cmd/pyclient/kstat_dump.py
usr/src/cmd/pyclient/pyclient.py
usr/src/cmd/pyclient/test.py
usr/src/cmd/rad/daemon/radctl.py
usr/src/cmd/zmgr/zmgr.py
usr/src/cmd/zmgr/ztest.py
usr/src/doc/rad-dev/c-best-practices.xml
usr/src/doc/rad-dev/c-client-python.xml
usr/src/lib/pykstat/rad.py
usr/src/lib/pyrad/Makefile
usr/src/lib/pyrad/adaptor.py
usr/src/lib/pyrad/client.py
usr/src/lib/pyrad/recordmarking.py
usr/src/lib/pyrad/util.py
usr/src/lib/pysmf/rad.py
usr/src/pkg/manifests/system-management-rad-client-rad-python.p5m
usr/src/test/python/client/test_addremove.py
usr/src/test/python/client/test_basetypes.py
usr/src/test/python/client/test_connect.py
usr/src/test/python/client/test_derivedtypes.py
usr/src/test/python/client/test_fallback.py
usr/src/test/python/client/test_list.py
usr/src/test/python/client/test_prop_access.py
usr/src/test/python/client/test_unions.py
usr/src/test/python/common/tests.py
--- a/usr/src/apis/kstat.xml	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/apis/kstat.xml	Fri May 04 10:14:24 2012 -0700
@@ -307,19 +307,17 @@
 import rad.util
 
 # Create a connection
-radconn = rad.util.connect_local()
+radconn = rad.util.connect_unix()
 
 # Retrieve a particular kstat
 kstat_name = rad.client.Name("<strong>com.oracle.solaris.rad.kstat</strong>",
     [("<strong>type</strong>", "Kstat"), ("<strong>class</strong>", "misc"), ("<strong>module</strong>", "cpu_info"),
     ("<strong>instance</strong>", "2"), ("<strong>name</strong>", "cpu_info2")])
-kstat_obj = radconn.get_object(kstat_name)
-
-# Make a native-looking python object that throws RAD exceptions
-kstat = rad.adaptor.RawAdaptor(kstat_obj)
+# Get a native-looking python object that throws RAD exceptions
+kstat = radconn.get_object(kstat_name)
 
 # Retrieve a handle to the Kstype enum
-kstype = kstat._object.types.Kstype
+kstype = rad.client.get_types(kstat).Kstype
 
 # Do something with our kstat
 data = kstat.fresh_snapshot().data
@@ -341,7 +339,7 @@
 kstat = kstats.lookup("cpu_info", "cpu_info2", 2)
 
 # Retrieve a handle to the kstype enum
-kstype = kstat._object.types.Kstype
+kstype = rad.client.get_types(kstat).Kstype
 
 # Do something with our kstat
 data = kstat.fresh_snapshot().data
--- a/usr/src/apis/pam.xml	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/apis/pam.xml	Fri May 04 10:14:24 2012 -0700
@@ -163,7 +163,6 @@
       </para>
 
       <example caption="Authentication API (Python)">
-import rad.adaptor
 import rad.client
 import rad.util
 import os
@@ -176,7 +175,7 @@
 
 def login(auth, lang, user):
     # Retrieve a handle to the BlockType enum
-    BlockType = auth._object.types.BlockType
+    BlockType = rad.client.get_types(auth).BlockType
 
     # Initiate a login
     answer = auth.login(lang, user)
@@ -198,15 +197,13 @@
             answer = auth.submit(response)
 
 # Create a connection
-radconn = rad.util.connect_ssl("nerd")
+radconn = rad.util.connect_tls("nerd")
 
 # Retrieve the auth object
 auth_name = rad.client.Name("com.oracle.solaris.rad.pam",
     [("type", "Authentication")])
-auth_obj = radconn.get_object(auth_name)
-
-# Make a native-looking python object that throws RAD exceptions
-auth = rad.adaptor.RawAdaptor(auth_obj)
+# Get a native-looking python object that throws RAD exceptions
+auth = radconn.get_object(auth_name)
 
 success = login(auth, os.environ.get("LANG"), "talley")</example>
 
--- a/usr/src/apis/smf.xml	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/apis/smf.xml	Fri May 04 10:14:24 2012 -0700
@@ -1188,15 +1188,13 @@
 import rad.util
 
 # Create a connection
-radconn = rad.util.connect_local()
+radconn = rad.util.connect_unix()
 
 # Retrieve a particular service
 service_name = rad.client.Name("<strong>com.oracle.solaris.rad.smf</strong>",
     [("<strong>type</strong>", "<strong>Service</strong>"), ("<strong>service</strong>", "network/physical")])
-service_obj = radconn.get_object(service_name)
-
-# Make a native-looking python object that throws RAD exceptions
-service = rad.adaptor.RawAdaptor(service_obj)
+# Get a native-looking python object that throws RAD exceptions
+service = radconn.get_object(service_name)
 
 # Do something with our service
 print "service %s has %d instances" % (service.fmri, len(service.instances))</example>
@@ -1346,16 +1344,14 @@
 import rad.util
 
 # Create a connection
-radconn = rad.util.connect_local()
+radconn = rad.util.connect_unix()
 
 # Retrieve a particular instance
 instance_name = rad.client.Name("<strong>com.oracle.solaris.rad.smf</strong>",
     [("<strong>type</strong>", "<strong>Instance</strong>"), ("<strong>service</strong>", "network/physical"),
     ("<strong>instance</strong>", "default")])
-instance_obj = radconn.get_object(instance_name)
-
-# Make a native-looking python object that throws RAD exceptions
-instance = rad.adaptor.RawAdaptor(instance_obj)
+# Get a native-looking python object that throws RAD exceptions
+instance = radconn.get_object(instance_name)
 
 # Do something with our instance
 print "instance %s state: %s" % (instance.fmri, instance.state)</example>
@@ -1875,23 +1871,20 @@
       </para>
 
       <example caption="Master API (Python)">
-import rad.adaptor
 import rad.client
 import rad.util
 
 # Create a connection
-radconn = rad.util.connect_local()
+radconn = rad.util.connect_unix()
 
 # Retrieve the Master object
 master_name = rad.client.Name("<strong>com.oracle.solaris.rad.smf</strong>",
     [("<strong>type</strong>", "<strong>Master</strong>")])
-master_obj = radconn.get_object(master_name)
-
-# Make a native-looking python object that throws RAD exceptions
-master = rad.adaptor.RawAdaptor(master_obj)
+# Get a native-looking python object that throws RAD exceptions
+master = radconn.get_object(master_name)
 
 # Retrieve a handle to the SMFState enum
-SMFState = master._object.types.SMFState
+SMFState = rad.client.get_types(master).SMFState
 
 # Do something with the Master object
 print "%d service instances are online" % \
@@ -1910,7 +1903,7 @@
 master = repo.get_master()
 
 # Retrieve a handle to the SMFState enum
-SMFState = master._object.types.SMFState
+SMFState = rad.client.get_types(master).SMFState
 
 # Do something with the master object
 print "%d service instances are online" % \
--- a/usr/src/apis/zonesbridge.xml	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/apis/zonesbridge.xml	Fri May 04 10:14:24 2012 -0700
@@ -203,20 +203,17 @@
         </para>
 
         <example caption="openConsole (Python)">
-import rad.adaptor
 import rad.client
 import rad.util
 
 # Create a connection to the global zone
-radconn = rad.util.connect_local()
+radconn = rad.util.connect_unix()
 
 # Retrieve the zonesbridge.IO object
 zio_name = rad.client.Name("com.oracle.solaris.rad.zonesbridge",
     [("type", "IO")])
-zio_obj = radconn.get_object(zio_name)
-
-# Make a native-looking python object that throws RAD exceptions
-zio = rad.adaptor.RawAdaptor(zio_obj)
+# Get a native-looking python object that throws RAD exceptions
+zio = radconn.get_object(zio_name)
 
 # Open myzone's console
 token = zio.<strong>openConsole</strong>("myzone")
@@ -275,7 +272,7 @@
 import rad.util
 
 # Create a connection to the global zone
-gradconn = rad.util.connect_local()
+gradconn = rad.util.connect_unix()
 
 # Create a connection to zone "myzone" as user "talley"
 # (if user is None or not specified, connect as root)
--- a/usr/src/cmd/pyclient/kstat_dump.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/cmd/pyclient/kstat_dump.py	Fri May 04 10:14:24 2012 -0700
@@ -23,11 +23,12 @@
 #
 
 from __future__ import absolute_import
+import rad.client
 import kstat.rad
 
 kstats = kstat.rad.Kstats()			# get kstat connection
 for i in kstats.lookup_many():
-	types = i.__dict__["_object"].types
+	types = rad.client.get_types(i.__dict__["_object"])
 	info = i.info
 	print "module: %-30.30s  instance: %-6d" % (info.module, info.instance)
 	print "name:   %-30.30s  class:    %-.30s" % (info.name, info.klass)
--- a/usr/src/cmd/pyclient/pyclient.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/cmd/pyclient/pyclient.py	Fri May 04 10:14:24 2012 -0700
@@ -23,32 +23,30 @@
 #
 
 import rad.client as rad
-import rad.adaptor as adapt
 import rad.util as util
 
 # Make connection (AF_UNIX socket lets us bypass authentication)
-rc = util.connect_local()
+rc = util.connect_unix()
 
 # Make a second, completely unauthenticated connection
-rc2 = util.connect_ssl("localhost")
+rc2 = util.connect_tls("localhost")
 
 # Get an authorization token from authenticated session
-auth = adapt.Adaptor(rc.get_object_s("com.oracle.solaris.rad.pam",
-    [("type", "Authentication")]))
+auth = rc.get_object_s("com.oracle.solaris.rad.pam",
+    [("type", "Authentication")])
 token = auth.createToken();
 
 # Redeem token with unauthenticated session
-auth2 = adapt.Adaptor(rc2.get_object_s("com.oracle.solaris.rad.pam",
-    [("type", "Authentication")]))
+auth2 = rc2.get_object_s("com.oracle.solaris.rad.pam",
+    [("type", "Authentication")])
 auth2.redeemToken(auth.user, token)
 
 # Continue using newly authenticated session
 # Obtain service object for application/pkg/server:default
-rawobj = rc2.get_object_s("com.oracle.solaris.vp.panel.common.api.smf_old",
+obj = rc2.get_object_s("com.oracle.solaris.vp.panel.common.api.smf_old",
     [("type", "service"),
     ("service", "application/pkg/server"),
     ("instance", "default")])
-obj = adapt.Adaptor(rawobj)
 
 # Iterate over property groups and their properties
 for pg in obj.PropertyGroups:
@@ -58,15 +56,15 @@
 	propvals = obj.getSnapshotPropertyValues("running", pgname, propname)
 	print '\t%s = %s' % (propname, propvals)
 
-rc2.subscribe(rawobj, "statechange")
+rc2.subscribe(obj, "statechange")
 try:
-    rc2.subscribe(rawobj, "statechange")
+    rc2.subscribe(obj, "statechange")
 except rad.ExistsError, ex:
     print 'Attempt to add listener twice (correctly) failed: %s' % \
 	ex.get_message()
-rc2.unsubscribe(rawobj, "statechange")
+rc2.unsubscribe(obj, "statechange")
 try:
-    rc2.unsubscribe(rawobj, "statechange")
+    rc2.unsubscribe(obj, "statechange")
 except rad.NotFoundError, ex:
     print 'Attempt to remove listener twice (correctly) failed: %s' % \
 	ex.get_message()
--- a/usr/src/cmd/pyclient/test.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/cmd/pyclient/test.py	Fri May 04 10:14:24 2012 -0700
@@ -24,13 +24,12 @@
 
 import rad.client as rad
 import rad.util as util
-import rad.adaptor as adapt
 
 # Make connection (AF_UNIX socket lets us bypass authentication)
-rc = util.connect_local()
+rc = util.connect_unix()
 
 # Make a second, completely unauthenticated connection
-rc2 = util.connect_ssl("localhost")
+rc2 = util.connect_tls("localhost")
 
 print "BEFORE AUTH"
 for o in rc2.list_objects():
@@ -39,19 +38,19 @@
 print ""
 
 # Get an authorization token from authenticated session
-auth = adapt.Adaptor(rc.get_object_s("com.oracle.solaris.rad.pam",
-    [("type", "Authentication")]))
+auth = rc.get_object_s("com.oracle.solaris.rad.pam",
+    [("type", "Authentication")])
 token = auth.createToken();
 
 # Redeem token with unauthenticated session
-auth2 = adapt.Adaptor(rc2.get_object_s("com.oracle.solaris.rad.pam",
-    [("type", "Authentication")]))
+auth2 = rc2.get_object_s("com.oracle.solaris.rad.pam",
+    [("type", "Authentication")])
 auth2.redeemToken(auth.user, token)
 
 # Continue using newly authenticated session
 # Obtain service object for application/pkg/server:default
-obj = adapt.Adaptor(rc2.get_object_s("com.oracle.solaris.rad.smf",
-    [("type", "Master")]))
+obj = rc2.get_object_s("com.oracle.solaris.rad.smf",
+    [("type", "Master")])
 
 print "AFTER AUTH"
 for o in rc2.list_objects():
--- a/usr/src/cmd/rad/daemon/radctl.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/cmd/rad/daemon/radctl.py	Fri May 04 10:14:24 2012 -0700
@@ -28,7 +28,6 @@
 import socket
 import rad.client as client
 import rad.util as util
-import rad.adaptor as adapt
 
 #
 # Path for AF_UNIX control socket
@@ -53,8 +52,8 @@
 	try:
 		name = client.Name("com.oracle.solaris.rad",
 		    [("type", "Control")])
-		rc = util.connect_local(_RAD_PATH_CTL)
-		obj = adapt.RawAdaptor(rc.get_object(name))
+		rc = util.connect_unix(_RAD_PATH_CTL)
+		obj = rc.get_object(name)
 	except IOError:
 		sys.stderr.write('failed to communicate to server\n')
 		return 1
--- a/usr/src/cmd/zmgr/zmgr.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/cmd/zmgr/zmgr.py	Fri May 04 10:14:24 2012 -0700
@@ -19,13 +19,12 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 import socket
 import rad.client as rad
 import rad.util as radutil
-import rad.adaptor as adapt
 import sys
 import getopt
 
@@ -539,17 +538,17 @@
 
 # Inital args look ok.  Connect to rad
 if host:
-	rc = radutil.connect_ssl(host)
+	rc = radutil.connect_tls(host)
 else:
-	rc = radutil.connect_local()
+	rc = radutil.connect_unix()
 
 auth = radutil.RadAuth(rc)
 if auth.handle().user == None:
 	auth.pam_login()
 
-obj = adapt.RawAdaptor(rc.get_object_s("com.oracle.solaris.zonesManagement",
-    [("type", "zonesManager")]))
-types = obj._object.types
+obj = rc.get_object_s("com.oracle.solaris.zonesManagement",
+    [("type", "zonesManager")])
+types = rad.get_types(obj)
 
 res = do_funcs[cmd](args)
 
--- a/usr/src/cmd/zmgr/ztest.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/cmd/zmgr/ztest.py	Fri May 04 10:14:24 2012 -0700
@@ -23,7 +23,6 @@
 
 import socket
 import rad.client as rad
-import rad.adaptor as adapt
 import sys
 
 #
@@ -53,10 +52,11 @@
 
 # Continue using newly authenticated session
 # Obtain service object for application/pkg/server:default
-obj = adapt.Adaptor(rc.get_object_s("com.oracle.solaris.zonesManagement",
-    [("type", "zonesManager")]))
-IpType = obj._object.types.IpType
-ZoneConfig = obj._object.types.ZoneConfig
+obj = rc.get_object_s("com.oracle.solaris.zonesManagement",
+    [("type", "zonesManager")])
+types = rad.get_types(obj)
+IpType = types.IpType
+ZoneConfig = types.ZoneConfig
 
 print ""
 print "Test getSystemState"
--- a/usr/src/doc/rad-dev/c-best-practices.xml	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/doc/rad-dev/c-best-practices.xml	Fri May 04 10:14:24 2012 -0700
@@ -382,7 +382,7 @@
 import rad.util
 
 # Create a connection
-radconn = rad.util.connect_local()
+radconn = rad.util.connect_unix()
 
 # Retrieve a ZPool object
 zpool_name = rad.client.Name("<emphasis role="strong">com.oracle.solaris.rad.zfs</emphasis>",
--- a/usr/src/doc/rad-dev/c-client-python.xml	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/doc/rad-dev/c-client-python.xml	Fri May 04 10:14:24 2012 -0700
@@ -24,14 +24,6 @@
       The RAD Python implementation provides the following
       modules to facilitate client implementation.
     </para>
-    <section><title>adaptor</title>
-      <para>
-        Provides classes which adapt the behaviour of low
-        level RAD instances to be more "Pythonesque" in
-        nature. For instance, RAD protocol errors are mapped
-        to Python exceptions.
-      </para>
-    </section>
     <section><title>client</title>
       <para>
         Provides classes and methods which fully implement the RAD
@@ -58,7 +50,7 @@
           <funcprototype>
             <funcdef>
               <type>RadConnection</type>
-              <function>connect_local</function>
+              <function>connect_unix</function>
             </funcdef>
             <paramdef>
               <type>string</type> <parameter>path</parameter>
@@ -101,7 +93,7 @@
           <funcprototype>
             <funcdef>
               <type>RadConnection</type>
-              <function>connect_ssl</function>
+              <function>connect_tls</function>
             </funcdef>
             <paramdef>
               <type>string</type> <parameter>host</parameter>
@@ -140,60 +132,54 @@
     <example><title>Method Invocation</title>
     <programlisting>
 import rad.util
-import rad.adaptor
 
 # Connect to a local RAD instance.
-rc = rad.util.connect_local()
+with rad.util.connect_unix() as rc:
 
-# Obtain a remote reference to the desired target.
-rawobj= rc.get_object_s("com.example", [("type", "GrabBag")])
-obj = rad.adaptor.RawAdaptor(rawobj)
+    # Obtain a remote reference to the desired target.
+    obj= rc.get_object_s("com.example", [("type", "GrabBag")])
 
-# Invoke a method on the target.
-res = obj.parseString("a test string")
+    # Invoke a method on the target.
+    res = obj.parseString("a test string")
 
-# Print the result.
-print "length: " + str(res.length)
+    # Print the result.
+    print "length: " + str(res.length)
     </programlisting>
     </example>
     <example><title>Attribute Access</title>
     <programlisting>
 import rad.util
-import rad.adaptor
 
 # Connect to a local RAD instance.
-rc = rad.util.connect_local()
+with rad.util.connect_unix() as rc:
 
-# Obtain a remote reference to the desired target.
-rawobj= rc.get_object_s("com.example", [("type", "GrabBag")])
-obj = rad.adaptor.RawAdaptor(rawobj)
+    # Obtain a remote reference to the desired target.
+    obj= rc.get_object_s("com.example", [("type", "GrabBag")])
 
-# Print the object attribute.
-print "Mood: " + str(obj.mood)</programlisting>
+    # Print the object attribute.
+    print "Mood: " + str(obj.mood)
+    </programlisting>
     </example>
     <example><title>Event Subscription</title>
     <programlisting>
 import rad.util
-import rad.adaptor
+
+with rad.util.connect_unix() as rc:
 
-# Connect to a local RAD instance.
-rc = rad.util.connect_local()
+    # Obtain a remote reference to the desired target.
+    obj= rc.get_object_s("com.example", [("type", "GrabBag")])
 
-# Obtain a remote reference to the desired target.
-rawobj= rc.get_object_s("com.example", [("type", "GrabBag")])
-obj = rad.adaptor.RawAdaptor(rawobj)
+    # Subscribe to the "moodswings" event
+    rc.subscribe(obj, "moodswings")
 
-# Subscribe to the "moodswings" event
-rc.subscribe(rawobj, "moodswings")
+    while True:
+        # Perform a (blocking) read of an event
+        ev_obj = obj.read_event()
 
-type = rc.get_type(obj._object._typeid)
-while True:
-    # Perform a (blocking) read of an event
-    ev_obj = type.read_event()
-
-    print "Received Event:"
-    print "mood: " +str(ev_obj.mood)
-    print "changed: " +str(ev_obj.changed)</programlisting>
+        print "Received Event:"
+        print "mood: " +str(ev_obj.mood)
+        print "changed: " +str(ev_obj.changed)
+    </programlisting>
     </example>
   </section>
 </section>
--- a/usr/src/lib/pykstat/rad.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/lib/pykstat/rad.py	Fri May 04 10:14:24 2012 -0700
@@ -27,7 +27,6 @@
 
 from __future__ import absolute_import
 import rad.client as client
-import rad.adaptor as adaptor
 import rad.util as util
 import os
 
@@ -48,15 +47,15 @@
 
     def __init__(self, conn = None):
 	if conn is None:
-	    self._rc = util.connect_local()
+	    self._rc = util.connect_unix()
 	else:
 	    self._rc = conn
 
-	self._ctl = adaptor.Adaptor(self._rc.get_object(Kstats.ctlname))
+	self._ctl = self._rc.get_object(Kstats.ctlname)
 
     def __safe_wrap(self, name):
 	try:
-	    return adaptor.RawAdaptor(self._rc.get_object(name))
+	    return self._rc.get_object(name)
 	except:
 	    pass
 	return None
@@ -77,10 +76,10 @@
 	"""
 	Look up a single kstat instance by module, name, and instance.
 	"""
-	return adaptor.RawAdaptor(self._rc.get_object(
+	return self._rc.get_object(
 	    client.Name(_RAD_KSTAT_DOMAIN, [("type", "Kstat"),
 	    ("module", module), ("name", name),
-	    ("instance", "%d" % instance)])))
+	    ("instance", "%d" % instance)]))
 
     def lookup_many(self, module = None, name = None, instance = None,
 	clazz = None):
--- a/usr/src/lib/pyrad/Makefile	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/lib/pyrad/Makefile	Fri May 04 10:14:24 2012 -0700
@@ -20,13 +20,13 @@
 #
 
 #
-# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 include $(SRC)/Makefile.env
 
 PROTO_PYRAD = $(PROTO_PYTHON)/rad
-PYSRCS = __init__.py adaptor.py client.py recordmarking.py util.py
+PYSRCS = __init__.py client.py recordmarking.py util.py
 PYOBJS = $(PYSRCS:%.py=%.pyc)
 PYFILES = $(PYSRCS) $(PYOBJS)
 INSTFILES = $(PYFILES:%=$(PROTO_PYRAD)/%)
--- a/usr/src/lib/pyrad/adaptor.py	Fri Apr 27 01:54:08 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-import xdrlib
-import threading
-import rad.recordmarking as recordmarking
-import rad.client
-
-#
-# Base adaptor classes, which do the bare minimum necessary.
-# Exceptions generated by the rad client are passed straight through.
-# Subclasses are free to map exceptions to meet their needs.
-#
-
-class RawAdaptorMethod(object):
-    def __init__(self, realmeth):
-        self._method = realmeth
-
-    def __call__(self, *args):
-	return self._method.call(*args)
-
-class RawAdaptor(object):
-    """ Makes a native-looking python object that throws RAD exceptions """
-
-    def __init__(self, realobj, adapt = RawAdaptorMethod):
-	# We complicate __init__ slightly to streamline __getattr__/__setattr__
-	self.__dict__["_object"] = realobj
-	self.__dict__.update(dict([[i._name, adapt(i)]
-	    for i in realobj._methods.values()]))
-
-    def __getattr__(self, attr):
-    	obj = self.__dict__["_object"]
-    	try:
-		return obj.read(attr)
-	except KeyError as e:
-		raise AttributeError("%s has no attribute %s" %
-		    (obj._name, attr))
-
-    def __setattr__(self, attr, value):
-    	obj = self.__dict__["_object"]
-    	try:
-		obj.write(attr, value)
-	except KeyError as e:
-		raise AttributeError("%s has no attribute %s" %
-		    (obj._name, attr)) 
-
-    def __repr__(self):
-	return "< RawAdaptor: %s >" % str(self.__dict__["_object"])
-
-#
-# Adaptor classes that map all errors to Python-like exceptions.
-#
-
-class AdaptorMethod(RawAdaptorMethod):
-    def __call__(self, *args):
-	try:
-             return RawAdaptorMethod.__call__(self, *args)
-	except Exception as e:
-	     raise AttributeError(e)
-
-class Adaptor(RawAdaptor):
-    """ Makes a native-looking python object """
-
-    def __init__(self, realobj):
-    	RawAdaptor.__init__(self, realobj, AdaptorMethod)
-
-    def __getattr__(self, attr):
-    	try:
-		return RawAdaptor.__getattr__(self, attr)
-	except AttributeError: raise
-	except rad.client.InvalidFeatureError as e:
-		raise AttributeError(e.get_message())
-	except Exception as e:
-		raise AttributeError(e)
-
-    def __setattr__(self, attr, value):
-    	try:
-		RawAdaptor.__setattr__(self, attr, value)
-	except AttributeError: raise
-	except rad.client.InvalidFeatureError as e:
-		raise AttributeError(e.get_message())
-	except Exception as e:
-		raise AttributeError(e)
-
-    def __repr__(self):
-	return "< Adaptor: %s >" % str(self.__dict__["_object"])
--- a/usr/src/lib/pyrad/client.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/lib/pyrad/client.py	Fri May 04 10:14:24 2012 -0700
@@ -1,4 +1,4 @@
-#
+# 
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
@@ -23,13 +23,26 @@
 # Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
+"""client - RAD python client language binding
+
+This module is the main implementation of the RAD python language
+binding. The RadConnection class acts as the primary interface and offers
+a connection to a RAD instance which may be used to:
+
+    - locate objects
+    - invoke object methods
+    - read/write object properties
+    - subscribe/unsubscribe to object events
+"""
 import locale as oslocale
 import xdrlib
 import threading
+import types
 import datetime
 import rad.recordmarking as recordmarking
 
-class Op(object):
+class _Op(object):
+    """ RAD protocol Operations. """
     INVOKE = 0
     GETATTR = 1
     SETATTR = 2
@@ -39,7 +52,8 @@
     SUB = 6
     UNSUB = 7
 
-class Type(object):
+class _Type(object):
+    """ RAD protocol basic types. """
     VOID = 0
     BOOLEAN = 1
     INTEGER = 2
@@ -58,7 +72,8 @@
     COMPOSITE = 15
     UNION = 16
 
-class Error(object):
+class _Error(object):
+    """ RAD protocol error codes. """
     OK = 0
     OBJECT = 1
     NOMEM = 2
@@ -69,12 +84,14 @@
     MISMATCH = 7
     ILLEGAL = 8
 
-TYPES = set(range(17))
-DERIVED = set([ Type.ARRAY, Type.COMPOSITE, Type.ENUM, Type.UNION ])
-BASE = TYPES - DERIVED
+_TYPES = set(range(17))
+_DERIVED = set([ _Type.ARRAY, _Type.COMPOSITE, _Type.ENUM, _Type.UNION ])
+_BASE = _TYPES - _DERIVED
 
-class RequestError(Exception):
+class _RequestError(Exception):
+    """ A RAD protocol request error. """
     def __init__(self, error, payload):
+	""" Create a _RequestError object. """
 	self._error = error
 	self._payload = payload
 
@@ -82,10 +99,12 @@
 	return 'Request error: ' + self.get_message()
 
     def get_message(self):
-	return '%s (%d)' % (errors[self._error][0], self._error)
+	return '%s (%d)' % (_errors[self._error][0], self._error)
 
-class ContainerError(Exception):
+class _ContainerError(Exception):
+    """ A RAD error base class. """
     def __init__(self, msg, ex, error = None):
+	""" Create a _ContainerError object. """
     	self._msg = msg
     	self._error = ex
 	if error:
@@ -103,67 +122,747 @@
     	if self._payload:
 	    return self._payload.__str__()
 	else:
-	    return errors[self._error._error][0]
+	    return _errors[self._error._error][0]
 
-class ObjectError(ContainerError):
+class ObjectError(_ContainerError):
     pass
 
-class NomemError(ContainerError):
+class NomemError(_ContainerError):
     pass
 
-class NotFoundError(ContainerError):
+class NotFoundError(_ContainerError):
     pass
 
-class PrivError(ContainerError):
+class PrivError(_ContainerError):
     pass
 
-class SystemError(ContainerError):
+class SystemError(_ContainerError):
     pass
 
-class ExistsError(ContainerError):
+class ExistsError(_ContainerError):
     pass
 
-class MismatchError(ContainerError):
+class MismatchError(_ContainerError):
     pass
 
-class IllegalError(ContainerError):
+class IllegalError(_ContainerError):
     pass
 
-errors = {
-    Error.OK : [ 'no error', None ],
-    Error.OBJECT : [ 'object-specific error', ObjectError ],
-    Error.NOMEM : [ 'out of memory', NomemError ],
-    Error.NOTFOUND : [ 'not found', NotFoundError ],
-    Error.PRIV : [ 'insufficient privileges', PrivError ],
-    Error.SYSTEM : [ 'system error', SystemError ],
-    Error.EXISTS : [ 'already exists', ExistsError ],
-    Error.MISMATCH : [ 'type mismatch', MismatchError ],
-    Error.ILLEGAL : [ 'illegal access', IllegalError ]
+_errors = {
+    _Error.OK : [ 'no error', None ],
+    _Error.OBJECT : [ 'object-specific error', ObjectError ],
+    _Error.NOMEM : [ 'out of memory', NomemError ],
+    _Error.NOTFOUND : [ 'not found', NotFoundError ],
+    _Error.PRIV : [ 'insufficient privileges', PrivError ],
+    _Error.SYSTEM : [ 'system error', SystemError ],
+    _Error.EXISTS : [ 'already exists', ExistsError ],
+    _Error.MISMATCH : [ 'type mismatch', MismatchError ],
+    _Error.ILLEGAL : [ 'illegal access', IllegalError ]
 }
 
-def raise_error(ex, msg = None):
-    raise errors[ex._error][1](msg, ex, None)
+def _raise_error(ex, msg = None):
+    raise _errors[ex._error][1](msg, ex, None)
+
+class _RadBuilder(type):
+    """ Metaclass which creates methods and properties at runtime for a
+        class based on the RAD definition of those
+        methods/attributes. """
+
+    def __call__(cls, *args, **kwds):
+        obj = type.__call__(cls, *args, **kwds)
+        if "_rad_ready" not in cls.__dict__.keys():
+            cls.add_methods(obj._methods.keys())
+            cls.add_properties(obj._type._attributes)
+            cls._rad_ready = True
+        return obj
+
+    def add_methods(self, methods):
+        for method in methods:
+            rad_method = self.create_caller(method)
+            rad_method.__doc__ = "RAD Method"
+            setattr(self, method, rad_method)
+
+    def add_properties(self, properties):
+        for prop in properties:
+            setattr(self, "_get_" + prop, self.create_getter(prop))
+            setattr(self, "_set_" + prop, self.create_setter(prop))
+            setattr(self, prop, property(eval("self._get_" + prop),
+                eval("self._set_" + prop), None, "RAD Property"))
 
-# Should only be used when there is a mismatch, but is currently used
-# as a catch-all.  Fix.
+    def create_caller(self, method):
+        return lambda self, *args : self._call(method, *args)
+
+    def create_getter(self, prop):
+        return lambda self : self._read(prop)
+
+    def create_setter(self, prop):
+        return lambda self, value : self._write(prop, value)
 
-class InvalidFeatureError(Exception):
-    def __init__(self, name, msg = None):
-    	self._name = name
-	self._msg = msg
+class _RadField(object):
+    """ A RAD field. Used to represent a field in a derived type. """
+    def __init__(self, unpacker, types):
+	""" Create a _RadField object. """
+	self._name = unpacker.unpack_string()
+	self._nullable = unpacker.unpack_bool()
+	self._type = types.typeref(unpacker)
+
+class _RadEnumVal(object):
+    """ A RAD Enumeration value. """
+    def __init__(self, type, index, unpacker = None):
+	""" Create a _RadEnumVal object. """
+	self._type = type
+	self._index = index
+	if unpacker:
+	    self._name = unpacker.unpack_string()
+	    self._value = unpacker.unpack_uint()
+	else:
+	    self._name = type._fallback
 
     def __str__(self):
-	return self.get_message()
+	return self._name
+
+    def __repr__(self):
+	""" A string representation of this instance. """
+	return "<%s.%s>" % (self._type._name, self._name)
+
+#
+# Superclass for synthetic structure objects
+#
+class _RadData(object):
+    """ The superclass for synthetic structure objects. """
+    def __init__(self, type):
+	""" Create a _RadData object. """
+	self._type = type
+
+    def __repr__(self):
+	""" A string representation of this instance. """
+    	return "%s(%s)" % (self._type._name, ", ".join(map(
+	    lambda f: "%s = %r" % (f._name, self.__dict__[f._name]),
+	    self._type._fields.values())))
+
+#
+# Synthetic constructor for _RadData instances
+#
+class _RadDataConstructor(object):
+    """ A synthetic package for RAD Data instances. """
+    def __init__(self, type):
+	""" Create a _RadDataConstructor object. """
+	self._type = type
+
+    def __call__(self, *pargs, **kargs):
+    	return self._type.make(pargs, kargs)
+
+#
+# Superclass for synthetic enumeration "types"
+#
+class _RadEnum(object):
+    """ A RAD Enumeration. """
+    def __init__(self, type):
+	""" Create a _RadEnum object. """
+	self._type = type
+	for v in type._pvalues:
+	    self.__dict__[v._name] = v
+	if type._fbvalue:
+	    self.__dict__[type._fallback] = type._fbvalue
+
+#
+# Superclass for synthetic union "types"
+#
+class _RadUnion(object):
+    """ A RAD Union. """
+    def __init__(self, type, arm, armvalue, value):
+	""" Create a _RadUnion object. """
+    	if arm == None:
+	    raise Exception("%s: no arm for discriminant: %s" %
+		(type._name, str(armvalue)))
+
+	if value == None and arm != None and not arm._nullable and \
+	    arm._type._type != _Type.VOID:
+
+	    raise Exception("%s: arm required for discriminant: %s" %
+		(type._name, str(armvalue)))
+
+	self._type = type
+	self._arm = arm
+	self.u_arm = self._armvalue = armvalue
+	self.u_val = value
+
+    def __repr__(self):
+	""" A string representation of this instance. """
+    	return "%s(%s, %s)" % (self._type._name, self.u_arm, self.u_val)
+
+#
+# Synthetic constructor for _RadUnion instances
+#
+class _RadUnionConstructor(object):
+    """ A synthetic package for RAD unions. """
+    def __init__(self, type):
+	""" Create a _RadUnionConstructor object. """
+	self._type = type
+
+    def __call__(self, armvalue, value):
+	for arm in self._type._arms:
+	    if arm._value == armvalue:
+		return _RadUnion(self._type, arm, armvalue, value)
+	return _RadUnion(self._type, self._type._default, armvalue, value)
+
+def _read_time(unpacker):
+    seconds = unpacker.unpack_hyper()
+    nanos = unpacker.unpack_int()
+    dt = datetime.datetime.utcfromtimestamp(seconds)
+    return dt + datetime.timedelta(microseconds=(nanos/1000))
+
+def _write_time(packer, data):
+    naive = data.tzinfo == None or data.tzinfo.utcoffset(data) == None
+    if naive:
+	delta = data - datetime.datetime(1970, 1, 1)
+    else:
+	delta = data - datetime.datetime(1970, 1, 1, tzinfo=timezone.utc)
+    timestamp = delta / datetime.timedelta(microseconds=1)
+    packer.pack_hyper(timestamp / 1000000)
+    packer.pack_int((timestamp % 1000000) * 1000)
+
+#
+# Synthetic package that will contain _RadEnums and _RadDataConstructors
+#
+class _RadTypeSpace(object):
+    """ A synthetic package used to model RAD Enumerations and
+         RAD Data Constructors. """
+    def __init__(self, types):
+	""" Create a _RadTypeSpace object. """
+	self.__dict__.update(types)
+
+class _RadType(object):
+    """ A RAD Type. """
+    def __init__(self, type):
+	""" Create a _RadType object. """
+	self._type = type
+
+    def read(self, unpacker, nullable=False):
+	if nullable and not unpacker.unpack_bool(): return None
+	if self._type == _Type.VOID:
+	    pass
+	elif self._type == _Type.BOOLEAN:
+	    return unpacker.unpack_bool()
+	elif self._type == _Type.INTEGER:
+	    return unpacker.unpack_int()
+	elif self._type == _Type.STRING:
+	    return unpacker.unpack_string()
+	elif self._type == _Type.OPAQUE:
+	    return unpacker.unpack_opaque()
+	elif self._type == _Type.LONG:
+	    return unpacker.unpack_hyper()
+	elif self._type == _Type.TIME:
+	    return _read_time(unpacker)
+	elif self._type == _Type.ULONG:
+	    return unpacker.unpack_uhyper()
+	elif self._type == _Type.UINT:
+	    return unpacker.unpack_uint()
+	elif self._type == _Type.NAME:
+	    return Name.parse(unpacker.unpack_string())
+	elif self._type == _Type.SECRET:
+	    return unpacker.unpack_string()
+	elif self._type == _Type.FLOAT:
+	    return unpacker.unpack_float()
+	elif self._type == _Type.DOUBLE:
+	    return unpacker.unpack_double()
+
+    def write(self, packer, data, nullable=False):
+	if nullable:
+	    isdata = data != None
+	    packer.pack_bool(isdata)
+	    if not isdata: return
+	if self._type == _Type.VOID:
+	    pass
+	elif self._type == _Type.BOOLEAN:
+	    return packer.pack_bool(data)
+	elif self._type == _Type.INTEGER:
+	    return packer.pack_int(data)
+	elif self._type == _Type.STRING:
+	    return packer.pack_string(data)
+	elif self._type == _Type.OPAQUE:
+	    return packer.pack_opaque(data)
+	elif self._type == _Type.LONG:
+	    return packer.pack_hyper(data)
+	elif self._type == _Type.TIME:
+	    _write_time(packer, data)
+	elif self._type == _Type.ULONG:
+	    return packer.pack_uhyper(data)
+	elif self._type == _Type.UINT:
+	    return packer.pack_uint(data)
+	elif self._type == _Type.NAME:
+	    return packer.pack_string(str(data))
+	elif self._type == _Type.SECRET:
+	    return packer.pack_string(data)
+	elif self._type == _Type.FLOAT:
+	    return packer.pack_float(data);
+	elif self._type == _Type.DOUBLE:
+	    return packer.pack_double(data);
+
+class _RadUnionArm(object):
+    """ A RAD Union arm. """
+    def __init__(self, unpacker, types, index, value):
+	""" Create a _RadUnionArm object. """
+	self._index = index
+	self._value = value
+	self._nullable = unpacker.unpack_bool()
+	self._type = types.typeref(unpacker)
+
+class _RadDerivedType(_RadType):
+    """ A RAD Derived type. """
+    def __init__(self, unpacker, types):
+	""" Create a _RadDerivedType object. """
+	_RadType.__init__(self, unpacker.unpack_uint())
+	if self._type == _Type.ARRAY:
+	    self._atype = types.typeref(unpacker)
+	elif self._type == _Type.COMPOSITE:
+	    self._name = unpacker.unpack_string()
+	    self._pfields = unpacker.unpack_array(
+		lambda: _RadField(unpacker, types))
+	    self._fields = dict([(i._name, i) for i in self._pfields])
+	    types._typedict[self._name] = self
+	    types._concrete[self._name] = _RadDataConstructor(self)
+	elif self._type == _Type.ENUM:
+	    self._name = unpacker.unpack_string()
+	    if unpacker.unpack_bool():
+		self._fallback = unpacker.unpack_string()
+	        self._fbvalue = _RadEnumVal(self, 0)
+	    else:
+		self._fallback = self._fbvalue = None
+	    nvalues = unpacker.unpack_uint()
+	    self._pvalues = [ _RadEnumVal(self, i + 1, unpacker)
+	        for i in range(nvalues) ]
+	    types._typedict[self._name] = self
+	    types._concrete[self._name] = _RadEnum(self)
+	elif self._type == _Type.UNION:
+	    self._name = unpacker.unpack_string()
+	    self._utype = types.typeref(unpacker)
+	    if unpacker.unpack_bool():
+	        self._default = _RadUnionArm(unpacker, types, 0, None)
+	    else:
+		self._default = None
+	    self._narms = unpacker.unpack_uint();
+	    self._arms = [
+	        _RadUnionArm(unpacker, types, i + 1, self._utype.read(unpacker))
+		for i in range(self._narms) ]
+	    types._typedict[self._name] = self
+	    types._concrete[self._name] = _RadUnionConstructor(self)
+
+    def make(self, pargs, kargs):
+	""" Make the composite type using the supplied pargs and
+	     kargs. """
+	if self._type != _Type.COMPOSITE:
+	    raise Exeception("make() only invokable on composite types")
+
+	o = _RadData(self)
+	n = len(pargs)
+	nfields = 0
+
+	if n > len(self._pfields):
+	    raise Exception("Too many fields specified for " + self._name)
+
+	for (i, field) in enumerate(self._pfields):
+	    if i < n:
+		value = pargs[i]
+		if field._name in kargs:
+		    raise Exception("Field '%s' of '%s' assigned twice" %
+		        (field._name, self._name))
+	    else:
+		value = kargs.get(field._name)
+		if field._name in kargs:
+		    nfields = nfields + 1
+
+	    if value == None and not field._nullable:
+		    raise Exception("Field '%s' of '%s' must be specified" %
+			(field._name, self._name))
+
+	    o.__dict__[field._name] = value
+
+	if len(kargs) > nfields:
+	    raise Exception("Unrecognized fields specified for " + self._name)
+
+	return o
+
+    def read(self, unpacker, nullable=False):
+	""" Read and return the remote value of this derived type
+	    from the supplied unpacker. """
+	if nullable and not unpacker.unpack_bool(): return None
+	if self._type == _Type.ARRAY:
+	    return unpacker.unpack_array(lambda: self._atype.read(unpacker))
+	elif self._type == _Type.COMPOSITE:
+	    o = _RadData(self)
+	    for i in self._pfields:
+		o.__dict__[i._name] = i._type.read(unpacker, i._nullable)
+	    return o
+	elif self._type == _Type.ENUM:
+	    val = unpacker.unpack_int();
+	    if val > 0 and val <= len(self._pvalues):
+		return self._pvalues[val - 1]
+	    if val == 0 and self._fbvalue != None:
+		return self._fbvalue
+	    raise Exception("Bad enumeration value from server")
+	elif self._type == _Type.UNION:
+	    index = unpacker.unpack_uint()
+	    if index > self._narms:
+		raise Exception("Bad union arm index from server")
+
+	    if index > 0:
+		arm = self._arms[index - 1]
+		armvalue = arm._value;
+	    else:
+	        arm = self._default
+		armvalue = self._utype.read(unpacker, False)
+		for a in self._arms:
+		    if a._value == armvalue:
+			raise Exception("Bad union discriminant from server")
+	    if arm == None:
+		raise Exception("Bad default arm reference from server")
+
+	    data = arm._type.read(unpacker, arm._nullable)
+	    return _RadUnion(self, arm, armvalue, data)
 
-    def get_name(self):
-    	return self._name
+    def write(self, packer, data, nullable=False):
+	""" Set the remote derived type that this instance represents to
+	    the supplied value. Use the supplied packer to encode
+	    the data."""
+	if nullable:
+	    isdata = data != None
+	    packer.pack_bool(isdata)
+	    if not isdata: return
+	if self._type == _Type.ARRAY:
+	    packer.pack_array(data,
+		lambda x: self._atype.write(packer, x))
+	elif self._type == _Type.COMPOSITE:
+	    for i in self._pfields:
+		if i._name in data.__dict__:
+		    i._type.write(packer, data.__dict__[i._name], i._nullable)
+		else:
+		    i._type.write(packer, None, i._nullable)
+	elif self._type == _Type.ENUM:
+	    if not data._type == self:
+		raise Exception("Enumeration type mismatch: " +
+		    data._type._name)
+	    packer.pack_int(data._index)
+	elif self._type == _Type.UNION:
+	    index = data._arm._index
+	    packer.pack_uint(index)
+	    if index == 0:
+		self._utype.write(packer, data._armvalue)
+	    data._arm._type.write(packer, data.u_val, data._arm._nullable)
+
+
+class _RadTypeSet(object):
+    """ A RAD TypeSet. """
+    basetypes = [ _RadType(x) if x in _BASE else None for x in _TYPES ]
+
+    def __init__(self, unpacker):
+	""" Create a _RadTypeSet object. """
+	self._types = []
+	self._typedict = {}
+	self._concrete = {}
+	ntypes = unpacker.unpack_int();
+	for i in range(ntypes):
+	    self._types.insert(i, _RadDerivedType(unpacker, self))
+
+    def typeref(self, unpacker):
+	""" Return the type contained in the unpacker. """
+	type = unpacker.unpack_int();
+	if type in _DERIVED:
+	    return self._types[unpacker.unpack_int()]
+	else:
+	    return _RadTypeSet.basetypes[type]
+
+    def lookup(self, name):
+	""" Return the type identified by the name. """
+	return self._typedict[name]
+
+    def typespace(self):
+	""" Return the type space. """
+    	return _RadTypeSpace(self._concrete)
+
+class _RadAttribute(object):
+    """ A RAD Attribute. """
+    def __init__(self, unpacker, types):
+	""" Create a _RadAttribute object. """
+	self._name = unpacker.unpack_string()
+	self._stability = unpacker.unpack_enum()
+	self._readable = unpacker.unpack_bool()
+	self._writable = unpacker.unpack_bool()
+	self._nullable = unpacker.unpack_bool()
+	self._type = types.typeref(unpacker)
+	if unpacker.unpack_bool():
+		self._read_error = types.typeref(unpacker)
+	else:
+		self._read_error = None
+	if unpacker.unpack_bool():
+		self._write_error = types.typeref(unpacker)
+	else:
+		self._write_error = None
+
+    def read(self, instance):
+	""" Read and return the remote value of this attribute
+	    on the supplied instance. """
+	if not self._readable:
+	    raise InvalidFeatureError(self._name,
+	        'Attribute %s of %s isn\'t readable' %
+		(self._name, instance._name))
+
+	p = xdrlib.Packer()
+	p.pack_hyper(instance._id)
+	p.pack_string(self._name)
+	conn = instance._connection
+	ser = conn._make_request(_Op.GETATTR, p.get_buffer())
+
+	try:
+	    return self._type.read(conn._read_response(ser, None), True)
+	except _RequestError, ex:
+	    if ex._error == 1:
+	    	raise ObjectError("Object-specific error", ex, self._read_error)
+	    _raise_error(ex, 'Error getting %s from %s: %d' %
+		(self._name, instance._name, ex._error))
+
+    def write(self, instance, value):
+	""" Set the remote attribute that this instance represents to
+	    the supplied value. """
+	if not self._writable:
+	    raise InvalidFeatureError(self._name,
+	        'Attribute %s of %s isn\'t writable' %
+		(self._name, instance._name))
+
+	p = xdrlib.Packer()
+	p.pack_hyper(instance._id)
+	p.pack_string(self._name)
+	data = xdrlib.Packer()
+	self._type.write(data, value, True)
+	p.pack_opaque(data.get_buffer())
+	conn = instance._connection
+	ser = conn._make_request(_Op.SETATTR, p.get_buffer())
+
+	try:
+	    conn._read_response(ser, None)
+	except _RequestError, ex:
+	    if ex._error == 1:
+		raise ObjectError("Object-specific error", ex,
+		    self._write_error)
+	    _raise_error(ex, 'Error setting %s on %s: %d' %
+		(self._name, instance._name, ex._error))
+
+
+class _RadArg(object):
+    """ A RAD Argument. """
+    def __init__(self, unpacker, types):
+	""" Create a _RadArg object. """
+	self._name = unpacker.unpack_string()
+	self._nullable = unpacker.unpack_bool()
+	self._type = types.typeref(unpacker)
+
+class _RadMethod(object):
+    """ A RAD Method. """
+    def __init__(self, unpacker, types):
+	""" Create a _RadMethod object. """
+	self._name = unpacker.unpack_string()
+	self._stability = unpacker.unpack_enum()
+	self._nullable = unpacker.unpack_bool()
+	self._type = types.typeref(unpacker)
+	if unpacker.unpack_bool():
+		self._error = types.typeref(unpacker)
+	else:
+		self._error = None
+	self._args = unpacker.unpack_array(lambda : _RadArg(unpacker, types))
+
+    def call(self, instance, *args):
+	""" Call the RAD method using the instance connection and supplying
+	    args. """
+	if len(self._args) != len(args):
+	    raise InvalidFeatureError(self._name,
+		"%s called with invalid # of args (received %d, expected %d)" %
+		(self._name, len(args), len(self._args)))
 
-    def get_message(self):
-    	if self._msg: return self._msg
-	return 'Feature not found: ' + self._name
+	p = xdrlib.Packer()
+	p.pack_hyper(instance._id)
+	p.pack_string(self._name)
+	p.pack_uint(len(args))
+	for i in range(len(args)):
+	    pp = xdrlib.Packer()
+	    self._args[i]._type.write(pp, args[i], True)
+	    p.pack_opaque(pp.get_buffer())
+	conn = instance._connection
+	ser = conn._make_request(_Op.INVOKE, p.get_buffer())
+
+	try:
+	    return self._type.read(conn._read_response(ser, None), True)
+	except _RequestError, ex:
+	    if ex._error == 1:
+	    	raise ObjectError("Object-specific error", ex, self._error)
+	    _raise_error(ex, 'Error invoking %s on %s: %d' %
+		(self._name, instance._name, ex._error))
+
+class _RadEventType(object):
+    """ A RAD Event type. """
+    def __init__(self, unpacker, types):
+	""" Create a _RadEventType object. """
+	self._name = unpacker.unpack_string()
+	self._stability = unpacker.unpack_enum()
+	self._type = types.typeref(unpacker)
+
+    def read(self, instance):
+	""" Read and return the payload of the event on the supplied
+	    instance. """
+	up = xdrlib.Unpacker(instance._payload)
+	return self._type.read(up, True)
+
+class _RadApiVersion(object):
+    """ A RAD API version. """
+    def __init__(self, unpacker):
+	""" Create a _RadApiVersion object. """
+        stabilities = 'undefined', 'private', 'uncommitted', 'committed'
+        self._stability = stabilities[unpacker.unpack_enum()]
+        self._major = unpacker.unpack_int()
+        self._minor = unpacker.unpack_int()
+
+class _RadApi(object):
+    """ A RAD API. """
+    def __init__(self, unpacker):
+	""" Create a _RadApi object. """
+	self._versions = []
+	for i in range(3):
+	    self._versions.append(_RadApiVersion(unpacker))
+	
+class _RadObjectType(object):
+    """ A RAD type. """
+    def __init__(self, connection, id, unpacker):
+	""" Create a _RadObjectType object. """
+	self._connection = connection
+	self._id = id
+	self._apis = {}
+	self._iface = unpacker.unpack_string()
+	napis = unpacker.unpack_int()
+	for i in range(napis):
+	    aname = unpacker.unpack_string()
+	    self._apis[aname] = _RadApi(unpacker)
+	self._typeset = _RadTypeSet(unpacker)
+	self._attributes = dict([[i._name, i] for i in unpacker.unpack_array(
+	    lambda : _RadAttribute(unpacker, self._typeset))])
+	self._methods = unpacker.unpack_array(
+	    lambda : _RadMethod(unpacker, self._typeset))
+	self._events = dict([[i._name, i] for i in unpacker.unpack_array(
+	    lambda : _RadEventType(unpacker, self._typeset))])
+
+	self.types = self._typeset.typespace()
+
+    def read(self, instance, attr):
+	""" Read and return the value of the attribute on the supplied
+	    instance. """
+	try:
+	    return self._attributes[attr].read(instance)
+	except KeyError:
+	    raise InvalidFeatureError(instance._name,
+		"%s has no attribute %s" % (instance._name, attr))
+
+    def read_event(self):
+	""" Read and return an event. """
+	instance = self._connection.read_event()
+	try:
+		return self._events[instance._event].read(instance)
+	except KeyError:
+		raise InvalidFeatureError(self._iface,
+		    "%s has no event %s" % (self._iface, instance._event))
+
+    def write(self, instance, attr, value):
+	""" Set the specified attribute, attr, to the supplied value
+	    on the supplied instance. """
+	try:
+	    self._attributes[attr].write(instance, value)
+	except KeyError:
+	    raise InvalidFeatureError(instance._name,
+		"%s has no attribute %s" % (instance._name, attr))
+
+    def call(self, instance, meth, *args):
+	""" Call the method, meth, on instance, instance, with args. """
+	return self._methods[meth].call(instance, *args)
+
+    def __repr__(self):
+	""" A string representation of this instance. """
+	return "< Remote RAD type: %s >" % self._iface
+
+class _RadObject(object):
+    """ A RAD remote object instance. """
+
+    __metaclass__ = _RadBuilder
+
+    def __init__(self, connection, name, unpacker, id, typeid):
+	""" Create a _RadObject object. """
+	self._connection = connection
+	self._name = name
+	self._id = id
+	self._typeid = typeid
+	if unpacker.unpack_bool():
+	    self._type = connection._remember_type(self._typeid, unpacker, False)
+	else:
+	    self._type = connection._get_type(self._typeid)
+	self._methods = dict([[i._name, i] for i in self._type._methods])
+
+	self.types = self._type.types
+
+    def _read(self, attr):
+	""" Read and return the remote value of the supplied attr. """
+	return self._type.read(self, attr)
+
+    def _read_event(self):
+	""" Read and return an event. """
+	return self._type.read_event()
+
+    def _write(self, attr, value):
+	""" Set the specified attribute, attr, to the supplied value. """
+	self._type.write(self, attr, value)
+
+    def _call(self, meth, *args):
+	""" Call the method, meth, with args. """
+	return self._methods[meth].call(self, *args)
+
+    def __repr__(self):
+	""" A string representation of this instance. """
+        return "< Remote RAD object: %s >" % self._name
+
+class _RadReader(threading.Thread):
+    """ A utility class which reads RAD protocol message and posts
+        them on for further consumption. """
+    def __init__(self, connection):
+	""" Create a RadConnection object. """
+	threading.Thread.__init__(self)
+	self.daemon = True
+    	self._connection = connection
+
+    def run(self):
+	""" Called when a thread is started on this object. """
+    	try:
+		while True:
+		    msg, serial = self._connection._read_message()
+		    self._connection._post_message(msg, serial)
+	except Exception, e:
+		self._connection._set_error(e)
 
 class Name(object):
+    """ A RAD ADR name class.
+
+        An object's name consists of a mandatory reverse-dotted
+        domain combined with a non-empty set of key-value pairs.
+    """
+
     def __init__(self, domain, kvs):
+        """
+        Create a domain object using the supplied domain, keys and
+        values.
+
+        Arguments:
+
+        string     domain, the Name's domain
+        string     dict formatted keys and values
+
+        Returns:
+
+        Name: A new Name
+        """
     	if domain:
 	    self._domain = domain
 	else:
@@ -173,11 +872,33 @@
 
     @staticmethod
     def quote(value):
+        """
+        Quote the supplied value.
+
+        Arguments:
+
+        string     value, the value to be quoted
+
+        Returns:
+
+        string: A Quoted string
+        """
 	return value.replace("\\", "\\S").replace("=",
 	     "\\E").replace(",", "\\C")
 
     @staticmethod
     def unquote(value):
+        """
+        Unquote the supplied value.
+
+        Arguments:
+
+        string     value, the quoted value to be unquoted
+
+        Returns:
+
+        string: An unquoted string
+        """
 	return value.replace("\\E", "=").replace("\\C",
 	     ",").replace("\\S", "\\")
 
@@ -187,6 +908,23 @@
 
     @staticmethod
     def parse(namestr):
+        """
+        Return a new Name by parsing the supplied string into its 
+        constituent domain and key/value pairs.
+
+        Format: <domain>:[<key>=<value>,]...[<key>=<value>]
+
+        If a badly formatted string is provded, then an Exception
+        will be raised.
+
+        Arguments:
+
+        string     namestr, the name we are parsing
+
+        Returns:
+
+        Name: A new Name instance
+        """
     	parts = namestr.split(":", 1)
 	if len(parts) < 2:
 		raise Exception("Bad name format: %s" % namestr)
@@ -206,6 +944,19 @@
 	return Name(domain, kvs)
 
     def match(self, name):
+        """
+        Return True if self and name match. The names match if both
+        domains are the same and if both Names have the same keys
+        with the same values.
+
+        Arguments:
+
+        Name     name, the name we are matching
+
+        Returns:
+
+        boolean: True if the names match, False otherwise
+        """
         if len(self._domain) > 0 and self._domain != name._domain:
 	    return False
 	for key, value in self._sortedkeys:
@@ -216,12 +967,40 @@
 	return True
 
     def get_domain(self):
+        """
+        Return the domain part of this Name.
+
+        Arguments:
+
+        Returns:
+
+        string: The domain of this name
+        """
 	return self._domain
 
     def get_value(self, key):
+        """
+        Return the value of the supplied key.
+
+        Arguments:
+
+        string   key, the key
+        Returns:
+
+        string: The value of the key
+        """
 	return self._keys[key]
 
     def num_keys(self):
+        """
+        Return the number of keys in this name.
+
+        Arguments:
+
+        Returns:
+
+        integer: The number of keys in this name
+        """
 	return len(self._sortedkeys)
 
     def __cmp__(self, other):
@@ -259,588 +1038,25 @@
 	return "%s:%s" % (self._domain, keystr)
 
     def __repr__(self):
+	""" A string representation of this instance. """
     	return "Name.parse(\"%s\")" % str(self)
 
-class RadField(object):
-    def __init__(self, unpacker, types):
-	self._name = unpacker.unpack_string()
-	self._nullable = unpacker.unpack_bool()
-	self._type = types.typeref(unpacker)
-
-class RadEnumVal(object):
-    def __init__(self, type, index, unpacker = None):
-	self._type = type
-	self._index = index
-	if unpacker:
-	    self._name = unpacker.unpack_string()
-	    self._value = unpacker.unpack_uint()
-	else:
-	    self._name = type._fallback
-
-    def __str__(self):
-	return self._name
-
-    def __repr__(self):
-	return "<%s.%s>" % (self._type._name, self._name)
-
-#
-# Superclass for synthetic structure objects
-#
-class RadData(object):
-    def __init__(self, type):
-	self._type = type
-
-    def __repr__(self):
-    	return "%s(%s)" % (self._type._name, ", ".join(map(
-	    lambda f: "%s = %r" % (f._name, self.__dict__[f._name]),
-	    self._type._fields.values())))
-
-#
-# Synthetic constructor for RadData instances
-#
-class RadDataConstructor(object):
-    def __init__(self, type):
-	self._type = type
-
-    def __call__(self, *pargs, **kargs):
-    	return self._type.make(pargs, kargs)
-
-#
-# Superclass for synthetic enumeration "types"
-#
-class RadEnum(object):
-    def __init__(self, type):
-	self._type = type
-	for v in type._pvalues:
-	    self.__dict__[v._name] = v
-	if type._fbvalue:
-	    self.__dict__[type._fallback] = type._fbvalue
-
-#
-# Superclass for synthetic union "types"
-#
-class RadUnion(object):
-    def __init__(self, type, arm, armvalue, value):
-    	if arm == None:
-	    raise Exception("%s: no arm for discriminant: %s" %
-		(type._name, str(armvalue)))
-
-	if value == None and arm != None and not arm._nullable and \
-	    arm._type._type != Type.VOID:
-
-	    raise Exception("%s: arm required for discriminant: %s" %
-		(type._name, str(armvalue)))
-
-	self._type = type
-	self._arm = arm
-	self.u_arm = self._armvalue = armvalue
-	self.u_val = value
-
-    def __repr__(self):
-    	return "%s(%s, %s)" % (self._type._name, self.u_arm, self.u_val)
-
-#
-# Synthetic constructor for RadUnion instances
-#
-class RadUnionConstructor(object):
-    def __init__(self, type):
-	self._type = type
-
-    def __call__(self, armvalue, value):
-	for arm in self._type._arms:
-	    if arm._value == armvalue:
-		return RadUnion(self._type, arm, armvalue, value)
-	return RadUnion(self._type, self._type._default, armvalue, value)
-
-def read_time(unpacker):
-    seconds = unpacker.unpack_hyper()
-    nanos = unpacker.unpack_int()
-    dt = datetime.datetime.utcfromtimestamp(seconds)
-    return dt + datetime.timedelta(microseconds=(nanos/1000))
-
-def write_time(packer, data):
-    naive = data.tzinfo == None or data.tzinfo.utcoffset(data) == None
-    if naive:
-	delta = data - datetime.datetime(1970, 1, 1)
-    else:
-	delta = data - datetime.datetime(1970, 1, 1, tzinfo=timezone.utc)
-    timestamp = delta / datetime.timedelta(microseconds=1)
-    packer.pack_hyper(timestamp / 1000000)
-    packer.pack_int((timestamp % 1000000) * 1000)
-
-#
-# Synthetic package that will contain RadEnums and RadDataConstructors
-#
-class RadTypeSpace(object):
-    def __init__(self, types):
-	self.__dict__.update(types)
-
-class RadType(object):
-    def __init__(self, type):
-	self._type = type
+class RadConnection(object):
+    """ A connection to a RAD instance. """
+    def __init__(self, socket, threaded=True, locale=None):
+        """
+        Create a RadConnection object.
 
-    def read(self, unpacker, nullable=False):
-	if nullable and not unpacker.unpack_bool(): return None
-	if self._type == Type.VOID:
-	    pass
-	elif self._type == Type.BOOLEAN:
-	    return unpacker.unpack_bool()
-	elif self._type == Type.INTEGER:
-	    return unpacker.unpack_int()
-	elif self._type == Type.STRING:
-	    return unpacker.unpack_string()
-	elif self._type == Type.OPAQUE:
-	    return unpacker.unpack_opaque()
-	elif self._type == Type.LONG:
-	    return unpacker.unpack_hyper()
-	elif self._type == Type.TIME:
-	    return read_time(unpacker)
-	elif self._type == Type.ULONG:
-	    return unpacker.unpack_uhyper()
-	elif self._type == Type.UINT:
-	    return unpacker.unpack_uint()
-	elif self._type == Type.NAME:
-	    return Name.parse(unpacker.unpack_string())
-	elif self._type == Type.SECRET:
-	    return unpacker.unpack_string()
-	elif self._type == Type.FLOAT:
-	    return unpacker.unpack_float()
-	elif self._type == Type.DOUBLE:
-	    return unpacker.unpack_double()
-
-    def write(self, packer, data, nullable=False):
-	if nullable:
-	    isdata = data != None
-	    packer.pack_bool(isdata)
-	    if not isdata: return
-	if self._type == Type.VOID:
-	    pass
-	elif self._type == Type.BOOLEAN:
-	    return packer.pack_bool(data)
-	elif self._type == Type.INTEGER:
-	    return packer.pack_int(data)
-	elif self._type == Type.STRING:
-	    return packer.pack_string(data)
-	elif self._type == Type.OPAQUE:
-	    return packer.pack_opaque(data)
-	elif self._type == Type.LONG:
-	    return packer.pack_hyper(data)
-	elif self._type == Type.TIME:
-	    write_time(packer, data)
-	elif self._type == Type.ULONG:
-	    return packer.pack_uhyper(data)
-	elif self._type == Type.UINT:
-	    return packer.pack_uint(data)
-	elif self._type == Type.NAME:
-	    return packer.pack_string(str(data))
-	elif self._type == Type.SECRET:
-	    return packer.pack_string(data)
-	elif self._type == Type.FLOAT:
-	    return packer.pack_float(data);
-	elif self._type == Type.DOUBLE:
-	    return packer.pack_double(data);
-
-class RadUnionArm(object):
-    def __init__(self, unpacker, types, index, value):
-	self._index = index
-	self._value = value
-	self._nullable = unpacker.unpack_bool()
-	self._type = types.typeref(unpacker)
-
-class RadDerivedType(RadType):
-    def __init__(self, unpacker, types):
-	RadType.__init__(self, unpacker.unpack_uint())
-	if self._type == Type.ARRAY:
-	    self._atype = types.typeref(unpacker)
-	elif self._type == Type.COMPOSITE:
-	    self._name = unpacker.unpack_string()
-	    self._pfields = unpacker.unpack_array(
-		lambda: RadField(unpacker, types))
-	    self._fields = dict([(i._name, i) for i in self._pfields])
-	    types._typedict[self._name] = self
-	    types._concrete[self._name] = RadDataConstructor(self)
-	elif self._type == Type.ENUM:
-	    self._name = unpacker.unpack_string()
-	    if unpacker.unpack_bool():
-		self._fallback = unpacker.unpack_string()
-	        self._fbvalue = RadEnumVal(self, 0)
-	    else:
-		self._fallback = self._fbvalue = None
-	    nvalues = unpacker.unpack_uint()
-	    self._pvalues = [ RadEnumVal(self, i + 1, unpacker)
-	        for i in range(nvalues) ]
-	    types._typedict[self._name] = self
-	    types._concrete[self._name] = RadEnum(self)
-	elif self._type == Type.UNION:
-	    self._name = unpacker.unpack_string()
-	    self._utype = types.typeref(unpacker)
-	    if unpacker.unpack_bool():
-	        self._default = RadUnionArm(unpacker, types, 0, None)
-	    else:
-		self._default = None
-	    self._narms = unpacker.unpack_uint();
-	    self._arms = [
-	        RadUnionArm(unpacker, types, i + 1, self._utype.read(unpacker))
-		for i in range(self._narms) ]
-	    types._typedict[self._name] = self
-	    types._concrete[self._name] = RadUnionConstructor(self)
-
-    def make(self, pargs, kargs):
-	if self._type != Type.COMPOSITE:
-	    raise Exeception("make() only invokable on composite types")
-
-	o = RadData(self)
-	n = len(pargs)
-	nfields = 0
-
-	if n > len(self._pfields):
-	    raise Exception("Too many fields specified for " + self._name)
-
-	for (i, field) in enumerate(self._pfields):
-	    if i < n:
-		value = pargs[i]
-		if field._name in kargs:
-		    raise Exception("Field '%s' of '%s' assigned twice" %
-		        (field._name, self._name))
-	    else:
-		value = kargs.get(field._name)
-		if field._name in kargs:
-		    nfields = nfields + 1
-
-	    if value == None and not field._nullable:
-		    raise Exception("Field '%s' of '%s' must be specified" %
-			(field._name, self._name))
-
-	    o.__dict__[field._name] = value
-
-	if len(kargs) > nfields:
-	    raise Exception("Unrecognized fields specified for " + self._name)
-
-	return o
-
-    def read(self, unpacker, nullable=False):
-	if nullable and not unpacker.unpack_bool(): return None
-	if self._type == Type.ARRAY:
-	    return unpacker.unpack_array(lambda: self._atype.read(unpacker))
-	elif self._type == Type.COMPOSITE:
-	    o = RadData(self)
-	    for i in self._pfields:
-		o.__dict__[i._name] = i._type.read(unpacker, i._nullable)
-	    return o
-	elif self._type == Type.ENUM:
-	    val = unpacker.unpack_int();
-	    if val > 0 and val <= len(self._pvalues):
-		return self._pvalues[val - 1]
-	    if val == 0 and self._fbvalue != None:
-		return self._fbvalue
-	    raise Exception("Bad enumeration value from server")
-	elif self._type == Type.UNION:
-	    index = unpacker.unpack_uint()
-	    if index > self._narms:
-		raise Exception("Bad union arm index from server")
-
-	    if index > 0:
-		arm = self._arms[index - 1]
-		armvalue = arm._value;
-	    else:
-	        arm = self._default
-		armvalue = self._utype.read(unpacker, False)
-		for a in self._arms:
-		    if a._value == armvalue:
-			raise Exception("Bad union discriminant from server")
-	    if arm == None:
-		raise Exception("Bad default arm reference from server")
+        Arguments:
 
-	    data = arm._type.read(unpacker, arm._nullable)
-	    return RadUnion(self, arm, armvalue, data)
-
-    def write(self, packer, data, nullable=False):
-	if nullable:
-	    isdata = data != None
-	    packer.pack_bool(isdata)
-	    if not isdata: return
-	if self._type == Type.ARRAY:
-	    packer.pack_array(data,
-		lambda x: self._atype.write(packer, x))
-	elif self._type == Type.COMPOSITE:
-	    for i in self._pfields:
-		if i._name in data.__dict__:
-		    i._type.write(packer, data.__dict__[i._name], i._nullable)
-		else:
-		    i._type.write(packer, None, i._nullable)
-	elif self._type == Type.ENUM:
-	    if not data._type == self:
-		raise Exception("Enumeration type mismatch: " +
-		    data._type._name)
-	    packer.pack_int(data._index)
-	elif self._type == Type.UNION:
-	    index = data._arm._index
-	    packer.pack_uint(index)
-	    if index == 0:
-		self._utype.write(packer, data._armvalue)
-	    data._arm._type.write(packer, data.u_val, data._arm._nullable)
-
-
-class RadTypeSet(object):
-    basetypes = [ RadType(x) if x in BASE else None for x in TYPES ]
-
-    def __init__(self, unpacker):
-	self._types = []
-	self._typedict = {}
-	self._concrete = {}
-	ntypes = unpacker.unpack_int();
-	for i in range(ntypes):
-	    self._types.insert(i, RadDerivedType(unpacker, self))
-
-    def typeref(self, unpacker):
-	type = unpacker.unpack_int();
-	if type in DERIVED:
-	    return self._types[unpacker.unpack_int()]
-	else:
-	    return RadTypeSet.basetypes[type]
-
-    def lookup(self, name):
-	return self._typedict[name]
-
-    def typespace(self):
-    	return RadTypeSpace(self._concrete)
-
-class RadAttribute(object):
-    def __init__(self, unpacker, types):
-	self._name = unpacker.unpack_string()
-	self._stability = unpacker.unpack_enum()
-	self._readable = unpacker.unpack_bool()
-	self._writable = unpacker.unpack_bool()
-	self._nullable = unpacker.unpack_bool()
-	self._type = types.typeref(unpacker)
-	if unpacker.unpack_bool():
-		self._read_error = types.typeref(unpacker)
-	else:
-		self._read_error = None
-	if unpacker.unpack_bool():
-		self._write_error = types.typeref(unpacker)
-	else:
-		self._write_error = None
-
-    def read(self, instance):
-	if not self._readable:
-	    raise InvalidFeatureError(self._name,
-	        'Attribute %s of %s isn\'t readable' %
-		(self._name, instance._name))
-
-	p = xdrlib.Packer()
-	p.pack_hyper(instance._id)
-	p.pack_string(self._name)
-	conn = instance._connection
-	ser = conn.make_request(Op.GETATTR, p.get_buffer())
-
-	try:
-	    return self._type.read(conn.read_response(ser, None), True)
-	except RequestError, ex:
-	    if ex._error == 1:
-	    	raise ObjectError("Object-specific error", ex, self._read_error)
-	    raise_error(ex, 'Error getting %s from %s: %d' %
-		(self._name, instance._name, ex._error))
-
-    def write(self, instance, value):
-	if not self._writable:
-	    raise InvalidFeatureError(self._name,
-	        'Attribute %s of %s isn\'t writable' %
-		(self._name, instance._name))
-
-	p = xdrlib.Packer()
-	p.pack_hyper(instance._id)
-	p.pack_string(self._name)
-	data = xdrlib.Packer()
-	self._type.write(data, value, True)
-	p.pack_opaque(data.get_buffer())
-	conn = instance._connection
-	ser = conn.make_request(Op.SETATTR, p.get_buffer())
-
-	try:
-	    conn.read_response(ser, None)
-	except RequestError, ex:
-	    if ex._error == 1:
-		raise ObjectError("Object-specific error", ex,
-		    self._write_error)
-	    raise_error(ex, 'Error setting %s on %s: %d' %
-		(self._name, instance._name, ex._error))
-
-
-class RadArg(object):
-    def __init__(self, unpacker, types):
-	self._name = unpacker.unpack_string()
-	self._nullable = unpacker.unpack_bool()
-	self._type = types.typeref(unpacker)
-
-class RadMethod(object):
-    def __init__(self, unpacker, types):
-	self._name = unpacker.unpack_string()
-	self._stability = unpacker.unpack_enum()
-	self._nullable = unpacker.unpack_bool()
-	self._type = types.typeref(unpacker)
-	if unpacker.unpack_bool():
-		self._error = types.typeref(unpacker)
-	else:
-		self._error = None
-	self._args = unpacker.unpack_array(lambda : RadArg(unpacker, types))
-
-    def call(self, instance, *args):
-	if len(self._args) != len(args):
-	    raise InvalidFeatureError(self._name,
-		"%s called with invalid # of args (received %d, expected %d)" %
-		(self._name, len(args), len(self._args)))
+        socket   socket, Used for communication with a RAD instance
+        boolean  threaded, should this instance create communication
+                 threads
+        string   locale, locale to use for this connection
+        Returns:
+        RadConnection
 
-	p = xdrlib.Packer()
-	p.pack_hyper(instance._id)
-	p.pack_string(self._name)
-	p.pack_uint(len(args))
-	for i in range(len(args)):
-	    pp = xdrlib.Packer()
-	    self._args[i]._type.write(pp, args[i], True)
-	    p.pack_opaque(pp.get_buffer())
-	conn = instance._connection
-	ser = conn.make_request(Op.INVOKE, p.get_buffer())
-
-	try:
-	    return self._type.read(conn.read_response(ser, None), True)
-	except RequestError, ex:
-	    if ex._error == 1:
-	    	raise ObjectError("Object-specific error", ex, self._error)
-	    raise_error(ex, 'Error invoking %s on %s: %d' %
-		(self._name, instance._name, ex._error))
-
-class RadObjectMethod(object):
-    def __init__(self, method, instance):
-	self._name = method._name
-	self._method = method
-	self._instance = instance
-
-    def call(self, *args):
-	return self._method.call(self._instance, *args)
-
-class RadEventType(object):
-    def __init__(self, unpacker, types):
-	self._name = unpacker.unpack_string()
-	self._stability = unpacker.unpack_enum()
-	self._type = types.typeref(unpacker)
-
-    def read(self, instance):
-	up = xdrlib.Unpacker(instance._payload)
-	return self._type.read(up, True)
-
-class RadApiVersion(object):
-    def __init__(self, unpacker):
-        stabilities = 'undefined', 'private', 'uncommitted', 'committed'
-        self._stability = stabilities[unpacker.unpack_enum()]
-        self._major = unpacker.unpack_int()
-        self._minor = unpacker.unpack_int()
-
-class RadApi(object):
-    def __init__(self, unpacker):
-	self._versions = []
-	for i in range(3):
-	    self._versions.append(RadApiVersion(unpacker))
-	
-class RadObjectType(object):
-    def __init__(self, connection, id, unpacker):
-	self._connection = connection
-	self._id = id
-	self._apis = {}
-	self._iface = unpacker.unpack_string()
-	napis = unpacker.unpack_int()
-	for i in range(napis):
-	    aname = unpacker.unpack_string()
-	    self._apis[aname] = RadApi(unpacker)
-	self._typeset = RadTypeSet(unpacker)
-	self._attributes = dict([[i._name, i] for i in unpacker.unpack_array(
-	    lambda : RadAttribute(unpacker, self._typeset))])
-	self._methods = unpacker.unpack_array(
-	    lambda : RadMethod(unpacker, self._typeset))
-	self._events = dict([[i._name, i] for i in unpacker.unpack_array(
-	    lambda : RadEventType(unpacker, self._typeset))])
-
-	self.types = self._typeset.typespace()
-
-    def read(self, instance, attr):
-	try:
-	    return self._attributes[attr].read(instance)
-	except KeyError:
-	    raise InvalidFeatureError(instance._name,
-		"%s has no attribute %s" % (instance._name, attr))
-
-    def read_event(self):
-	instance = self._connection.read_event()
-	try:
-		return self._events[instance._event].read(instance)
-	except KeyError:
-		raise InvalidFeatureError(self._iface,
-		    "%s has no event %s" % (self._iface, instance._event))
-
-    def write(self, instance, attr, value):
-	try:
-	    self._attributes[attr].write(instance, value)
-	except KeyError:
-	    raise InvalidFeatureError(instance._name,
-		"%s has no attribute %s" % (instance._name, attr))
-
-    def call(self, instance, meth, *args):
-	return self._methods[meth].call(*args)
-
-    def __repr__(self):
-	return "< Remote RAD type: %s >" % self._iface
-
-class RadObject(object):
-    def __init__(self, connection, name, unpacker):
-	self._connection = connection
-	self._name = name
-	self._id = unpacker.unpack_hyper()
-	self._typeid = unpacker.unpack_hyper()
-	if unpacker.unpack_bool():
-	    self._type = connection.remember_type(self._typeid, unpacker, False)
-	else:
-	    self._type = connection.get_type(self._typeid)
-	self._methods = dict([[i._name, RadObjectMethod(i, self)]
-	    for i in self._type._methods])
-
-	self.types = self._type.types
-
-    def read(self, attr):
-	return self._type.read(self, attr)
-
-    def write(self, attr, value):
-	self._type.write(self, attr, value)
-
-    def call(self, meth, *args):
-    	return self._methods[meth].call(*args)
-
-    def __repr__(self):
-        return "< Remote RAD object: %s >" % self._name
-
-class RadEvent(object):
-    def __init__(self, unpacker):
-	self._source = unpacker.unpack_hyper()
-	self._sequence = unpacker.unpack_hyper()
-	self._tstamp = read_time(unpacker)
-	self._event = unpacker.unpack_string()
-	self._payload = unpacker.unpack_opaque()
-
-class RadReader(threading.Thread):
-    def __init__(self, connection):
-	threading.Thread.__init__(self)
-	self.daemon = True
-    	self._connection = connection
-
-    def run(self):
-    	try:
-		while True:
-		    msg, serial = self._connection.read_message()
-		    self._connection.post_message(msg, serial)
-	except Exception, e:
-		self._connection.set_error(e)
-    	
-class RadConnection(object):
-    def __init__(self, socket, threaded=True, locale=None):
+        """
     	self._wlock = threading.Lock()
     	self._rlock = threading.Lock()
     	self._tlock = threading.Lock()
@@ -854,6 +1070,7 @@
 	self._errors = [ None, None ]	# no error and object-specific error
 	self._rs = recordmarking.RecordMarkingSocket(socket)
 	self._reader = None
+	self._klasses = { }
 
 	if locale == None:
 	    dloc = oslocale.getdefaultlocale()
@@ -878,22 +1095,40 @@
 	self._rs.skip_record()
 	data = self._rs.read_record()
 	errors = xdrlib.Unpacker(data)
-	typeset = RadTypeSet(errors)
+	typeset = _RadTypeSet(errors)
 	self._errors.extend(errors.unpack_array(
 	    lambda: typeset.typeref(errors)))
 
 	self._serial = 1
 
 	if threaded:
-	    self.start_threads()
+	    self._start_threads()
+
+    def __enter__(self):
+	""" Implement context manager protocol for this class. """
+        return self
 
-    def start_threads(self):
+    def __exit__(self, type, value, tb):
+	""" Implement context manager protocol for this class. """
+        self.close()
+        return False
+
+    def __repr__(self):
+	""" A string representation of this instance. """
+	state = "open"
+	if self._closed is not None:
+		state = "closed"
+        return "<%s RADConnection >" % state
+
+    def _start_threads(self):
+	""" Start our reader thread. """
     	with self._tlock:
 	    if not self._reader:
-		self._reader = RadReader(self)
+		self._reader = _RadReader(self)
 		self._reader.start()
 
-    def set_error(self, e):
+    def _set_error(self, e):
+	""" Set our closed error state. """
     	with self._rlock:
 	    if self._closed:
 		return
@@ -901,17 +1136,22 @@
 	    self._econd.notifyAll()
 	    self._rcond.notifyAll()
 
-    def wait_until_closed(self, cond):
+    def _wait_until_closed(self, cond):
+	""" Wait until the supplied condition closes. """
 	if self._closed:
 	    raise IOError, self._closed
 	cond.wait()
 
-    def read_message(self):
+    def _read_message(self):
+	""" Read a RAD protocol message. """
         self._rs.skip_record()
 	up = xdrlib.Unpacker(self._rs.read_record())
 	return up, up.unpack_hyper()
 
-    def post_message(self, up, serial):
+    def _post_message(self, up, serial):
+	""" Post a RAD protocol message, supplied in up. If serial
+	    is 0, then we are posting the message to the server, 
+	    otherwise it is an event response from the server. """
 	with self._rlock:
 	    if serial == 0:
 		self._events.append(RadEvent(up))
@@ -920,31 +1160,38 @@
 		self._responses[serial] = up
 		self._rcond.notifyAll()
 
-    def unpack_message(self, up):
+    def _unpack_message(self, up):
+	""" Unpack a RAD protocol message, supplied in up. """
         error = up.unpack_int()
         payload = up.unpack_opaque()
-	if error == Error.OK:
+	if error == _Error.OK:
 	    up.reset(payload)
 	    return up
 	else:
-	    raise RequestError(error, payload)
+	    raise _RequestError(error, payload)
 
-    def read_response(self, reqserial, etype):
+    def _read_response(self, reqserial, etype):
+	""" Read a RAD protocol response and return the unpacked
+	    message. If the reqserial is specified, ensure the serial
+	    number from the message matches."""
         with self._tlock:
 	    if not self._reader:
-	    	up, serial = self.read_message()
+	    	up, serial = self._read_message()
 		if serial != reqserial:
 		    raise Exception('Bad response (serial %d, expected %d)' %
 			(serial, reqserial))
-	    	return self.unpack_message(up)
+	    	return self._unpack_message(up)
 
 	with self._rlock:
 	    while not reqserial in self._responses:
-	        self.wait_until_closed(self._rcond)
+	        self._wait_until_closed(self._rcond)
 	    up = self._responses.pop(reqserial)
-	    return self.unpack_message(up)
+	    return self._unpack_message(up)
 
-    def make_request(self, op, buffer):
+    def _make_request(self, op, buffer):
+	""" Write a RAD protocol request and return the allocated
+	    serial number. The operation and buffer are packed
+	    before transmission."""
     	with self._wlock:
 	    serial = self._serial
 	    p = xdrlib.Packer()
@@ -955,81 +1202,274 @@
 	    self._rs.write(p.get_buffer(), True)
 	    return serial
 
-    def list_objects(self, pattern = None):
-	p = xdrlib.Packer()
-	if pattern:
-		p.pack_string(str(pattern))
-	else:
-		p.pack_string('')
-	ser = self.make_request(Op.LIST, p.get_buffer())
-	up = self.read_response(ser, None)
-	return [ Name.parse(i) for i in up.unpack_array(up.unpack_string) ]
-
-    def remember_type(self, id, unpacker, force):
-	with self._typelock:
-	    # Only replace if necessary or requested to avoid
-	    # proliferation of identical types
-	    if force or not id in self._types:
-		result = RadObjectType(self, id, unpacker)
-		self._types[id] = result
-	    else:
-		result = self._types[id]
-	return result
-
-    def get_type(self, id, force = False):
+    def _get_type(self, id, force = False):
+	""" Get the definition of the type. """
 	with self._typelock:
 	    result = self._types.get(id)
 	if force or result == None:
 	    p = xdrlib.Packer()
 	    p.pack_hyper(id)
-	    ser = self.make_request(Op.DEFINE, p.get_buffer())
+	    ser = self._make_request(_Op.DEFINE, p.get_buffer())
 	    try:
-		    up = self.read_response(ser, None)
-	    except RequestError, ex:
-		    raise_error(ex)
-	    result = self.remember_type(id, up, force)
+		    up = self._read_response(ser, None)
+	    except _RequestError, ex:
+		    _raise_error(ex)
+	    result = self._remember_type(id, up, force)
+	return result
+
+    def _remember_type(self, id, unpacker, force):
+	""" Remember this type in the local cache. """
+	with self._typelock:
+	    # Only replace if necessary or requested to avoid
+	    # proliferation of identical types
+	    if force or not id in self._types:
+		result = _RadObjectType(self, id, unpacker)
+		self._types[id] = result
+	    else:
+		result = self._types[id]
 	return result
 
+    def list_objects(self, pattern = None):
+        """
+        List all the objects on the server which match the supplied
+        pattern. If no pattern is supplied, all server objects will
+        be matched.
+
+        Arguments:
+
+        pattern  Name, a RAD ADR name
+
+        Returns:
+
+        List[Name]: A list of RAD Name objects
+        """
+	p = xdrlib.Packer()
+	if pattern:
+		p.pack_string(str(pattern))
+	else:
+		p.pack_string('')
+	ser = self._make_request(_Op.LIST, p.get_buffer())
+	up = self._read_response(ser, None)
+	return [ Name.parse(i) for i in up.unpack_array(up.unpack_string) ]
+
     def get_object(self, name):
+        """
+        Return a RadObject which is identified by this name.
+
+        Arguments:
+
+        name     Name, a RAD ADR name
+
+        Returns:
+
+        RadObject: A RAD object.
+        """
 	p = xdrlib.Packer()
 	p.pack_string(str(name))
 	p.pack_bool(False)
-	ser = self.make_request(Op.LOOKUP, p.get_buffer())
+	ser = self._make_request(_Op.LOOKUP, p.get_buffer())
 	try:
-		up = self.read_response(ser, None)
-	except RequestError, ex:
-		raise_error(ex)
-	return RadObject(self, name, up)
+		up = self._read_response(ser, None)
+	except _RequestError, ex:
+		_raise_error(ex)
+	# Read the id and the typeid so that we can examine our cache
+	id = up.unpack_hyper()
+	typeid = up.unpack_hyper()
+	klass_name = "RadBuilder_%d" % typeid
+        try:
+                klass = self._klasses[klass_name]
+        except KeyError as e:
+                # Define the class
+                klass = type(klass_name, (_RadObject,), {})
+                # Cache this
+                self._klasses[klass_name] = klass
+
+	return klass(self, name, up, id, typeid)
 
     def get_object_s(self, domain, keys):
+        """
+        Return a RadObject which is identified by this domain and set
+        of keys.
+
+        Arguments:
+
+        domain   string, a RAD ADR Domain name
+        keys     List[string], a list of RAD ADR keys
+
+        Returns:
+
+        RadObject: A RAD object.
+        """
 	return self.get_object(Name(domain, keys))
 
     def subscribe(self, object, event):
+        """
+        Subscribe to this object's event notifications.
+
+        Arguments:
+
+        object   rad.client.RadObject, a RAD interface
+        event    string, name of the event
+
+        Returns:
+
+        """
 	p = xdrlib.Packer()
-	p.pack_hyper(object._id)
+	p.pack_hyper(object._object._id)
 	p.pack_string(event)
-	ser = self.make_request(Op.SUB, p.get_buffer())
+	ser = self._make_request(_Op.SUB, p.get_buffer())
 	try:
-		self.read_response(ser, None)
-	except RequestError, ex:
-		raise_error(ex)
+		self._read_response(ser, None)
+	except _RequestError, ex:
+		_raise_error(ex)
 
     def unsubscribe(self, object, event):
+        """
+        Unsubscribe from this object's event notifications.
+
+        Arguments:
+
+        object   rad.client.RadObject, a RAD interface
+        event    string, name of the event
+
+        Returns:
+
+        """
 	p = xdrlib.Packer()
-	p.pack_hyper(object._id)
+	p.pack_hyper(object._object._id)
 	p.pack_string(event)
-	ser = self.make_request(Op.UNSUB, p.get_buffer())
+	ser = self._make_request(_Op.UNSUB, p.get_buffer())
 	try:
-		self.read_response(ser, None)
-	except RequestError, ex:
-		raise_error(ex)
+		self._read_response(ser, None)
+	except _RequestError, ex:
+		_raise_error(ex)
 
     def read_event(self):
+        """
+        Perform a blocking read for an event.
+
+        Arguments:
+
+        Returns:
+
+        RadEvent: A RAD event.
+        """
     	with self._rlock:
 	    while len(self._events) == 0:
-	        self.wait_until_closed(self._econd)
+	        self._wait_until_closed(self._econd)
 	    return self._events.pop(0)
 
     def close(self):
-        self.set_error(IOError("close() called"))
+        """
+        Close this connection.
+
+        Arguments:
+
+        Returns:
+
+        """
+        self._set_error(IOError("close() called"))
         self._rs.close()
+
+class RadEvent(object):
+    """ A RAD event instance.
+
+    source    _Type.LONG   id of generating object
+    sequence  _Type.LONG   sequence number of event
+    tstamp    _Type.ULONG  time of event
+    event     string       event name
+    payload   _Type.OPAQUE event payload
+    """
+    def __init__(self, unpacker):
+        """
+        Create a RadEvent object.
+
+        Arguments:
+        Unpacker unpacker, event unpacker
+        Returns:
+
+        RadEvent:
+        """
+	self.source = unpacker.unpack_hyper()
+	self.sequence = unpacker.unpack_hyper()
+	self.tstamp = _read_time(unpacker)
+	self.event = unpacker.unpack_string()
+	self.payload = unpacker.unpack_opaque()
+
+def get_events(obj):
+    """
+    Get the events associated with the supplied object.
+
+    Arguments:
+
+    obj      RadObject, a RAD interface object
+
+    Returns:
+
+    List[string]: A list of object events which may be subscribed to
+    """
+    return obj._type._events
+
+def get_types(obj):
+    """
+    Get the types associated with the supplied object.
+
+    Arguments:
+
+    obj      RadObject, a RAD interface object
+
+    Returns:
+
+    _RadTypeSpace: A container for Rad Types and Enums
+    """
+    return obj.types
+
+# Should only be used when there is a mismatch, but is currently used
+# as a catch-all.  Fix.
+
+class InvalidFeatureError(Exception):
+    """ An exception class used to indicate RAD errors. """
+    def __init__(self, name, msg = None):
+        """
+        Create an InvalidFeatureError object.
+
+        Arguments:
+
+        string   name
+        string   msg
+        Returns:
+
+        InvalidFeatureError:
+        """
+    	self._name = name
+	self._msg = msg
+
+    def __str__(self):
+	return self.get_message()
+
+    def get_name(self):
+        """
+        Return this instance's name.
+
+        Arguments:
+
+        Returns:
+
+        string: name
+        """
+    	return self._name
+
+    def get_message(self):
+        """
+        Return this instance's message.
+
+        Arguments:
+
+        Returns:
+
+        string: message
+        """
+
+    	if self._msg: return self._msg
+	return 'Feature not found: ' + self._name
+
--- a/usr/src/lib/pyrad/recordmarking.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/lib/pyrad/recordmarking.py	Fri May 04 10:14:24 2012 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 import xdrlib
@@ -34,6 +34,13 @@
 	self._atlast = True
 	self._eof = False
 
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, tb):
+	self.close()
+        return False
+
     def really_read(self, n):
 	""" Internal: read n bytes or else (mark EOF) """
 	alldata = ''
@@ -111,5 +118,5 @@
 	self._socket.sendall(p.get_buffer())
 
     def close(self):
-	""" Close the socket """
+        """ Close the socket """
 	self._socket.close()
--- a/usr/src/lib/pyrad/util.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/lib/pyrad/util.py	Fri May 04 10:14:24 2012 -0700
@@ -23,30 +23,45 @@
 # Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
+"""util - RAD connection oriented utilities
+
+This module facilitates communication with RAD instances via a number of
+alternative transports.
+
+"""
 import socket
 import ssl
 import getpass
 import subprocess
 import os
 import rad.client as rad
-import rad.adaptor as adapt
 
 #
 # Paths for authenticated/unauthenticated AF_UNIX socket
 #
 RAD_PATH_AFUNIX_AUTH = "/system/volatile/rad/radsocket"
 RAD_PATH_AFUNIX_UNAUTH = "/system/volatile/rad/radsocket-unauth"
-RAD_PORT_SSL = 12302
+RAD_PORT_TLS = 12302
 
 #
 # Make pipes quack enough like a socket to satisfy RecordMarkingSocket
 #
 class ProcessPseudoSocket(object):
+    """ A class which implements a sufficient amount of the socket.socket
+        interface to allow a pipe to communicate like a
+        rad.recordmarking.RecordMarkingSocket. """
     def __init__(self, process):
 	self._process = process
 	self._in = process.stdin
 	self._out = process.stdout
 
+    def __enter__(self):
+	return self
+
+    def __exit__(self, type, value, tb):
+	self.close()
+	return False
+
     def recv(self, n):
 	#
 	# If the file is unbuffered, it reads one byte at a time.
@@ -74,11 +89,21 @@
 # Make a zonesbridge.IO object quack enough like a socket to satisfy
 # RecordMarkingSocket
 #
-class ZonesBridgePseudoSocket(object):
+class _ZonesBridgePseudoSocket(object):
+    """ A class which implements a sufficient amount of the socket.socket
+        interface to allow a zonesbridge.IO object communicate like a
+        rad.recordmarking.RecordMarkingSocket. """
     def __init__(self, zio, zone, user = None):
 	self._zio = zio
 	self._token = zio.openRad(zone, user)
 
+    def __enter__(self):
+	return self
+
+    def __exit__(self, type, value, tb):
+	self.close()
+	return False
+
     def recv(self, n):
 	return self._zio.read(self._token, n)
 
@@ -91,7 +116,7 @@
 #
 # Map a path given the specified root directory
 #
-def map_path(root, path):
+def _map_path(root, path):
     if root is not None and path[0] == '/':
 	return root + path;
     return path
@@ -100,16 +125,33 @@
 # build the rad commandline command with the given options.
 #
 def build_rad_cmd(modules = None, debug = False, root = None, auxargs = None):
-    cmd = [map_path(root, "/usr/lib/rad/rad"),
-	"-M", map_path(root, "/usr/lib/rad/transport/mod_xport_pipe.so"),
-	"-M", map_path(root, "/usr/lib/rad/protocol/mod_proto_rad.so")]
+    """
+    Get a List[string] suitable to use when spawning a RAD process
+    via subprocess.Popen().
+
+    Arguments:
+
+    modules  List[string], a list of modules to load
+    debug    boolean, run the spawned RAD process in debug mode
+    root     string, root directory to use for the spawned RAD
+             process
+    auxargs  List[string], additional argument to supply to the
+             spawned RAD process
+
+    Returns:
+
+    List[string]: A list containing a command plus arguments
+    """
+    cmd = [_map_path(root, "/usr/lib/rad/rad"),
+	"-M", _map_path(root, "/usr/lib/rad/transport/mod_xport_pipe.so"),
+	"-M", _map_path(root, "/usr/lib/rad/protocol/mod_proto_rad.so")]
 
     if modules is not None:
 	for module in modules:
-	    cmd.extend(["-M", map_path(root, module)])
+	    cmd.extend(["-M", _map_path(root, module)])
     else:
-	cmd.extend(["-m", map_path(root, "/usr/lib/rad/module"),
-	    "-m", map_path(root, "/usr/lib/rad/site-modules")])
+	cmd.extend(["-m", _map_path(root, "/usr/lib/rad/module"),
+	    "-m", _map_path(root, "/usr/lib/rad/site-modules")])
 
     if debug:
 	cmd.extend(["-d"])
@@ -120,61 +162,203 @@
     cmd.extend(["-t", "stdin:exit"])
     return cmd
 
+
 #
 # Connect to a privately spawned copy of rad
 # Defaults to loading all system modules if a list of modules isn't provided
 #
-def connect_private(modules = None, debug = False, env = None, root = None,
-    auxargs = None, locale = None):
+def _get_private_transport(modules = None, debug = False, env = None,
+    root = None, auxargs = None):
+    """
+    Get a transport suitable for connecting to a privately spawned
+    RAD process.
+
+    Arguments:
+
+    modules  List[string], a list of modules to load
+    debug    boolean, run the spawned RAD process in debug mode
+    env      Dictionary[string, string], environment for the
+             spawned RAD process
+    root     string, root directory to use for the spawned RAD
+             process
+    auxargs  List[string], additional argument to supply to the
+             spawned RAD process
+
+    Returns:
+
+    ProcessPseudoSocket: a "socket" for a spawned RAD process
+    """
     cmd = build_rad_cmd(modules = modules, debug = debug, root = root,
 	auxargs = auxargs)
     p = subprocess.Popen(cmd, 0, None, subprocess.PIPE, subprocess.PIPE,
 	env = env)
-    return rad.RadConnection(ProcessPseudoSocket(p), locale = locale)
+    return ProcessPseudoSocket(p)
+
+#
+# Use _get_private_transport() to return a RADConnection
+#
+def connect_private(modules = None, debug = False, env = None, root = None,
+    auxargs = None, locale = None):
+    """
+    Connect to a privately spawned instance of RAD using a pipe.
+
+    Arguments:
+
+    modules  List[string], a list of modules to load
+    debug    boolean, run the spawned RAD process in debug mode
+    env      Dictionary[string, string], environment for the
+             spawned RAD process
+    root     string, root directory to use for the spawned RAD
+             process
+    auxargs  List[string], additional argument to supply to the
+             spawned RAD process
+    locale   string, locale
+
+    Returns:
+
+    rad.client.RadConnection: a connection to RAD
+    """
+    p = _get_private_transport(modules, debug, env, root, auxargs)
+    return rad.RadConnection(p, locale = locale)
 
 #
 # Connect to the local rad daemon via the standard unix domain socket
 #
-def connect_local(path = RAD_PATH_AFUNIX_AUTH, locale = None):
+def _get_unix_transport(path = RAD_PATH_AFUNIX_AUTH):
+    """
+    Get a transport suitable for connecting to a local RAD instance.
+
+    Arguments:
+
+    path     string, path to the socket
+
+    Returns:
+
+    socket.socket: a Unix Domain(AF_UNIX) socket
+    """
     s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM);
     s.connect(path)
+    return s
+
+#
+# Use _get_unix_transport() to return a RADConnection
+#
+def connect_unix(path = RAD_PATH_AFUNIX_AUTH, locale = None):
+    """
+    Connect to a RAD instance over a Unix Domain Socket.
+
+    Arguments:
+
+    path     string, path to the socket
+    locale   string, locale
+
+    Returns:
+
+    rad.client.RadConnection: a connection to RAD
+    """
+    """ Get a UnixDomainSocket based RadConnection to RAD on
+        the local host at path. """
+    s = _get_unix_transport(path)
     return rad.RadConnection(s, locale = locale)
 
 #
 # Connect to a remote rad daemon at the standard port
 #
-def connect_ssl(host, port = RAD_PORT_SSL, locale = None):
+def _get_tls_transport(host, port = RAD_PORT_TLS):
+    """
+    Get a TLS transport suitable for connecting to a remote host.
+
+    Arguments:
+
+    host     string, target host
+    port     int, target port
+
+    Returns:
+
+    ssl.SSLSocket: a TLS based socket
+    """
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
     s.connect((host, port))
-    s = ssl.wrap_socket(s)
+    return ssl.wrap_socket(s)
+
+#
+# Use _get_tls_transport() to return a RADConnection
+#
+def connect_tls(host, port = RAD_PORT_TLS, locale = None):
+    """
+    Connect to a RAD instance over TLS.
+
+    Arguments:
+
+    host     string, target host
+    port     int, target port
+    locale   string, locale
+
+    Returns:
+
+    rad.client.RadConnection: a connection to RAD
+    """
+    s = _get_tls_transport(host, port)
     return rad.RadConnection(s, locale = locale)
 
 #
 # Connect to a non-global zone's local (unix domain socket) rad daemon, through
 # an established rad connection to its global zone.
 #
-def connect_zone(rc, zone, user = None, locale = None):
+def _get_zone_transport(rc, zone, user = None):
+    """
+    Get a transport suitable for connecting to a local zone.
+
+    Arguments:
+
+    rc       rad.client.RadConnection, Connection to a global zone
+    zone     string, Name of a local zone
+    user     string, user name
+
+    Returns:
+
+    _ZonesBridgePseudoSocket: a "socket" for a local zone
+    """
     # Retrieve the zonesbridge.IO object
     zio_name = rad.Name("com.oracle.solaris.rad.zonesbridge",
 	[("type", "IO")])
-    zio_obj = rc.get_object(zio_name)
+    # Get a native-looking python object that throws RAD exceptions
+    zio = rc.get_object(zio_name)
+
+    return _ZonesBridgePseudoSocket(zio, zone, user)
+
+#
+# Use _get_zone_transport() to return a RADConnection
+#
+def connect_zone(rc, zone, user = None, locale = None):
+    """
+    Connect to a RAD instance in a local zone.
 
-    # Make a native-looking python object that throws RAD exceptions
-    zio = adapt.RawAdaptor(zio_obj)
+    Arguments:
+
+    rc       rad.client.RadConnection, Connection to a global zone
+    zone     string, Name of a local zone
+    user     string, user name
+    locale   string, locale
 
-    return rad.RadConnection(ZonesBridgePseudoSocket(zio, zone, user),
-	locale = locale)
+    Returns:
+
+    rad.client.RadConnection: a connection to RAD
+    """
+    s = _get_zone_transport(rc, zone, user)
+    return rad.RadConnection(s, locale = locale)
 
 #
 # Fetches and caches a handle to the authentication object.
 # Supplies some convenience routines built on top of it.
 #
 class RadAuth(object):
+    """ Authentication utility class. """
     AUTH_NAME = rad.Name("com.oracle.solaris.rad.pam",
 	[("type", "Authentication")])
 
     def __init__(self, rc):
-	self._auth = adapt.Adaptor(rc.get_object(self.AUTH_NAME))
+	self._auth = rc.get_object(self.AUTH_NAME)
 
     def handle(self):
 	return self._auth
@@ -184,10 +368,20 @@
     # Currently not recommended due to bug in Python's getpass.getpass()
     #
     def pam_login(self, user = None):
+        """
+        Perform a terminal-interactive PAM login.
+    
+        Arguments:
+    
+        user     string, user name
+    
+        Returns:
+    
+        """
 	if not user:
 	    user = raw_input("Username: ")
 	blk = self._auth.login("C", user);
-	types = self._auth._object.types
+	types = rad.get_types(self._auth)
 	BlockType = types.BlockType
 	MsgType = types.MsgType
 	while True:
--- a/usr/src/lib/pysmf/rad.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/lib/pysmf/rad.py	Fri May 04 10:14:24 2012 -0700
@@ -27,7 +27,6 @@
 
 from __future__ import absolute_import
 import rad.client as client
-import rad.adaptor as adaptor
 import rad.util as util
 import threading
 import smf.fmri
@@ -52,7 +51,7 @@
 
     def __init__(self, conn = None):
 	if conn is None:
-	    self._rc = util.connect_local()
+	    self._rc = util.connect_unix()
 	else:
 	    self._rc = conn
 
@@ -102,7 +101,7 @@
 
     def lookup_byname(self, name):
 	""" Look up a service/instance object by rad.client.Name """
-	return adaptor.RawAdaptor(self._rc.get_object(name))
+	return self._rc.get_object(name)
 
     def lookup(self, fmri):
 	""" Look up a service/instance object by FMRI object """
--- a/usr/src/pkg/manifests/system-management-rad-client-rad-python.p5m	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/pkg/manifests/system-management-rad-client-rad-python.p5m	Fri May 04 10:14:24 2012 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 license cr_Oracle license=cr_Oracle
@@ -36,8 +36,6 @@
 dir path=usr/lib/python2.6/vendor-packages/rad
 file path=usr/lib/python2.6/vendor-packages/rad/__init__.py
 file path=usr/lib/python2.6/vendor-packages/rad/__init__.pyc
-file path=usr/lib/python2.6/vendor-packages/rad/adaptor.py
-file path=usr/lib/python2.6/vendor-packages/rad/adaptor.pyc
 file path=usr/lib/python2.6/vendor-packages/rad/client.py
 file path=usr/lib/python2.6/vendor-packages/rad/client.pyc
 file path=usr/lib/python2.6/vendor-packages/rad/recordmarking.py
--- a/usr/src/test/python/client/test_addremove.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/test/python/client/test_addremove.py	Fri May 04 10:14:24 2012 -0700
@@ -21,11 +21,10 @@
 #
 
 #
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 import rad.client as rad
-import rad.adaptor as adapt
 import common.tests as tests
 
 class AddRemoveTest(tests.RADTestObject):
@@ -49,7 +48,7 @@
 		""" new objects appear in LIST results """
 
 		objects_before = self._rc.list_objects()
-		rval = self._wobj.addOne()
+		rval = self._obj.addOne()
 		objects_after = self._rc.list_objects()
 
 		if rval in objects_before:
@@ -61,9 +60,8 @@
 	def test_use_new_object(self):
 		""" new objects are referenceable """
 
-		rval = self._wobj.addOne()
-		nobj = self._rc.get_object(rval)
-		aobj = adapt.RawAdaptor(nobj)
+		rval = self._obj.addOne()
+		aobj = self._rc.get_object(rval)
 
 		if aobj.tickle() != self.text:
 			self.fail("New object failed to respond correctly")
@@ -71,10 +69,9 @@
 	def test_remove_object(self):
 		""" after removing object, it disappears from LIST  """
 
-		rval = self._wobj.addOne()
+		rval = self._obj.addOne()
 		objects_before = self._rc.list_objects()
-		nobj = self._rc.get_object(rval)
-		aobj = adapt.RawAdaptor(nobj)
+		aobj = self._rc.get_object(rval)
 		aobj.remove()
 		objects_after = self._rc.list_objects()
 
@@ -87,22 +84,20 @@
 	def test_use_removed_object(self):
 		""" after removing object, name isn't referenceable """
 
-		rval = self._wobj.addOne()
-		nobj = self._rc.get_object(rval)
-		aobj = adapt.RawAdaptor(nobj)
+		rval = self._obj.addOne()
+		aobj = self._rc.get_object(rval)
 		aobj.remove()
 
 		try:
-			nobj = self._rc.get_object(rval)
+			aobj = self._rc.get_object(rval)
 		except rad.NotFoundError:
 			pass
 
 	def test_use_stale_object(self):
 		""" after removing object, existing references stop working """
 
-		rval = self._wobj.addOne()
-		nobj = self._rc.get_object(rval)
-		aobj = adapt.RawAdaptor(nobj)
+		rval = self._obj.addOne()
+		aobj = self._rc.get_object(rval)
 		aobj.remove()
 
 		try:
@@ -114,12 +109,11 @@
 		""" after removing and recreating object, existing references
 		still don't work """
 
-		rval = self._wobj.addOne()
-		nobj = self._rc.get_object(rval)
-		aobj = adapt.RawAdaptor(nobj)
+		rval = self._obj.addOne()
+		aobj = self._rc.get_object(rval)
 		aobj.remove()
 
-		rval = self._wobj.addSpecific(int(rval.get_value("id")))
+		rval = self._obj.addSpecific(int(rval.get_value("id")))
 
 		try:
 			aobj.tickle()
@@ -130,18 +124,16 @@
 		""" after removing and recreating object, able to use new
 		object """
 
-		rval = self._wobj.addOne()
-		nobj = self._rc.get_object(rval)
-		aobj = adapt.RawAdaptor(nobj)
+		rval = self._obj.addOne()
+		aobj = self._rc.get_object(rval)
 		aobj.remove()
 
-		rval = self._wobj.addSpecific(int(rval.get_value("id")))
+		rval = self._obj.addSpecific(int(rval.get_value("id")))
 
 		try:
 			aobj.tickle()
 		except rad.NotFoundError:
 			pass
 
-		nobj2 = self._rc.get_object(rval)
-		aobj2 = adapt.RawAdaptor(nobj2)
+		aobj2 = self._rc.get_object(rval)
 		aobj2.tickle()
--- a/usr/src/test/python/client/test_basetypes.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/test/python/client/test_basetypes.py	Fri May 04 10:14:24 2012 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 import os
@@ -29,7 +29,6 @@
 import unittest
 import common.tests as tests
 import rad.client as rad
-import rad.adaptor as adapt
 import rad.util as util
 
 #
@@ -66,18 +65,18 @@
 	#
 
 	def readTest(self, prop, eval):
-		rval = self._obj.read(prop)
+		rval = getattr(self._obj, prop)
 		if rval != eval:
 			self.fail(
 			    "%s returned incorrect value: got %s, expected %s" %
 			    (prop, rval, eval))
 
 	def writeTest(self, prop, eval):
-		self._obj.write(prop, eval)
+		setattr(self._obj, prop, eval)
 
 	def badWriteTest(self, prop, eval):
 		try:
-			self._obj.write(prop, eval)
+			setattr(self._obj, prop, eval)
 		except rad.ObjectError:
 			pass
 		else:
@@ -253,7 +252,7 @@
 	def test_stringEmpty_read(self):
 		""" read empty string """
 
-		val = self._wobj.stringEmpty
+		val = self._obj.stringEmpty
 		if val == None:
 			self.fail("received null string")
 		if len(val) > 0:
@@ -262,20 +261,20 @@
 	def test_stringEmpty_write(self):
 		""" write empty string """
 
-		self._wobj.stringEmpty = ""
+		self._obj.stringEmpty = ""
 
 	def test_stringEmpty_write_bad(self):
 		""" correctly fail to write null or non-empty string """
 
 		try:
-			self._wobj.stringEmpty = None
+			self._obj.stringEmpty = None
 		except rad.ObjectError:
 			pass
 		else:
 			self.fail("was able to write None")
 
 		try:
-			self._wobj.stringEmpty = " "
+			self._obj.stringEmpty = " "
 		except rad.ObjectError:
 			pass
 		else:
@@ -288,20 +287,20 @@
 	def test_stringNull_read(self):
 		""" read null string """
 
-		val = self._wobj.stringNull
+		val = self._obj.stringNull
 		if val != None:
 			self.fail("received non-null string")
 
 	def test_stringNull_write(self):
 		""" write null string """
 
-		self._wobj.stringNull = None
+		self._obj.stringNull = None
 
 	def test_stringNull_write_bad(self):
 		""" correctly fail to write non-null string """
 
 		try:
-			self._wobj.stringNull = ""
+			self._obj.stringNull = ""
 		except rad.ObjectError:
 			pass
 		else:
@@ -319,20 +318,20 @@
 	def test_stringTest_write(self):
 		""" write pre-arranged string """
 
-		self._wobj.stringTest = self.string_good
+		self._obj.stringTest = self.string_good
 
 	def test_stringTest_write_bad(self):
 		""" correctly fail to write null or incorrect string """
 
 		try:
-			self._wobj.stringTest = None
+			self._obj.stringTest = None
 		except rad.ObjectError:
 			pass
 		else:
 			self.fail("was able to write null string")
 
 		try:
-			self._wobj.stringTest = self.string_bad
+			self._obj.stringTest = self.string_bad
 		except rad.ObjectError:
 			pass
 		else:
--- a/usr/src/test/python/client/test_connect.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/test/python/client/test_connect.py	Fri May 04 10:14:24 2012 -0700
@@ -25,7 +25,6 @@
 #
 
 import rad.client as rad
-import rad.adaptor as adapt
 import rad.util as ru
 import common.tests as tests
 import pwd
@@ -89,7 +88,7 @@
 	    connected user."""
 
 	auth = rad_conn.get_object(self.get_name())
-	co = auth.read("connectionTimeout")
+	co = auth.connectionTimeout
 	# co should be greater than zero, the default value is 180
 	if (co <= 0):
 	    self.fail("unable to connect to RAD")
@@ -119,7 +118,7 @@
     #
     # A private function to create a TLS connection.
     #
-    def _connect_ssl(self, host, port, keyfile, certfile):
+    def _connect_tls(self, host, port, keyfile, certfile):
 	s = self._connect_tcp(host, port)
 	return ssl.wrap_socket(s, keyfile, certfile)
 
@@ -134,7 +133,7 @@
     # A public function to create a TLS connection.
     #
     def connect_tls(self, host, port, keyfile, certfile, locale = None):
-	s = self._connect_ssl(host, port, keyfile, certfile)
+	s = self._connect_tls(host, port, keyfile, certfile)
 	return rad.RadConnection(s, locale = locale)
 
 #
@@ -176,7 +175,7 @@
     def get_modules(self):
 	return ["/usr/lib/rad/transport/mod_xport_unix.so"]
 
-    def get_uds_path(self):
+    def get_unix_path(self):
 	return os.path.join(TEST_DIRNAME, AFUNIX_FILENAME)
 
     # This function verifies the connection and retrieves the logged used
@@ -185,12 +184,12 @@
 	self.verify_connection(self._rc)
 
 	# connect to RAD using UDS
-	rad_conn = ru.connect_local(self.get_uds_path())
+	rad_conn = ru.connect_unix(self.get_unix_path())
 	self.verify_connection(rad_conn)
 
 	# retrieve and return the server username
 	auth = rad_conn.get_object(self.get_name())
-	svr_user = auth.read("user")
+	svr_user = auth.user
 	rad_conn.close()
 
 	return svr_user
@@ -201,7 +200,7 @@
 #
 class ConnectTestLocalAFUNIXauth(ConnectTestLocalAFUNIX):
     def get_auxargs(self):
-	transport = "unix:path=" + self.get_uds_path()
+	transport = "unix:path=" + self.get_unix_path()
 	return ["-t", transport]
 
     def connectLocalAFUNIXauth(self):
@@ -221,7 +220,7 @@
 #
 class ConnectTestLocalAFUNIXunauth(ConnectTestLocalAFUNIX):
     def get_auxargs(self):
-	transport = "unix:path=" + self.get_uds_path() +\
+	transport = "unix:path=" + self.get_unix_path() +\
 	    ",peercred=false"
 	return ["-t", transport]
 
@@ -332,7 +331,6 @@
 	    name = self.get_name()
 	    if name is not None:
 		self._obj = self._rc.get_object(name)
-		self._wobj = adapt.RawAdaptor(self._obj)
 
 #
 # Test a remote RAD using the TCP transport.
--- a/usr/src/test/python/client/test_derivedtypes.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/test/python/client/test_derivedtypes.py	Fri May 04 10:14:24 2012 -0700
@@ -29,7 +29,6 @@
 import unittest
 import common.tests as tests
 import rad.client as rad
-import rad.adaptor as adapt
 import rad.util as util
 
 #
@@ -66,11 +65,11 @@
 	#
 
 	def writeTest(self, prop, eval):
-		self._obj.write(prop, eval)
+		setattr(self._obj, prop, eval)
 
 	def badWriteTest(self, prop, eval):
 		try:
-			self._obj.write(prop, eval)
+			setattr(self._obj, prop, eval)
 		except rad.ObjectError:
 			pass
 		else:
@@ -84,9 +83,9 @@
 	def test_structure_read(self):
 		""" read of structProp returns correct value """
 		
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
-		val = self._obj.read("structProp")
+		val = self._obj.structProp
 		self.assertEqual(val.intfield, self.VALUE_INTFIELD)
 		self.assertEqual(val.enumfield, types.SubEnum.val_one)
 		self.assertEqual(val.structfield.stringfield,
@@ -100,7 +99,7 @@
 	def test_structure_write(self):
 		""" write to structProp writes correct value """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		val = types.ComplexStruct(self.VALUE_INTFIELD,
 		    types.SubStruct(self.VALUE_SF_STRINGFIELD),
@@ -110,13 +109,13 @@
 	def test_structure_write_read(self):
 		""" write to structProp writes correct value """
 
-		val = self._obj.read("structProp")
+		val = self._obj.structProp
 		self.writeTest("structProp", val)
 
 	def test_structure_write_tagged(self):
 		""" write to structProp writes correct value """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		val = types.ComplexStruct(
 		    enumfield = types.SubEnum.val_one,
@@ -128,7 +127,7 @@
 	def test_structure_write_tagged_mixed(self):
 		""" write to structProp writes correct value """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		val = types.ComplexStruct(self.VALUE_INTFIELD,
 		    types.SubStruct(self.VALUE_SF_STRINGFIELD),
@@ -139,7 +138,7 @@
 	def test_structure_write_bad_mismatch(self):
 		""" write to structProp of bad (but legal) value fails """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		val = types.ComplexStruct(
 		    enumfield = types.SubEnum.val_one,
@@ -150,7 +149,7 @@
 	def test_structure_construct_bad_extra(self):
 		""" extra field causes failure """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		try:
 			val = types.ComplexStruct(self.VALUE_INTFIELD,
@@ -165,7 +164,7 @@
 	def test_structure_construct_bad_extra_labeled(self):
 		""" extra labeled field causes failure """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		try:
 			val = types.ComplexStruct(self.VALUE_INTFIELD,
@@ -181,7 +180,7 @@
 	def test_structure_construct_bad_missing(self):
 		""" missing non-nullable field causes failure """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		try:
 			val = types.ComplexStruct(self.VALUE_INTFIELD,
@@ -195,7 +194,7 @@
 	def test_structure_construct_bad_double(self):
 		""" double-specified field causes failure """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		try:
 			val = types.ComplexStruct(self.VALUE_INTFIELD,
--- a/usr/src/test/python/client/test_fallback.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/test/python/client/test_fallback.py	Fri May 04 10:14:24 2012 -0700
@@ -25,7 +25,6 @@
 #
 
 import rad.client as rad
-import rad.adaptor as adapt
 import common.tests as tests
 
 #
@@ -63,26 +62,26 @@
 	def test_growerFirst(self):
 		""" read from growerFirst returns correct value """
 
-		Grower = self._obj.types.Grower
-		self.assertEqual(self._wobj.growerFirst, Grower.first)
+		Grower = rad.get_types(self._obj).Grower
+		self.assertEqual(self._obj.growerFirst, Grower.first)
 
 	def test_growerLast(self):
 		""" read from growerLast returns correct value """
 
-		Grower = self._obj.types.Grower
-		self.assertEqual(self._wobj.growerLast, Grower.third)
+		Grower = rad.get_types(self._obj).Grower
+		self.assertEqual(self._obj.growerLast, Grower.third)
 
 	def test_growerStringGood(self):
 		""" growerString recognizes an in-range value """
 
-		Grower = self._obj.types.Grower
-		self.assertEqual(self._wobj.growerString(Grower.first),
+		Grower = rad.get_types(self._obj).Grower
+		self.assertEqual(self._obj.growerString(Grower.first),
 		    "first")
 
 	def test_growerStringBad(self):
 		""" growerString recognizes an out-of-range value """
 		# XXX: Currently impossible to have truly out-of-range value
 
-		Grower = self._obj.types.Grower
-		self.assertEqual(self._wobj.growerString(Grower.whoknows),
+		Grower = rad.get_types(self._obj).Grower
+		self.assertEqual(self._obj.growerString(Grower.whoknows),
 		    "whoknows")
--- a/usr/src/test/python/client/test_list.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/test/python/client/test_list.py	Fri May 04 10:14:24 2012 -0700
@@ -25,7 +25,6 @@
 #
 
 import rad.client as rad
-import rad.adaptor as adapt
 import common.tests as tests
 
 class ListTest(tests.RADTest):
--- a/usr/src/test/python/client/test_prop_access.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/test/python/client/test_prop_access.py	Fri May 04 10:14:24 2012 -0700
@@ -21,11 +21,10 @@
 #
 
 #
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 import rad.client as rad
-import rad.adaptor as adapt
 import common.tests as tests
 
 class PropTest(tests.RADTestObject):
@@ -56,7 +55,7 @@
 	def test_ro_read(self):
 		""" read from propRO returns correct value """
 
-		rval = self._wobj.propRO
+		rval = self._obj.propRO
 		if rval != self.propval:
 			self.fail_value("propRO", rval, self.propval)
 
@@ -64,7 +63,7 @@
 		""" write to propRO throws exception """
 
 		try:
-			self._wobj.propRO = 12345
+			self._obj.propRO = 12345
 		except (rad.InvalidFeatureError, rad.IllegalError):
 			pass
 		else:
@@ -74,7 +73,7 @@
 		""" read from propWO throws exception """
 
 		try:
-			scratch = self._wobj.propWO
+			scratch = self._obj.propWO
 		except (rad.InvalidFeatureError, rad.IllegalError):
 			pass
 		else:
@@ -83,51 +82,51 @@
 	def test_wo_write(self):
 		""" write to propWO succeeds """
 
-		self._wobj.propWO = 12345
+		self._obj.propWO = 12345
 
 	def test_wo_write_correct(self):
 		""" write to propWO writes correct value """
 
-		self._wobj.propWO = 12345
+		self._obj.propWO = 12345
 
-		rval = self._wobj.propRO
+		rval = self._obj.propRO
 		if rval != 12345:
 			self.fail_value("propRO", rval, 12345)
 
 	def test_rw_misc(self):
 		""" propRW functionality - break up """
 
-		rval = self._wobj.propRW
+		rval = self._obj.propRW
 		if rval != self.propval:
 			self.fail_value("propRW", rval, self.propval)
 
-		self._wobj.propRW = 12345
+		self._obj.propRW = 12345
 
-		rval = self._wobj.propRW
+		rval = self._obj.propRW
 		if rval != 12345:
 			self.fail_value("propRW", rval, 12345)
 
 	def test_rwopt_misc(self):
 		""" propRWOpt functionality - break up """
 
-		if self._wobj.propRWOpt != None:
+		if self._obj.propRWOpt != None:
 			self.fail("propRWOpt not none")
 
-		self._wobj.propRWOpt = "test"
+		self._obj.propRWOpt = "test"
 
-		if self._wobj.propRWOpt != "test":
+		if self._obj.propRWOpt != "test":
 			self.fail("propRWOpt didn't retain value")
 
-		self._wobj.propRWOpt = None
+		self._obj.propRWOpt = None
 
-		if self._wobj.propRWOpt != None:
+		if self._obj.propRWOpt != None:
 			self.fail("propRWOpt didn't retain None")
 
 	def test_wononopt_none(self):
 		""" write of None to propWONonOpt fails """
 
 		try:
-			self._wobj.propWONonOpt = None
+			self._obj.propWONonOpt = None
 		except rad.MismatchError as e:
 			pass
 		else:
@@ -136,7 +135,7 @@
 	def test_wononopt_value(self):
 		""" write of non-None value to propWONonOpt fails """
 
-		self._wobj.propWONonOpt = "test"
+		self._obj.propWONonOpt = "test"
 
-		if self._wobj.propRWOpt != "test":
+		if self._obj.propRWOpt != "test":
 			self.fail("propWONonOpt didn't retain value")
--- a/usr/src/test/python/client/test_unions.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/test/python/client/test_unions.py	Fri May 04 10:14:24 2012 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 import os
@@ -30,7 +30,6 @@
 import unittest
 import common.tests as tests
 import rad.client as rad
-import rad.adaptor as adapt
 import rad.util as util
 
 #
@@ -82,7 +81,7 @@
 	def test_create_bad_arm(self):
 		""" try to assign to a non-existent arm """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		try:
 			un = types.up_bool(False, self.VALUE_STRING)
@@ -99,7 +98,7 @@
 	def test_create_void_arm(self):
 		""" try to assign non-None to a void arm """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		try:
 			un = types.uv_bool(False, self.VALUE_STRING)
@@ -110,7 +109,7 @@
 	def test_create_missing_arm(self):
 		""" try to create a union without assigning an arm """
 
-		types = self._obj.types
+		types = rad.get_types(self._obj)
 
 		try:
 			un = types.uc_bool(False, None)
@@ -125,8 +124,8 @@
 	def test_read_complete_boolean(self):
 		""" read of complete boolean union """
 		
-		types = self._obj.types
-		f = self._wobj.makeCompleteBool
+		types = rad.get_types(self._obj)
+		f = self._obj.makeCompleteBool
 
 		val = f(True)
 		self.assertEqual(val.u_arm, True)
@@ -139,8 +138,8 @@
 	def test_read_partial_boolean(self):
 		""" read of partial boolean union """
 		
-		types = self._obj.types
-		f = self._wobj.makePartialBool
+		types = rad.get_types(self._obj)
+		f = self._obj.makePartialBool
 
 		val = f(True)
 		self.assertEqual(val.u_arm, True)
@@ -156,8 +155,8 @@
 	def test_read_voidy_boolean(self):
 		""" read of voidy boolean union """
 		
-		types = self._obj.types
-		f = self._wobj.makeVoidyBool
+		types = rad.get_types(self._obj)
+		f = self._obj.makeVoidyBool
 
 		val = f(True)
 		self.assertEqual(val.u_arm, True)
@@ -170,8 +169,8 @@
 	def test_read_complete_enum(self):
 		""" read of complete enum union """
 		
-		types = self._obj.types
-		f = self._wobj.makeCompleteEnum
+		types = rad.get_types(self._obj)
+		f = self._obj.makeCompleteEnum
 
 		val = f(types.simpleenum.A)
 		self.assertEqual(val.u_arm, types.simpleenum.A)
@@ -196,8 +195,8 @@
 	def test_read_partial_enum(self):
 		""" read of partial enum union """
 		
-		types = self._obj.types
-		f = self._wobj.makePartialEnum
+		types = rad.get_types(self._obj)
+		f = self._obj.makePartialEnum
 
 		val = f(types.simpleenum.A)
 		self.assertEqual(val.u_arm, types.simpleenum.A)
@@ -228,8 +227,8 @@
 	def test_read_defaulted_enum(self):
 		""" read of defaulted enum union """
 		
-		types = self._obj.types
-		f = self._wobj.makeDefaultedEnum
+		types = rad.get_types(self._obj)
+		f = self._obj.makeDefaultedEnum
 
 		val = f(types.simpleenum.A)
 		self.assertEqual(val.u_arm, types.simpleenum.A)
@@ -254,8 +253,8 @@
 	def test_read_voidy_enum(self):
 		""" read of voidy enum union """
 		
-		types = self._obj.types
-		f = self._wobj.makeVoidyEnum
+		types = rad.get_types(self._obj)
+		f = self._obj.makeVoidyEnum
 
 		val = f(types.simpleenum.A)
 		self.assertEqual(val.u_arm, types.simpleenum.A)
@@ -280,8 +279,8 @@
 	def test_read_types(self):
 		""" read of type variety """
 		
-		types = self._obj.types
-		f = self._wobj.makeTypes
+		types = rad.get_types(self._obj)
+		f = self._obj.makeTypes
 
 		val = f(types.simpleenum.A)
 		self.assertEqual(val.u_arm, types.simpleenum.A)
@@ -309,8 +308,8 @@
 	def test_read_array(self):
 		""" read of union array """
 
-		types = self._obj.types
-		val = self._wobj.makeArray()
+		types = rad.get_types(self._obj)
+		val = self._obj.makeArray()
 
 		self.assertEqual(len(val), 2)
 
@@ -324,8 +323,8 @@
 	def test_read_complete_flex(self):
 		""" read of complete flex union """
 		
-		types = self._obj.types
-		f = self._wobj.makeCompleteFlex
+		types = rad.get_types(self._obj)
+		f = self._obj.makeCompleteFlex
 
 		val = f(types.flexyenum.A)
 		self.assertEqual(val.u_arm, types.flexyenum.A)
@@ -345,8 +344,8 @@
 	def test_read_defaulted_flex(self):
 		""" read of defaulted flex union """
 		
-		types = self._obj.types
-		f = self._wobj.makeDefaultedFlex
+		types = rad.get_types(self._obj)
+		f = self._obj.makeDefaultedFlex
 
 		val = f(types.flexyenum.A)
 		self.assertEqual(val.u_arm, types.flexyenum.A)
@@ -371,8 +370,8 @@
 	def test_write_complete_boolean(self):
 		""" write of complete boolean union """
 		
-		types = self._obj.types
-		f = self._wobj.takeCompleteBool
+		types = rad.get_types(self._obj)
+		f = self._obj.takeCompleteBool
 
 		val = f(types.uc_bool(True, self.VALUE_INT))
 		self.assertEqual(val, True)
@@ -383,8 +382,8 @@
 	def test_write_partial_boolean(self):
 		""" write of partial boolean union """
 		
-		types = self._obj.types
-		f = self._wobj.takePartialBool
+		types = rad.get_types(self._obj)
+		f = self._obj.takePartialBool
 
 		val = f(types.up_bool(True, self.VALUE_INT))
 		self.assertEqual(val, True)
@@ -392,8 +391,8 @@
 	def test_write_voidy_boolean(self):
 		""" write of voidy boolean union """
 		
-		types = self._obj.types
-		f = self._wobj.takeVoidyBool
+		types = rad.get_types(self._obj)
+		f = self._obj.takeVoidyBool
 
 		val = f(types.uv_bool(True, self.VALUE_INT))
 		self.assertEqual(val, True)
@@ -404,8 +403,8 @@
 	def test_write_complete_enum(self):
 		""" write of complete enum union """
 		
-		types = self._obj.types
-		f = self._wobj.takeCompleteEnum
+		types = rad.get_types(self._obj)
+		f = self._obj.takeCompleteEnum
 
 		val = f(types.uc_enum(types.simpleenum.A, self.VALUE_INT))
 		self.assertEqual(val, types.simpleenum.A)
@@ -425,8 +424,8 @@
 	def test_write_partial_enum(self):
 		""" write of partial enum union """
 		
-		types = self._obj.types
-		f = self._wobj.takePartialEnum
+		types = rad.get_types(self._obj)
+		f = self._obj.takePartialEnum
 
 		val = f(types.up_enum(types.simpleenum.A, self.VALUE_INT))
 		self.assertEqual(val, types.simpleenum.A)
@@ -440,8 +439,8 @@
 	def test_write_defaulted_enum(self):
 		""" write of default enum union """
 		
-		types = self._obj.types
-		f = self._wobj.takeDefaultedEnum
+		types = rad.get_types(self._obj)
+		f = self._obj.takeDefaultedEnum
 
 		val = f(types.ud_enum(types.simpleenum.A, self.VALUE_INT))
 		self.assertEqual(val, types.simpleenum.A)
@@ -461,8 +460,8 @@
 	def test_write_voidy_enum(self):
 		""" write of voidy enum union """
 		
-		types = self._obj.types
-		f = self._wobj.takeVoidyEnum
+		types = rad.get_types(self._obj)
+		f = self._obj.takeVoidyEnum
 
 		val = f(types.uv_enum(types.simpleenum.A, self.VALUE_INT))
 		self.assertEqual(val, types.simpleenum.A)
@@ -482,8 +481,8 @@
 	def test_write_types(self):
 		""" write of type variety """
 		
-		types = self._obj.types
-		f = self._wobj.takeTypes
+		types = rad.get_types(self._obj)
+		f = self._obj.takeTypes
 
 		val = f(types.u_types(types.simpleenum.A, self.VALUE_STRING))
 		self.assertEqual(val, types.simpleenum.A)
@@ -506,8 +505,8 @@
 	def test_write_array(self):
 		""" write of union array """
 		
-		types = self._obj.types
-		self._wobj.takeArray([
+		types = rad.get_types(self._obj)
+		self._obj.takeArray([
 		  types.uc_enum(types.simpleenum.A, self.VALUE_INT),
 		  types.uc_enum(types.simpleenum.B, self.VALUE_STRING)])
 
@@ -515,8 +514,8 @@
 	def test_write_complete_flex(self):
 		""" write of complete flex union """
 		
-		types = self._obj.types
-		f = self._wobj.takeCompleteFlex
+		types = rad.get_types(self._obj)
+		f = self._obj.takeCompleteFlex
 
 		val = f(types.uc_flex(types.flexyenum.A, self.VALUE_INT))
 		self.assertEqual(val, types.flexyenum.A)
@@ -533,8 +532,8 @@
 	def test_write_defaulted_flex(self):
 		""" write of defaulted flex union """
 		
-		types = self._obj.types
-		f = self._wobj.takeDefaultedFlex
+		types = rad.get_types(self._obj)
+		f = self._obj.takeDefaultedFlex
 
 		val = f(types.ud_flex(types.flexyenum.A, self.VALUE_INT))
 		self.assertEqual(val, types.flexyenum.A)
--- a/usr/src/test/python/common/tests.py	Fri Apr 27 01:54:08 2012 -0400
+++ b/usr/src/test/python/common/tests.py	Fri May 04 10:14:24 2012 -0700
@@ -27,7 +27,6 @@
 import unittest
 import os
 import rad.util
-import rad.adaptor
 from rad.client import Name
 from abc import ABCMeta, abstractmethod
 import radtest.fw as radtest
@@ -54,7 +53,6 @@
 		name = self.get_name()
 		if name is not None:
 			self._obj = self._rc.get_object(name)
-			self._wobj = rad.adaptor.RawAdaptor(self._obj)
 
 	def tearDown(self):
 		if self._rc is not None: