focal (3) apptools.3.gz

Provided by: python-apptools-doc_4.5.0-1_all bug

NAME

       apptools - apptools 4.5.0

APPLICATION SCRIPTING FRAMEWORK

       The  Application  Scripting Framework is a component of the Enthought Tool Suite that provides developers
       with an API that allows traits based objects to be made scriptable.  Operations on  a  scriptable  object
       can be recorded in a script and subsequently replayed.

       The  framework  is  completely  configurable.   Alternate  implementations of all major components can be
       provided if necessary.

   Framework Concepts
       The following are the concepts supported by the framework.

       • Scriptable Type

         A scriptable type is a sub-type of HasTraits that has scriptable methods and scriptable traits.   If  a
         scriptable method is called, or a scriptable trait is set, then that action can be recorded in a script
         and subsequently replayed.

         If the __init__() method is scriptable then the creation of an object from the type can be recorded.

         Scriptable types can be explicitly defined or created dynamically from any sub-type of HasTraits.

       • Scriptable API

         The set of a scriptable type's scriptable methods and traits constitutes the type's scriptable API.

         The API can be defined explicitly using the  scriptable  decorator  (for  methods)  or  the  Scriptable
         wrapper (for traits).

         For  scriptable  types that are created dynamically then the API can be defined in terms of one or more
         types or interfaces or an explicit list of method and trait names.  By default, all public methods  and
         traits  (ie.   those  whose  name  does  not begin with an underscore) are part of the API.  It is also
         possible to then explicitly exclude a list of method and trait names.

       • Scriptable Object

         A scriptable object is an instance of a scriptable type.

         Scriptable objects can  be  explicitly  created  by  calling  the  scriptable  type.   Alternatively  a
         non-scriptable object can be made scriptable dynamically.

       • Script

         A script is a Python script and may be a recording or written from scratch.

         If  the  creation  of scriptable objects can be recorded, then it may be possible for a recording to be
         run directly by the Python interpreter and independently of the application that  made  the  recording.
         Otherwise  the  application  must run the script and first create any scriptable objects referred to in
         the script.

       • Binding

         A script runs in a namespace which is, by default, empty.  If the scriptable objects referred to  in  a
         script  are  not  created  by the script (because their type's __init__() method isn't scriptable) then
         they must be created by the application and added to the namespace.  Adding an object to the  namespace
         is called binding.

         Scriptable  objects  whose  creation  can  be recorded will automatically bind themselves when they are
         created.

         It also possible to bind an object factory rather than the object itself.  The factory will be  called,
         and  the  object created, only if the object is needed by the script when it is run.  This is typically
         used by plugins.

         The name that an object is bound to need bear no relation to the object's name within the  application.
         Names may be dotted names (eg. aaa.bbb.ccc) and appropriate objects representing the intermediate parts
         of such a name will be created automatically.

         An event is fired whenever an object is bound (or when a bound factory is invoked).  This allows  other
         objects (eg. an embedded Python shell) to expose scriptable objects in other ways.

       • Script Manager

         A  script  manager is responsible for the recording and subsequent playback of scripts.  An application
         has a single script manager instance which can be explicitly set or created automatically.

   Limitations
       In the current implementation scriptable Trait container types (eg. List, Dict) may only contain  objects
       corresponding to fundamental Python types (eg.  int, bool, str).

   API Overview
       This  section  gives an overview of the API implemented by the framework.  The complete API documentation
       is available as endo generated HTML.

       The example application demonstrates some the features of the framework.

   Module Level Objects
       get_script_manager()
              The application's script manager is returned.  One will be created automatically if needed.

       set_script_manager(script_manager)
              The application's script manager will be set  to  script_manager  replacing  any  existing  script
              manager.

       scriptable
              This is a decorator used to explicitly mark methods as being scriptable.  Any call to a scriptable
              method is recorded.  If a type's __init__() method is decorated then the creation  of  the  object
              will be recorded.

       Scriptable
              This  is a wrapper for a trait to explicitly mark it as being scriptable.  Any change to the value
              of the trait will be recorded.  Simple reads of the trait will not be recorded unless  unless  the
              value  read  is bound to another scriptable trait or passed as an argument to a scriptable method.
              Passing has_side_effects=True when wrapping the trait will ensure  that  a  read  will  always  be
              recorded.

       create_scriptable_type(script_type,     name=None,     bind_policy='auto',    api=None,    includes=None,
       excludes=None, script_init=True)
              This creates a new type based on an existing type but with certain methods and  traits  marked  as
              being scriptable.  Scriptable objects can then be created by calling the type.

              script_type  is  the  existing, non-scriptable, type.  The new type will be a sub-type of it.  The
              api, includes and excludes arguments determine which methods and traits are made  scriptable.   By
              default,  all  public  methods and traits (ie. those whose name does not begin with an underscore)
              are made scriptable.

              The name and bind_policy arguments determine how  scriptable  objects  are  bound  when  they  are
              created.   name  is  the  name  that  an  object  will  be  bound  to.  It defaults to the name of
              script_type with the first character forced to lower  case.   name  may  be  a  dotted  name,  eg.
              aaa.bb.c.

              bind_policy determines what happens if an object is already bound to the name.  If it is auto then
              a numerical suffix will be added to the name of the new object.  If it is unique then an exception
              will be raised.  If it is rebind then the object currently bound to the name will be unbound.

              api is a class or interface (or a list of classes or interfaces) that is used to provide the names
              of the methods and traits to be made scriptable.  The class or interface effectively  defines  the
              scripting API.

              If  api  is  not  specified  then  includes  is  a  list  of  method and trait names that are made
              scriptable.

              If api and includes are not specified then excludes is a list of method and trait names  that  are
              not made scriptable.

              If  script_init  is  set  then  the  __init__() method is made scriptable irrespective of the api,
              includes and excludes arguments.

              If script_init is not set then objects must be explicitly  bound  and  name  and  bind_policy  are
              ignored.

       make_object_scriptable(obj, api=None, includes=None, excludes=None)
              This  takes  an  existing  unscriptable  object  and  makes  it  scriptable.   It works by calling
              create_scriptable_type() on the the objects existing type and replacing that  existing  type  with
              the new scriptable type.

              See  the  description  of  create_scriptable_type()  for  an  explanation of the api, includes and
              excludes arguments.

   ScriptManager
       The ScriptManager class is the default implementation of the IScriptManager interface.

       bind_event
              This event is fired whenever an object is bound or unbound.  The event's argument  implements  the
              IBindEvent interface.

       recording
              This  trait  is  set  if a script is currently being recorded.  It is updated automatically by the
              script manager.

       script This trait contains the text of the script currently being recorded (or the last  recorded  script
              if one is not being currently recorded).  It is updated automatically by the script manager.

       script_updated
              This  event  is  fired  whenever  the script trait is updated.  The event's argument is the script
              manager.

       bind(self, obj, name=None, bind_policy='unique', api=None, includes=None, excludes=None)
              This method makes an  object  scriptable  and  binds  it  to  a  name.   See  the  description  of
              create_scriptable_type()  for  an explanation of the api, includes, excludes, name and bind_policy
              arguments.

       bind_factory(self, factory, name, bind_policy='unique', api=None, includes=None, excludes=None)
              This method binds an object factory to a name.  The factory is called to create  the  object  (and
              make  it  scriptable)  only when the object is needed by a running script.  See the description of
              create_scriptable_type() for an explanation of the name and bind_policy arguments.

       run(self, script)
              This method runs a script in a namespace containing all currently bound objects.   script  is  any
              object that can be used by Python's exec statement including a string or a file-like object.

       run_file(self, file_name)
              This method runs a script in a namespace containing all currently bound objects.  file_name is the
              name of a file containing the script.

       start_recording(self)
              This method starts the recording of a script.

       stop_recording(self)
              This method stops the recording of the current script.

   IBindEvent
       The IBindEvent interface defines the interface that is implemented by the object passed when  the  script
       manager's bind_event is fired.

       name   This trait is the name being bound or unbound.

       obj    This trait is the obj being bound to name or None if name is being unbound.

   StartRecordingAction
       The  StartRecordingAction  class  is  a  canned  PyFace  action  that  starts the recording of changes to
       scriptable objects to a script.

   StopRecordingAction
       The StopRecordingAction class is a canned PyFace action that ends the recording of changes to  scriptable
       objects to a script.

   Implementing Application Scripting
       The  key part of supporting application scripting is to design an appropriate scripting API and to ensure
       than the application itself uses the API so that changes to the data  can  be  recorded.   The  framework
       provides many ways to specify the scripting API.  Which approach is appropriate in a particular case will
       depend on when it is a new application, or whether scripting is being added to an  existing  application,
       and how complex the application's data model is.

   Static Specification
       A  scripting  API  is  specified  statically  by  the  explicit  use  of the scriptable decorator and the
       Scriptable trait wrapper.  For example:

          from apptools.appscripting.api import scriptable, Scriptable
          from traits.api import HasTraits, Int, Str

          class DataModel(HasTraits):

              foo = Scriptable(Str)

              bar = Scriptable(Int, has_side_effects=True)

              @scriptable
              def baz(self):
                  pass

              def weeble(self)
                  pass

          # Create the scriptable object.  It's creation won't be recorded because
          # __init__() isn't decorated.
          obj = DataModel()

          # These will be recorded.
          obj.foo = ''
          obj.bar = 10
          obj.baz()

          # This will not be recorded.
          obj.weeble()

          # This won't be recorded unless 'f' is passed to something that is
          # recorded.
          f = obj.foo

          # This will be recorded because we set 'has_side_effects'.
          b = obj.bar

   Dynamic Specification
       A scripting API can also be specified dynamically.  The following example produces  a  scriptable  object
       with  the  same  scriptable  API  as  above (with the exception that has_side_effects cannot be specified
       dynamically):

          from apptools.appscripting.api import create_scriptable_type
          from traits.api import HasTraits, Int, Str

          class DataModel(HasTraits):

              foo = Str

              bar = Int

              def baz(self):
                  pass

              def weeble(self)
                  pass

          # Create a scriptable type based on the above.
          ScriptableDataModel = create_scriptable_type(DataModel, excludes=['weeble'])

          # Now create scriptable objects from the scriptable type.  Note that each
          # object has the same type.
          obj1 = ScriptableDataModel()
          obj2 = ScriptableDataModel()

       Instead we could bypass the type and make the objects themselves scriptable as follows:

          from apptools.appscripting.api import make_object_scriptable
          from traits.api import HasTraits, Int, Str

          class DataModel(HasTraits):

              foo = Str

              bar = Int

              def baz(self):
                  pass

              def weeble(self)
                  pass

          # Create unscriptable objects.
          obj1 = DataModel()
          obj2 = DataModel()

          # Now make the objects scriptable.  Note that each object has a different
          # type, each a sub-type of 'DataModel'.
          make_object_scriptable(obj1, excludes=['weeble'])
          make_object_scriptable(obj2, excludes=['weeble'])

       With a more sophisticated design we may choose to specify the scriptable API as an interface as follows:

          from apptools.appscripting.api import make_object_scriptable
          from traits.api import HasTraits, Int, Interface, Str

          class DataModel(HasTraits):

              foo = Str

              bar = Int

              def baz(self):
                  pass

              def weeble(self)
                  pass

          class IScriptableDataModel(Interface):

              foo = Str

              bar = Int

              def baz(self):
                  pass

          # Create an unscriptable object.
          obj = DataModel()

          # Now make the object scriptable.
          make_object_scriptable(obj, api=IScriptableDataModel)

   Scripting __init__()
       Making a type's __init__() method has advantages and  disadvantages.   It  means  that  the  creation  of
       scriptable objects will be recorded in a script (along with the necessary import statements).  This means
       that the script can be run independently of your application by the standard Python interpreter.

       The disadvantage is that, if you have a complex data model, with many interdependencies, then defining  a
       complete  and consistent scripting API that allows a script to run independently may prove difficult.  In
       such cases it is better to have the application create and bind the scriptable objects itself.

PERMISSIONS FRAMEWORK - INTRODUCTION

       The Permissions Framework is a component of the Enthought Tool Suite that provides  developers  with  the
       facility  to  limit  access  to  parts of an application unless the user is appropriately authorised.  In
       other words it enables and disables different parts of the GUI according to the identity of the user.

       The framework includes an API to allow it to be  integrated  with  an  organisation's  existing  security
       infrastructure, for example to look users up in a corporate LDAP directory.

       The  framework  is  completely  configurable.   Alternate  implementations of all major components can be
       provided if necessary.  The default implementations provide a simple local filesystem user  database  and
       allows roles to be defined and assigned to users.

       The  framework  does  not  provide  any  facility  for  protecting access to data.  It is not possible to
       implement such protection in Python and using the file security provided by a typical operating system.

   Framework Concepts
       The following are the concepts supported by the framework.

       • Permission

         A permission is the basic tool that a  developer  uses  to  specify  that  access  to  a  part  of  the
         application  should  be  restricted.  If the current user has the permission then access is granted.  A
         permission may be attached to a PyFace action, to an item of a TraitsUI  view,  or  to  a  GUI  toolkit
         specific  widget.   When  the  user  is  denied  access,  the  corresponding GUI control is disabled or
         completely hidden.

       • User

         Each application has a current user who is either authorised  or  unauthorised.   In  order  to  become
         authorised a user must identify themselves and authenticate that identity.

         An  arbitrary  piece of data (called a blob) can be associated with an authorised user which (with user
         manager support) can be stored securely.  This might be used, for  example,  to  store  sensitive  user
         preferences, or to implement a roaming profile.

       • User Manager

         The  user  manager  is responsible for authorising the current user and, therefore, defines how that is
         done.  It also provides information about the user population to the  policy  manager.   It  may  also,
         optionally,  provide  the  ability  to  manage the user population (eg. add or delete users).  The user
         manager must either maintain a persistent record of the user population, or interface with an  external
         user database or directory service.

         The default user manager uses password based authorisation.

         The  user  manager  persists  its data in a user database.  The default user manager provides an API so
         that different implementations of the user database can be used (for example to store the  data  in  an
         RDBMS,  or  to integrate with an existing directory service).  A default user database is provided that
         pickles the data in a local file.

       • Policy Manager

         The policy manager  is  responsible  for  assigning  permissions  to  users  and  for  determining  the
         permissions  assigned  to  the  current user.  To do this it must maintain a persistent record of those
         assignments.

         The default policy  manager  supplied  with  the  framework  uses  roles  to  make  it  easier  for  an
         administrator  to manage the relationships between permissions and users.  A role is defined as a named
         set of permissions, and a user may have one or more roles assigned to them.

         The policy manager persists its data in a policy database.  The default policy manager provides an  API
         so  that different implementations of the policy database can be used (for example to store the data in
         an RDBMS).  A default policy database is provided that pickles the data in a local file.

       • Permissions Manager

         The permissions manager is a singleton object used to get and set the current policy and user managers.

   Framework APIs
       The APIs provided by the permissions framework can be split into the following groups.

       • Application API

         This part of the API is used by application developers.

       • Policy Manager API

         This is the interface that an alternative policy manager must implement.   The  need  to  implement  an
         alternative  is  expected  to be very rare and so the API isn't covered further.  See the definition of
         the IPolicyManager interface for the details.

       • Default Policy Manager Data API

         This part of the API is used by developers to store the policy's  persistent  data  in  a  more  secure
         location (eg. on a remote server) than that provided by the default implementation.

       • User Manager API

         This  is  the  interface  that  an  alternative  user manager must implement.  The need to implement an
         alternative is expected to be very rare and so the API isn't covered further.  See  the  definition  of
         the IUserManager interface for the details.

       • Default User Manager Data API

         This part of the API is used by developers to store the user database in a more secure location (eg. on
         a remote server) than that provided by the default implementation.

       The complete API documentation is available as endo generated HTML.

   What Do I Need to Reimplement?
       The architecture of the permissions framework comprises several layers, each of which  can  reimplemented
       to meet the requirements of a particular environment.  Hopefully the following questions and answers will
       clarify what needs to be reimplemented depending on your environment.

       Q: Do you want to use roles to group permissions and assign them to users?

       A: If yes then use the supplied PolicyManager, otherwise provide your own
              IPolicyManager implementation.

       Q: Do you want users to be authenticated using a password?

       A: If yes then use the supplied UserManager, otherwise provide your own
              IUserManager implementation.

       Q: Does the IUser interface allow you to store all the user specific
              information you need?

       A: If yes then use the supplied UserDatabase, otherwise provide your own
              IUserDatabase implementation.

       Q: Do you want to store your user accounts as pickled data in a local file?

       A: If yes then use the supplied default, otherwise provide UserDatabase with
              your own IUserStorage implementation.

       Q: Do you want to store your policy data (ie. roles and role assignments) as
              pickled data in a local file?

       A: If yes then use the supplied default, otherwise provide PolicyManager with
              your own IPolicyStorage implementation.

   Deploying Alternative Managers
       The  permissions   framework   will   first   try   to   import   the   different   managers   from   the
       apptools.permissions.external namespace.  The default managers are only used if no alternative was found.
       Therefore, alternative managers should be deployed as an egg containing that namespace.

       Specifically the framework looks for the following classes:
          PolicyManager from apptools.permissions.external.policy_manager

          PolicyStorage from apptools.permissions.external.policy_storage

          UserDatabase from apptools.permissions.external.user_database

          UserManager from apptools.permissions.external.user_manager

          UserStorage from apptools.permissions.external.user_storage

       The example server is such a package that provides PolicyStorage and UserStorage implementations that use
       an XML-RPC based server to provide remote (and consequently more secure) policy and user databases.

   Using the Default Storage Implementations
       The default policy and user managers both (again by default) persist their data as pickles in local files
       called ets_perms_policydb and  ets_perms_userdb  respectively.   By  default  these  are  stored  in  the
       application's home directory (ie. that returned by ETSConfig.application_home).

       Note  that  this  directory  is  normally  in  the  user's own directory structure whereas it needs to be
       available to all users of the application.

       If the ETS_PERMS_DATA_DIR environment variable is set then its value is used instead.

       The directory must be writeable by all users of the application.

       It should be restated that the default implementations do not provide secure access  to  the  permissions
       and user data.  They are useful in a cooperative environment and as working examples.

APPLICATION API

       This  section  provides  an overview of the part of the ETS Permissions Framework API used by application
       developers.  The Permissions Framework example demonstrates the API in  use.   An  application  typically
       uses the API to do the following:

       • define permissions

       • apply permissions

       • user authentication

       • getting and setting user data

       • integrate management actions.

   Defining Permissions
       A  permission  is  the object that determines the user's access to a part of an application.  While it is
       possible to apply the same permission to more than one part of an application, it is generally a bad idea
       to do so as it makes it difficult to separate them at a later date.

       A permission has an id and a human readable description.  Permission ids must be unique.  By convention a
       dotted notation is used for ids to give them a structure.  Ids should at least be given an application or
       plugin specific prefix to ensure their uniqueness.

       Conventionally  all  an  applications  permissions  are  defined  in a single permissions.py module.  The
       following is an extract of the example's permissions.py module:

          from apptools.permissions.api import Permission

          # Add a new person.
          NewPersonPerm = Permission(id='ets.permissions.example.person.new',
                  description=u"Add a new person")

          # Update a person's age.
          UpdatePersonAgePerm = Permission(id='ets.permissions.example.person.age.update',
                  description=u"Update a person's age")

          # View or update a person's salary.
          PersonSalaryPerm = Permission(id='ets.permissions.example.person.salary',
                  description=u"View or update a person's salary")

   Applying Permissions
       Permissions are applied to different parts of an applications GUI.  When the  user  has  been  granted  a
       permission  then  the  corresponding  part  of  the GUI is displayed normally.  When the user is denied a
       permission then the corresponding part of the GUI is disabled or completely hidden.

       Permissions can be applied to TraitsUI  view  items  and  to  any  object  which  can  be  wrapped  in  a
       SecureProxy.

   TraitsUI View Items
       Items  in TraitsUI views have enabled_when and visible_when traits that are evaluated to determine if the
       item should be enabled or visible respectively.  These are used  to  apply  permissions  by  storing  the
       relevant  permissions  in  the  model  so  that  they  are  available  to the view.  The enabled_when and
       visible_when  traits  then  simply  reference  the  permission's  granted  trait.   The   granted   trait
       automatically reflects whether or not the user currently has the corresponding permission.

       In  order  for  the view to be correctly updated when the user's permissions change (ie. when they become
       authenticated) the view must use the SecureHandler handler.  This handler is a simple  sub-class  of  the
       standard Traits Handler class.

       The  following  extract  from  the example shows a default view of the Person object that enables the age
       item when the user has the UpdatePersonAgePerm permission and shows the salary item when the user has the
       PersonSalaryPerm permission:

          from apptools.permissions.api import SecureHandler
          from traits.api import HasTraits, Int, Unicode
          from traitsui.api import Item, View

          from permissions import UpdatePersonAgePerm, PersonSalaryPerm

          class Person(HasTraits):
              """A simple example of an object model"""

              # Name.
              name = Unicode

              # Age in years.
              age = Int

              # Salary.
              salary = Int

              # Define the default view with permissions attached.
              age_perm = UpdatePersonAgePerm
              salary_perm = PersonSalaryPerm

              traits_view = View(
                      Item(name='name'),
                      Item(name='age', enabled_when='object.age_perm.granted'),
                      Item(name='salary', visible_when='object.salary_perm.granted'),
                      handler=SecureHandler)

   Wrapping in a SecureProxy
       Any  object can have permissions applied by wrapping it in a SecureProxy object.  An adapter is used that
       manages the enabled and visible states of the proxied object according to the current user's permissions.
       Otherwise the proxy behaves just like the object being proxied.

       Adapters are included for the following types of object:

       • PyFace actions

       • PyFace widgets FIXME: TODO

       • Qt widgets

       • wx widgets

       See Writing SecureProxy Adapters for a description of how to write adapters for other types of objects.

       The following extract from the example shows the wrapping of a standard PyFace action and the application
       of the NewPersonPerm permission:

          from apptools.permissions.api import SecureProxy

          from permissions import NewPersonPerm

          ...

              def _new_person_action_default(self):
                  """Trait initializer."""

                  # Create the action and secure it with the appropriate permission.
                  act = Action(name='New Person', on_perform=self._new_person)
                  act = SecureProxy(act, permissions=[NewPersonPerm])

                  return act

       A SecureProxy also accepts a show argument that, when set to False, hides  the  object  when  it  becomes
       disabled.

   Authenticating the User
       The  user manager supports the concept of the current user and is responsible for authenticating the user
       (and subsequently unauthorising the user if required).

       The code fragment to authenticate the current user is:

          from apptools.permissions.api import get_permissions_manager

          get_permissions_Manager().user_manager.authenticate_user()

       Unauthorising the current user is done using the unauthenticate_user() method.

       As a convenience two PyFace actions, called LoginAction and LogoutAction, are provided  that  wrap  these
       two methods.

       As a further convenience a PyFace menu manager, called UserMenuManager, is provided that contains all the
       user and management actions (see below) in the permissions framework.  This is used by the example.

       The user menu, login and logout actions can be imported from apptools.permissions.action.api.

   Getting and Setting User Data
       The user manager has a user trait that is an object that implements the  IUser  interface.   It  is  only
       valid once the user has been authenticated.

       The  IUser  interface has a blob trait that holds any binary data (as a Python string).  The data will be
       read when the user is authenticated.  The data will be written whenever it is changed.

   Integrating Management Actions
       Both policy and user managers can provide actions that provide access to  various  management  functions.
       Both  have  a  management_actions  trait that is a list of PyFace actions that invoke appropriate dialogs
       that allow the user to manage the policy and the user population appropriately.

       User managers also have a user_actions trait that is a list of PyFace  actions  that  invoke  appropriate
       dialogs  that  allow  the  user  to manage themselves.  For example, the default user manager provides an
       action that allows a user to change their password.

       The default policy manager provides actions that  allows  roles  to  be  defined  in  terms  of  sets  of
       permissions, and allows users to be assigned one or more roles.

       The  default  user  manager provides actions that allows users to be added, modified and deleted.  A user
       manager that integrates with an enterprise's secure directory service  may  not  provide  any  management
       actions.

       All management actions have appropriate permissions attached to them.

   Writing SecureProxy Adapters
       SecureProxy  will  automatically  handle  most of the object types you will want to apply permissions to.
       However it is possible to implement additional adapters to support other object types.  To  do  this  you
       need to implement a sub-class of AdapterBase and register it.

       Adapters  tend  to  be  one  of  two  styles according to how the object's enabled and visible states are
       changed.  If the states are changed via attributes (typically Traits based objects) then the adapter will
       cause  a  proxy  to  be created for the object.  If the states are changed via methods (typically toolkit
       widgets) then the adapter will probably modify the object itself.  We will refer to these two  styles  as
       wrapping adapters and patching adapters respectively.

       The following gives a brief overview of the AdapterBase class:

       proxied
              This instance attribute is a reference to the original object.

       register_adapter(adapter, type, type, ...)
              This  is a class method that is used to register your adapter and one or more object types that it
              handles.

       adapt()
              This is a method that should be reimplemented by patching adapters.  (The  default  implementation
              will  cause  a  proxy  to  be  created  for wrapping adapters.)  This is where any patching of the
              proxied attribute is done.  The object returned  will  be  returned  by  SecureProxy()  and  would
              normally be the patched object - but can be any object.

       setattr(name, value)
              This  method  should  be  reimplemented  by wrapping adapters to intercept the setting of relevant
              attributes of the proxied object.  The default implementation should be used as the  fallback  for
              irrelevant attributes.

       get_enabled()
              This method must be reimplemented to return the current enabled state.

       set_enabled(value)
              This method must be reimplemented to set the enabled state to the given value.

       update_enabled(value)
              This  method  is called by your adapter to set the desired value of the enabled state.  The actual
              state set will depend on the current user's permissions.

       get_visible()
              This method must be reimplemented to return the current visible state.

       set_visible(value)
              This method must be reimplemented to set the visible state to the given value.

       update_visible(value)
              This method is called by your adapter to set the desired value of the visible state.   The  actual
              state set will depend on the current user's permissions.

       The AdapterBase class is defined in adapter_base.py.

       The PyFace action adapter is an example of a wrapping adapter.

       The PyQt widget adapter is an example of a patching adapter.

DEFAULT POLICY MANAGER DATA API

       This section provides an overview of the part of the ETS Permissions Framework API used by developers who
       want to store a policy manager's persistent data in a more secure location (eg.  a  remote  server)  than
       that provided by the default implementation.

       The API is defined by the default policy manager which uses roles to make it easier to assign permissions
       to users.  If this API isn't sufficiently flexible, or if roles are inappropriate,  then  an  alternative
       policy manager should be implemented.

       The  API  is fully defined by the IPolicyStorage interface.  The default implementation of this interface
       stores the policy database as a pickle in a local file.

   Overview of IPolicyStorage
       The IPolicyStorage interface defines a number of methods that must be implemented to read  and  write  to
       the policy database.  The methods are designed to be implemented using simple SQL statements.

       In the event of an error a method must raise the PolicyStorageError exception.  The string representation
       of the exception is used as an error message that is displayed to the user.

DEFAULT USER MANAGER DATA API

       This section provides an overview of the part of the ETS Permissions Framework API used by developers who
       want  to  store a user database in a more secure location (eg. a remote server) than that provided by the
       default implementation.

       The API is defined by the default user manager which uses password  based  authorisation.   If  this  API
       isn't  sufficiently flexible, or if another method of authorisation is used (biometrics for example) then
       an alternative user manager should be implemented.

       The API is fully defined by the IUserDatabase interface.  This allows user databases  to  be  implemented
       that  extend  the  IUser interface and store additional user related data.  If the user database is being
       persisted in secure storage (eg. a remote RDBMS) then this could be used to  store  sensitive  data  (eg.
       passwords for external systems) that shouldn't be stored as ordinary preferences.

       In  most  cases  there  will be no requirement to store additional user related data than that defined by
       IUser so the supplied UserDatabase implementation (which provides all the GUI code required to  implement
       the  IUserDatabase  interface)  can be used.  The UserDatabase implementation delegates the access to the
       user database to an object implementing the IUserStorage interface.  The default implementation  of  this
       interface stores the user database as a pickle in a local file.

   Overview of IUserStorage
       The  IUserStorage interface defines a number of methods that must be implemented to read and write to the
       user database.  The methods are designed to be implemented using simple SQL statements.

       In the event of an error a method must raise the UserStorageError exception.  The  string  representation
       of the exception is used as an error message that is displayed to the user.

   Overview of IUserDatabase
       The  IUserDatabase  interface  defines  a  set of Bool traits, all beginning with can_, that describe the
       capabilities of a  particular  implementation.   For  example,  the  can_add_user  trait  is  set  by  an
       implementation if it supports the ability to add a new user to the database.

       Each  of  these  capability traits has a corresponding method which has the same name except for the can_
       prefix.  The method only needs to be implemented if the corresponding traits is True.   The  method,  for
       example add_user() is called by the user manager to implement the capability.

       The interface has two other methods.

       The  bootstrapping()  method is called by the user manager to determine if the database is bootstrapping.
       Typically this is when the database is empty and  no  users  have  yet  been  defined.   The  permissions
       framework  treats this situation as a special case and is able to relax the enforcement of permissions to
       allow users and permissions to be initially defined.

       The user_factory() method is called by the user manager to create a new user object, ie. an  object  that
       implements  the  IUser  interface.  This allows an implementation to extend the IUser interface and store
       additional user related data in the object if the blob trait proves insufficient.

PREFERENCES

       The preferences package provides a simple API for managing application preferences. The  classes  in  the
       package  are  implemented  using  a  layered  approach  where the lowest layer provides access to the raw
       preferences mechanism and each layer on top providing more convenient ways  to  get  and  set  preference
       values.

THE BASIC PREFERENCES MECHANISM

       Lets  start  by  taking  a  look at the lowest layer which consists of the IPreferences interface and its
       default implementation in the Preferences class. This layer implements the basic preferences system which
       is a hierarchical arrangement of preferences 'nodes' (where each node is simply an object that implements
       the IPreferences interface). Nodes in the hierarchy can contain preference settings and/or  child  nodes.
       This  layer  also  provides  a  default  way  to read and write preferences from the filesystem using the
       excellent ConfigObj package.

       This all sounds a bit complicated but, believe me, it isn't! To prove it  (hopefully)  lets  look  at  an
       example. Say I have the following preferences in a file 'example.ini':

          [acme.ui]
          bgcolor = blue
          width = 50
          ratio = 1.0
          visible = True

          [acme.ui.splash_screen]
          image = splash
          fgcolor = red

       I can create a preferences hierarchy from this file by:

          >>> from apptools.preferences.api import Preferences
          >>> preferences = Preferences(filename='example.ini')
          >>> preferences.dump()

           Node() {}
              Node(acme) {}
                Node(ui) {'bgcolor': 'blue', 'ratio': '1.0', 'width': '50', 'visible': 'True'}
                  Node(splash_screen) {'image': 'splash', 'fgcolor': 'red'}

       The  'dump'  method  (useful  for  debugging  etc)  simply  'pretty  prints' a preferences hierarchy. The
       dictionary next to each node contains the node's actual preferences. In this case,  the  root  node  (the
       node  with  no  name) is the preferences object that we created. This node now has one child node 'acme',
       which contains no preferences. The 'acme' node has one child, 'ui', which contains some preferences (e.g.
       'bgcolor') and also a child node 'splash_screen' which also contains preferences (e.g. 'image').

       To look up a preference we use:

          >>> preferences.get('acme.ui.bgcolor')
          'blue'

       If no such preferences exists then, by default, None is returned:

          >>> preferences.get('acme.ui.bogus') is None
          True

       You can also specify an explicit default value:

          >>> preferences.get('acme.ui.bogus', 'fred')
          'fred'

       To set a preference we use:

          >>> preferences.set('acme.ui.bgcolor', 'red')
          >>> preferences.get('acme.ui.bgcolor')
          'red'

       And to make sure the preferences are saved back to disk:

          >>> preferences.flush()

       To add a new preference value we simply set it:

          >>> preferences.set('acme.ui.fgcolor', 'black')
          >>> preferences.get('acme.ui.fgcolor')
          'black'

       Any missing nodes in a call to 'set' are created automatically, hence:

          >>> preferences.set('acme.ui.button.fgcolor', 'white')
          >>> preferences.get('acme.ui.button.fgcolor')
          'white'

       Preferences  can  also  be  'inherited'.  e.g.  Notice  that  the 'splash_screen' node does not contain a
       'bgcolor' preference, and hence:

          >>> preferences.get('acme.ui.splash_screen.bgcolor') is None
          True

       But if we allow the 'inheritance' of preference values then:

          >>> preferences.get('acme.ui.splash_screen.bgcolor', inherit=True)
          'red'

       By using 'inheritance' here the preferences system will try the following preferences:

          'acme.ui.splash_screen.bgcolor'
          'acme.ui.bgcolor'
          'acme.bgcolor'
          'bgcolor'

   Strings, Glorious Strings
       At this point it is worth mentioning that preferences are always stored and returned as strings. This  is
       because  of  the  limitations  of  the  traditional  '.ini'  file format i.e. they don't contain any type
       information! Now before you start panicking, this doesn't mean that all of your preferences  have  to  be
       strings!  Currently  the preferences system allows, strings(!), booleans, ints, longs, floats and complex
       numbers. When you store a non-string value it gets converted to a string for you, but you  always  get  a
       string back:

          >>> preferences.get('acme.ui.width')
          '50'
          >>> preferences.set('acme.ui.width', 100)
          >>> preferences.get('acme.ui.width')
          '100'

          >>> preferences.get('acme.ui.visible')
          'True'
          >>> preferences.set('acme.ui.visible', False)
          >>> preferences.get('acme.ui.visible')
          'False'

       This  is  obviously not terribly convenient, and so the following section discusses how we associate type
       information with our preferences to make getting and setting them more natural.

PREFERENCES AND TYPES

       As mentioned previously, we would like to be able to  get  and  set  non-string  preferences  in  a  more
       convenient way. This is where the PreferencesHelper class comes in.

       Let's take another look at 'example.ini':

          [acme.ui]
          bgcolor = blue
          width = 50
          ratio = 1.0
          visible = True

          [acme.ui.splash_screen]
          image = splash
          fgcolor = red

       Say,  I  am  interested  in  the  preferences in the 'acme.ui' section. I can use a preferences helper as
       follows:

          from apptools.preferences.api import PreferencesHelper

          class SplashScreenPreferences(PreferencesHelper):
              """ A preferences helper for the splash screen. """

              PREFERENCES_PATH = 'acme.ui'

              bgcolor = Str
              width   = Int
              ratio   = Float
              visible = Bool

          >>> preferences = Preferences(filename='example.ini')
          >>> helper = SplashScreenPreferences(preferences=preferences)
          >>> helper.bgcolor
          'blue'
          >>> helper.width
          100
          >>> helper.ratio
          1.0
          >>> helper.visible
          True

       And, obviously, I can set the value of the preferences via the helper too:

          >>> helper.ratio = 0.5

       And if you want to prove to yourself it really did set the preference:

          >>> preferences.get('acme.ui.ratio')
          '0.5'

       Using a preferences helper you also get notified via the usual trait mechanism when the  preferences  are
       changed (either via the helper or via the preferences node directly:

          def listener(obj, trait_name, old, new):
              print trait_name, old, new

          >>> helper.on_trait_change(listener)
          >>> helper.ratio = 0.75
          ratio 0.5 0.75
          >>> preferences.set('acme.ui.ratio', 0.33)
          ratio 0.75 0.33

       If  you  always  use  the same preference node as the root of your preferences you can also set the class
       attribute 'PreferencesHelper.preferences' to be that node and from then on in, you don't have to  pass  a
       preferences collection in each time you create a helper:

          >>> PreferencesHelper.preferences = Preferences(filename='example.ini')
          >>> helper = SplashScreenPreferences()
          >>> helper.bgcolor
          'blue'
          >>> helper.width
          100
          >>> helper.ratio
          1.0
          >>> helper.visible
          True

SCOPED PREFERENCES

       In  many  applications the idea of preferences scopes is useful. In a scoped system, an actual preference
       value can be stored in any scope and when a call is made to the 'get' method the scopes are  searched  in
       order of precedence.

       The default implementation (in the ScopedPreferences class) provides two scopes by default:

       1. The application scope

       This scope stores itself in the 'ETSConfig.application_home' directory. This scope is generally used when
       setting any user preferences.

       2. The default scope

       This scope is transient (i.e. it does not store itself anywhere). This scope is generally  used  to  load
       any predefined default values into the preferences system.

       If  you  are happy with the default arrangement, then using the scoped preferences is just like using the
       plain old non-scoped version:

          >>> from apptools.preferences.api import ScopedPreferences
          >>> preferences = ScopedPreferences(filename='example.ini')
          >>> preferences.load('example.ini')
          >>> p.dump()

            Node() {}
              Node(application) {}
                Node(acme) {}
                  Node(ui) {'bgcolor': 'blue', 'ratio': '1.0', 'width': '50', 'visible': 'True'}
                    Node(splash_screen) {'image': 'splash', 'fgcolor': 'red'}
              Node(default) {}

       Here you can see that the root node now has a child node representing each scope.

       When we are getting and setting preferences using scopes we generally want the following behaviour:

       a) When we get a preference we want to look it up in each scope in order. The first scope that contains a
       value 'wins'.

       b) When we set a preference, we want to set it in the first scope. By default this means that when we set
       a preference it will be set in the application scope. This is exactly what we  want  as  the  application
       scope is the scope that is persistent.

       So usually, we just use the scoped preferences as before:

          >>> preferences.get('acme.ui.bgcolor')
          'blue'
          >>> preferences.set('acme.ui.bgcolor', 'red')
          >>> preferences.dump()

            Node() {}
              Node(application) {}
                Node(acme) {}
                  Node(ui) {'bgcolor': 'red', 'ratio': '1.0', 'width': '50', 'visible': 'True'}
                    Node(splash_screen) {'image': 'splash', 'fgcolor': 'red'}
              Node(default) {}

       And, conveniently, preference helpers work just the same with scoped preferences too:

          >>> PreferencesHelper.preferences = ScopedPreferences(filename='example.ini')
          >>> helper = SplashScreenPreferences()
          >>> helper.bgcolor
          'blue'
          >>> helper.width
          100
          >>> helper.ratio
          1.0
          >>> helper.visible
          True

   Accessing a particular scope
       Should  you  care  about getting or setting a preference in a particular scope then you use the following
       syntax:

          >>> preferences.set('default/acme.ui.bgcolor', 'red')
          >>> preferences.get('default/acme.ui.bgcolor')
          'red'
          >>> preferences.dump()

            Node() {}
              Node(application) {}
                Node(acme) {}
                  Node(ui) {'bgcolor': 'red', 'ratio': '1.0', 'width': '50', 'visible': 'True'}
                    Node(splash_screen) {'image': 'splash', 'fgcolor': 'red'}
              Node(default) {}
                Node(acme) {}
                  Node(ui) {'bgcolor': 'red'}

       You can also get hold of a scope via:

          >>> default = preferences.get_scope('default')

       And then perform any of the usual operations on it.

FURTHER READING

       So that's a quick tour around the basic useage of the preferences API. For more imformation about what is
       provided take a look at the API documentation.

       If you are using Envisage to build your applications then you might also be interested in the Preferences
       in Envisage section.

PREFERENCES IN ENVISAGE

       This section discusses how an Envisage application uses the preferences mechanism. Envisage tries not  to
       dictate  too  much,  and  so  this  describes  the  default behaviour, but you are free to override it as
       desired.

       Envisage uses the default implementation of the ScopedPreferences class which is made available  via  the
       application's 'preferences' trait:

          >>> application = Application(id='myapplication')
          >>> application.preferences.set('acme.ui.bgcolor', 'yellow')
          >>> application.preferences.get('acme.ui.bgcolor')
          'yellow'

       Hence, you use the Envisage preferences just like you would any other scoped preferences.

       It  also  registers itself as the default preferences node used by the PreferencesHelper class. Hence you
       don't need to provide a preferences node explicitly to your helper:

          >>> helper = SplashScreenPreferences()
          >>> helper.bgcolor
          'blue'
          >>> helper.width
          100
          >>> helper.ratio
          1.0
          >>> helper.visible
          True

       The only extra thing that Envisage does for you is to provide an  extension  point  that  allows  you  to
       contribute  any  number  of  '.ini'  files that are loaded into the default scope when the application is
       started.

       e.g. To contribute a preference file for my plugin I might use:

          class MyPlugin(Plugin):
              ...

              @contributes_to('envisage.preferences')
              def get_preferences(self, application):
                  return ['pkgfile://mypackage:preferences.ini']

AUTOMATIC SCRIPT RECORDING

       This package provides a very handy and powerful Python script recording facility.  This can be used to:

          • record all actions performed on a traits based UI into a human readable, Python script  that  should
            be able to recreate your UI actions.

          • easily learn the scripting API of an application.

       This  package  is not just a toy framework and is powerful enough to provide full script recording to the
       Mayavi application.  Mayavi is a powerful 3D visualization tool that is part of ETS.

   The scripting API
       The scripting API primarily allows you to record UI actions for objects that  have  Traits.   Technically
       the  framework  listens  to all trait changes so will work outside a UI.  We do not document the full API
       here, the best place to look for that is the apptools.scripting.recorder module which is reasonably  well
       documented.  We provide a high level overview of the library.

       The quickest way to get started is to look at a small example.

   A tour by example
       The  following  example  is  taken  from the test suite.  Consider a set of simple objects organized in a
       hierarchy:

          from traits.api import (HasTraits, Float, Instance,
                  Str, List, Bool, HasStrictTraits, Tuple, Range, TraitPrefixMap,
                  Trait)
          from apptools.scripting.api import (Recorder, recordable,
              set_recorder)

          class Property(HasStrictTraits):
              color = Tuple(Range(0.0, 1.0), Range(0.0, 1.0), Range(0.0, 1.0))
              opacity = Range(0.0, 1.0, 1.0)
              representation = Trait('surface',
                                     TraitPrefixMap({'surface':2,
                                                     'wireframe': 1,
                                                     'points': 0}))
          class Toy(HasTraits):
              color = Str
              type = Str
              # Note the use of the trait metadata to ignore this trait.
              ignore = Bool(False, record=False)

          class Child(HasTraits):
              name = Str('child')
              age = Float(10.0)
              # The recorder walks through sub-instances if they are marked
              # with record=True
              property = Instance(Property, (), record=True)
              toy = Instance(Toy, record=True)
              friends = List(Str)

              # The decorator records the method.
              @recordable
              def grow(self, x):
                  """Increase age by x years."""
                  self.age += x

          class Parent(HasTraits):
              children = List(Child, record=True)
              recorder = Instance(Recorder, record=False)

       Using these simple classes we first create a simple object hierarchy as follows:

          p = Parent()
          c = Child()
          t = Toy()
          c.toy = t
          p.children.append(c)

       Given this hierarchy, we'd like to be able to record a  script.   To  do  this  we  setup  the  recording
       infrastructure:

          from mayavi.core.recorder import Recorder, set_recorder
          # Create a recorder.
          r = Recorder()
          # Set the global recorder so the decorator works.
          set_recorder(r)
          r.register(p)
          r.recording = True

       The  key  method  here is the r.register(p) call above.  It looks at the traits of p and finds all traits
       and nested objects that specify a record=True in their trait metadata (all methods  starting  and  ending
       with  _ are ignored).  All sub-objects are in turn registered with the recorder and so on.  Callbacks are
       attached to traits changes and these  are  wired  up  to  produce  readable  and  executable  code.   The
       set_recorder(r)  call is also very important and sets the global recorder so the framework listens to any
       functions that are decorated with the recordable decorator.

       Now lets test this out like so:

          # The following will be recorded.
          c.name = 'Shiva'
          c.property.representation = 'w'
          c.property.opacity = 0.4
          c.grow(1)

       To see what's been recorded do this:

          print r.script

       This prints:

          child = parent.children[0]
          child.name = 'Shiva'
          child.property.representation = 'wireframe'
          child.property.opacity = 0.40000000000000002
          child.grow(1)

       The recorder internally maintains a mapping between objects and unique names for each  object.   It  also
       stores  the  information about the location of a particular object in the object hierarchy.  For example,
       the path to the Toy instance in the hierarchy above  is  parent.children[0].toy.   Since  scripting  with
       lists this way can be tedious, the recorder first instantiates the child:

          child = parent.children[0]

       Subsequent  lines  use the child attribute.  The recorder always tries to instantiate the object referred
       to using its path information in this manner.

       To record a function or method call one must simply decorate  the  function/method  with  the  recordable
       decorator.   Nested recordable functions are not recorded and trait changes are also not recorded if done
       inside a recordable function.

       NOTE:

          1. It is very important to note that the global recorder must be set via the set_recorder method.  The
             recordable decorator relies on this being set to work.

          2. The recordable decorator will work with plain Python classes and with functions too.

       To stop recording do this:

          r.unregister(p)
          r.recording = False

       The r.unregister(p) reverses the r.register(p) call and unregisters all nested objects as well.

   Advanced use cases
       Here are a few advanced use cases.

          • The  API  also provides a RecorderWithUI class that provides a simple user interface that prints the
            recorded script and allows the user to save the script.

          • Sometimes it is not enough to just record trait changes, one may want to pass an arbitrary string or
            command  when  recording  is  occurring.   To allow for this, if one defines a recorder trait on the
            object, it is set to the current recorder.  One can then use this recorder to do whatever one wants.
            This is very convenient.

          • To ignore specific traits one must specify either a record=False metadata to the trait definition or
            specify a list of strings to the register method in the ignore keyword argument.

          • If you want to use a specific name for an object on the script you can pass the script_id  parameter
            to the register function.

       For  more  details  on  the recorder itself we suggest reading the module source code.  It is fairly well
       documented and with the above background should be enough to get you going.

UNDO FRAMEWORK

       The Undo Framework is a component of the Enthought Tool Suite that provides developers with an  API  that
       implements the standard pattern for do/undo/redo commands.

       The  framework  is  completely  configurable.   Alternate  implementations of all major components can be
       provided if necessary.

   Framework Concepts
       The following are the concepts supported by the framework.

       • Command

         A command is an application defined operation that can be done (i.e.  executed), undone (i.e. reverted)
         and redone (i.e. repeated).

         A command operates on some data and maintains sufficient state to allow it to revert or repeat a change
         to the data.

         Commands may be merged so that potentially long sequences of similar commands (e.g. to add a  character
         to some text) can be collapsed into a single command (e.g. to add a word to some text).

       • Macro

         A macro is a sequence of commands that is treated as a single command when being undone or redone.

       • Command Stack

         A  command  is  done  by pushing it onto a command stack.  The last command can be undone and redone by
         calling appropriate command stack methods.  It is also possible to move the  stack's  position  to  any
         point and the command stack will ensure that commands are undone or redone as required.

         A  command  stack  maintains a clean state which is updated as commands are done and undone.  It may be
         explicitly set, for example when the data being manipulated by the commands is saved to disk.

         Canned PyFace actions are provided as wrappers around command stack methods to  implement  common  menu
         items.

       • Undo Manager

         An  undo  manager  is  responsible  for  one  or  more  command stacks and maintains a reference to the
         currently active stack.  It provides convenience undo and redo methods that operate  on  the  currently
         active stack.

         An undo manager ensures that each command execution is allocated a unique sequence number, irrespective
         of which command stack it is pushed to.  Using this it is  possible  to  synchronise  multiple  command
         stacks and restore them to a particular point in time.

         An  undo manager will generate an event whenever the clean state of the active stack changes.  This can
         be used to maintain some sort of GUI status indicator to  tell  the  user  that  their  data  has  been
         modified since it was last saved.

       Typically  an  application  will  have one undo manager and one undo stack for each data type that can be
       edited.  However this is not a requirement: how the command  stack's  in  particular  are  organised  and
       linked (with the user manager's sequence number) can need careful thought so as not to confuse the user -
       particularly in a plugin based application that may have many editors.

       To support this typical usage the PyFace Workbench class has an undo_manager trait and the PyFace  Editor
       class has a command_stack trait.  Both are lazy loaded so can be completely ignored if they are not used.

   API Overview
       This  section  gives  a brief overview of the various classes implemented in the framework.  The complete
       API documentation is available as endo generated HTML.

       The example application demonstrates all the major features of the framework.

   UndoManager
       The UndoManager class is the default implementation of the IUndoManager interface.

       active_stack
              This trait is a reference to the currently active command stack and may be None.  Typically it  is
              set when some sort of editor becomes active.

       active_stack_clean
              This boolean trait reflects the clean state of the currently active command stack.  It is intended
              to support a "document modified" indicator in the GUI.  It is maintained by the undo manager.

       stack_updated
              This event is fired when the index of a command stack is changed.  A reference  to  the  stack  is
              passed as an argument to the event and may not be the currently active stack.

       undo_name
              This Unicode trait is the name of the command that can be undone, and will be empty if there is no
              such command.  It is maintained by the undo manager.

       redo_name
              This Unicode trait is the name of the command that can be redone, and will be empty if there is no
              such command.  It is maintained by the undo manager.

       sequence_nr
              This  integer  trait is the sequence number of the next command to be executed.  It is incremented
              immediately before a command's do() method is called.  A particular sequence number identifies the
              state  of  all command stacks handled by the undo manager and allows those stacks to be set to the
              point they were at at a particular point in time.  In other  words,  the  sequence  number  allows
              otherwise independent command stacks to be synchronised.

       undo() This method calls the undo() method of the last command on the active command stack.

       redo() This method calls the redo() method of the last undone command on the active command stack.

   CommandStack
       The CommandStack class is the default implementation of the ICommandStack interface.

       clean  This  boolean traits reflects the clean state of the command stack.  Its value changes as commands
              are executed, undone and redone.  It may also be explicitly set to mark the current stack position
              as being clean (when data is saved to disk for example).

       undo_name
              This Unicode trait is the name of the command that can be undone, and will be empty if there is no
              such command.  It is maintained by the command stack.

       redo_name
              This Unicode trait is the name of the command that can be redone, and will be empty if there is no
              such command.  It is maintained by the command stack.

       undo_manager
              This trait is a reference to the undo manager that manages the command stack.

       push(command)
              This  method executes the given command by calling its do() method.  Any value returned by do() is
              returned by push().  If the command couldn't be merged with the previous one then it is  saved  on
              the command stack.

       undo(sequence_nr=0)
              This  method  undoes the last command.  If a sequence number is given then all commands are undone
              up to an including the sequence number.

       redo(sequence_nr=0)
              This method redoes the last command and returns any result.  If a sequence number  is  given  then
              all commands are redone up to an including the sequence number and any result of the last of these
              is returned.

       clear()
              This method clears the command stack, without undoing or redoing  any  commands,  and  leaves  the
              stack in a clean state.  It is typically used when all changes to the data have been abandoned.

       begin_macro(name)
              This  method begins a macro by creating an empty command with the given name.  The commands passed
              to all subsequent calls to push()  will  be  contained  in  the  macro  until  the  next  call  to
              end_macro().   Macros  may be nested.  The command stack is disabled (ie. nothing can be undone or
              redone) while a macro is being created (ie. while there is an outstanding end_macro() call).

       end_macro()
              This method ends the current macro.

   ICommand
       The ICommand interface defines the interface that must be implemented by any undoable/redoable command.

       data   This optional trait is a reference to the data object that the command operates  on.   It  is  not
              used by the framework itself.

       name   This  Unicode  trait  is the name of the command as it will appear in any GUI element (e.g. in the
              text of an undo and redo menu entry).  It may include & to indicate a keyboard shortcut which will
              be automatically removed whenever it is inappropriate.

       __init__(*args)
              If  the  command  takes  arguments then the command must ensure that deep copies should be made if
              appropriate.

       do()   This method is called by a command stack to execute the command and to  return  any  result.   The
              command must save any state necessary for the undo() and redo() methods to work.  It is guaranteed
              that this will only ever be called once and that it will be called before any call  to  undo()  or
              redo().

       undo() This method is called by a command stack to undo the command.

       redo() This method is called by a command stack to redo the command and to return any result.

       merge(other)
              This method is called by the command stack to try and merge the other command with this one.  True
              should be returned if the commands were merged.  If the commands are merged then other will not be
              placed  on  the  command  stack.  A subsequent undo or redo of this modified command must have the
              same effect as the two original commands.

   AbstractCommand
       AbstractCommand is an abstract base class that implements the ICommand interface.  It provides a  default
       implementation of the merge() method.

   CommandAction
       The CommandAction class is a sub-class of the PyFace Action class that is used to wrap commands.

       command
              This  callable trait must be set to a factory that will return an object that implements ICommand.
              It will be called when the action is invoked and the object created pushed onto the command stack.

       command_stack
              This instance trait must be set to the command stack that  commands  invoked  by  the  action  are
              pushed to.

       data   This  optional  trait is a reference to the data object that will be passed to the command factory
              when it is called.

   UndoAction
       The UndoAction class is a canned PyFace action that undoes the last command of the active command stack.

   RedoAction
       The RedoAction class is a canned PyFace action that redoes the last command undone of the active  command
       stack.

THE SELECTION SERVICE

       It  is quite common in GUI applications to have a UI element displaying a collection of items that a user
       can select ("selection providers"), while other parts of the application must react  to  changes  in  the
       selection ("selection listeners").

       Ideally, the listeners would not have a direct dependency on the UI object.  This is especially important
       in extensible envisage applications, where a plugin might need to react to a selection change, but we  do
       not want to expose the internal organization of the application to external developers.

       This package defines a selection service that manages the communication between providers and listener.

   The SelectionService object
       The  SelectionService  object  is  the  central  manager that handles the communication between selection
       providers and listener.

       Selection providers are components that wish to publish information about  their  current  selection  for
       public  consumption.   They  register  to  a  selection service instance when they first have a selection
       available (e.g., when the UI showing a list of selectable items is initialized), and un-register as  soon
       as the selection is not available anymore (e.g., the UI is destroyed when the windows is closed).

       Selection listeners can query the selection service to get the current selection published by a provider,
       using the provider unique ID.

       The service acts as a broker between providers and listeners, making sure that they are notified when the
       selection event is fired.

   Selection providers
       Any  object  can  become  a  selection  provider  by  implementing  the ISelectionProvider interface, and
       registering to the selection service.

       Selection providers must provide a unique ID provider_id, which is  used  by  listeners  to  request  its
       current selection.

       Whenever its selection changes, providers fire a selection event. The content of the event is an instance
       implementing ISelection that contains information about the selected items.  For example, a ListSelection
       object contains a list of selected items, and their indices.

       Selection  providers  can  also be queried directly about their current selection using the get_selection
       method, and can be requested to change their selection to a new one with the set_selection method.

   Registration
       Selection  providers  publish  their  selection  by  registering  to  the  selection  service  using  the
       add_selection_provider  method.  When  the  selection  is no longer available, selection providers should
       un-register through remove_selection_provider.

       Typically, selection providers are UI objects showing a list or tree of items, they register as  soon  as
       the  UI  component  is initialized, and un-register when the UI component disappears (e.g., because their
       window has been closed).  In more complex applications, the registration could be done  by  a  controller
       object instead.

   Selection listeners
       Selection  listeners  request  information  regarding the current selection of a selection provider given
       their provider ID. The SelectionService supports two distinct use cases:

          1. Passively listening to selection changes: listener connect to a specific provider and are  notified
             when the provider's selection changes.

          2. Actively  querying a provider for its current selection: the selection service can be used to query
             a provider using its unique ID.

   Passive listening
       Listeners connect to the selection events for  a  given  provider  using  the  connect_selection_listener
       method.  They  need to provide the unique ID of the provider, and a function (or callable) that is called
       to send the event. This callback function takes one argument, an implementation of  the  ISelection  that
       represents the selection.

       It  is  possible  for  a  listener  to  connect  to a provider ID before it is registered. As soon as the
       provider is registered, the listener will  receive  a  notification  containing  the  provider's  initial
       selection.

       To disconnect a listener use the methods disconnect_selection_listener.

   Active querying
       In  other  instances,  an element of the application only needs the current selection at a specific time.
       For example, a toolbar button could open dialog representing a user action based  on  what  is  currently
       selected in the active editor.

       The  get_selection method calls the corresponding method on the provider with the given ID and returns an
       ISelection instance.

   Setting a selection
       Finally, it is possible to request a provider to set its  selection  to  a  given  set  of  objects  with
       set_selection.   The  main  use case for this method is multiple views of the same list of objects, which
       need to keep their selection synchronized.

       If the items specified in the arguments are not available in the provider,  a  ProviderNotRegisteredError
       is raised, unless the optional keyword argument ignore_missing is set to True.

   API Reference
   apptools.selection Package
       Users  of  the  apptools.selection package can access the objects that are part of the public API through
       the convenience apptools.selection.api.

   selection_service Module
       class apptools.selection.selection_service.SelectionService
              Bases: traits.has_traits.HasTraits

              The selection service connects selection providers and listeners.

              The selection service is a register of selection  providers,  i.e.,  objects  that  publish  their
              current selection.

              Selections can be requested actively, by explicitly requesting the current selection in a provider
              (get_selection(id)()), or passively by connecting selection listeners.

              add_selection_provider(provider)
                     Add a selection provider.

                     The provider is identified by its ID. If a provider with  the  same  ID  has  been  already
                     registered, an IDConflictError is raised.

                     Arguments:

                            provider -- ISelectionProvider
                                   The selection provider added to the internal registry.

              connect_selection_listener(provider_id, func)
                     Connect a listener to selection events from a specific provider.

                     The signature if the listener callback is func(i_selection).  The listener is called:

                     1. When a provider with the given ID is registered, with its initial selection as argument,
                        or

                     2. whenever the provider fires a selection event.

                     It is perfectly valid to connect a  listener  before  a  provider  with  the  given  ID  is
                     registered. The listener will remain connected even if the provider is repeatedly connected
                     and disconnected.

                     Arguments:

                            provider_id -- str
                                   The selection provider ID.

                            func -- callable(i_selection)
                                   A callable object that is notified when the selection changes.

              disconnect_selection_listener(provider_id, func)
                     Disconnect a listener from a specific provider.

                     Arguments:

                            provider_id -- str
                                   The selection provider ID.

                            func -- callable(provider_id, i_selection)
                                   A callable object that is notified when the selection changes.

              get_selection(provider_id)
                     Return the current selection of the provider with the given ID.

                     If a provider with that ID has not been registered, a ProviderNotRegisteredError is raised.

                     Arguments:

                            provider_id -- str
                                   The selection provider ID.

                     Returns:

                            selection -- ISelection
                                   The current selection of the provider.

              has_selection_provider(provider_id)
                     Has a provider with the given ID been registered?

              remove_selection_provider(provider)
                     Remove a selection provider.

                     If the provider has not been registered, a ProviderNotRegisteredError is raised.

                     Arguments:

                            provider -- ISelectionProvider
                                   The selection provider added to the internal registry.

              set_selection(provider_id, items, ignore_missing=False)
                     Set the current selection in a provider to the given items.

                     If a provider with the given ID has not been registered,  a  ProviderNotRegisteredError  is
                     raised.

                     If  ignore_missing  is  True,  items  that  are not available in the selection provider are
                     silently ignored. If it is False (default), a ValueError should be raised.

                     Arguments:

                            provider_id -- str
                                   The selection provider ID.

                            items -- list
                                   List of items to be selected.

                            ignore_missing -- bool
                                   If False (default), the provider raises an exception if any of the  items  in
                                   items  is  not  available  to  be  selected.  Otherwise, missing elements are
                                   silently ignored, and the rest is selected.

   i_selection_provider Module
       class apptools.selection.i_selection_provider.ISelectionProvider
              Bases: traits.has_traits.Interface

              Source of selections.

              get_selection()
                     Return the current selection.

                     Returns:

                            selection -- ISelection
                                   Object representing the current selection.

              provider_id = Str()
                     Unique ID identifying the provider.

              selection = Event
                     Event triggered when the selection changes.  The content of  the  event  is  an  ISelection
                     instance.

              set_selection(items, ignore_missing=False)
                     Set the current selection to the given items.

                     If  ignore_missing  is  True,  items  that  are not available in the selection provider are
                     silently ignored. If it is False (default), an ValueError should be raised.

                     Arguments:

                            items -- list
                                   List of items to be selected.

                            ignore_missing -- bool
                                   If False (default), the provider raises an exception if any of the  items  in
                                   items  is  not  available  to  be  selected.  Otherwise, missing elements are
                                   silently ignored, and the rest is selected.

   is_selection Module
       class apptools.selection.i_selection.IListSelection
              Bases: apptools.selection.i_selection.ISelection

              Selection for ordered sequences of items.

              indices = List
                     Indices of the selected objects in the selection provider.

              items = List
                     Selected objects.

       class apptools.selection.i_selection.ISelection
              Bases: traits.has_traits.Interface

              Collection of selected items.

              is_empty()
                     Is the selection empty?

              provider_id = Str
                     ID of the selection provider that created this selection object.

   list_selection Module
       class apptools.selection.list_selection.ListSelection
              Bases: traits.has_traits.HasTraits

              Selection for ordered sequences of items.

              This is the default implementation of the IListSelection interface.

              classmethod from_available_items(provider_id, selected, all_items)
                     Create a list selection given a list of all available items.

                     Fills in the required information (in particular, the indices) based on a list of  selected
                     items and a list of all available items.

                     NOTE:

                        • The list of available items must not contain any duplicate items.

                        • It is expected that selected is populated by items in all_items.

              indices = List
                     Indices of the selected objects in the selection provider.

              is_empty()
                     Is the selection empty?

              items = List
                     Selected objects.

              provider_id = Str
                     ID of the selection provider that created this selection object.

   errors Module
       exception apptools.selection.errors.IDConflictError(provider_id)
              Bases: Exception

              Raised when a provider is added and its ID is already registered.

       exception apptools.selection.errors.ListenerNotConnectedError(provider_id, listener)
              Bases: Exception

              Raised when a listener that was never connected is disconnected.

       exception apptools.selection.errors.ProviderNotRegisteredError(provider_id)
              Bases: Exception

              Raised when a provider is requested by ID and not found.

       • search

AUTHOR

       Enthought

       2008-2020, Enthought