PyUNO usability improvements

Matthew J. Francis mjay.francis at gmail.com
Sun Jun 14 06:26:43 PDT 2015


Hi,

For the past few weeks I've been working on some upgrades to PyUNO,
which have now reached (what I hope is) a sufficient level of sanity and 
stability. I've pushed the changes to:

   https://gerrit.libreoffice.org/16272

Given that this is a fairly large API change (if for a scripting
language that is not -yet- heavily used by our users), it probably
needs a careful review, but I have a suspicion that probably no one
developer currently has knowledge of all the interlocking requirements
at play here - or PyUNO might look somewhat different to begin with ;)
If anyone feels kind enough to take on the work of reviewing this,
please give me a shout and I'll offer what help I can on understanding
how all the pieces fit together.

* Parts of the test suite depend on
   https://gerrit.libreoffice.org/16073
Without this fix, various of the tests will fail


Regards
Matthew Francis


------------------------------------------------------------------------

     Make PyUNO provide more Pythonic behaviour

     - Simplifies working with UNO objects by giving the behaviour of
     Python lists, dicts and iterators to objects which implement UNO
     container interfaces

     - Applies a custom behaviour to allow objects which implement
     com::sun::star::table::XCellRange to yield cells and cell ranges by
     subscript

     - When UNO container objects are addressed in the new style,
     eliminates the requirement to manually construct Any objects for
     contained elements which are typed sequences

     - Allows lists and iterators to be passed wherever a UNO method
     accepts a sequence

     - Relaxes the requirements for initialising UNO structs to allow
     some members to be skipped when all initialisers are passed by name

     1. Collection interfaces
     ========================

     Objects which implement core UNO collection interfaces are made to
     behave in a way that is more natural for Python code.

     com::sun::star::container::XIndexAccess
     com::sun::star::container::XIndexReplace
     com::sun::star::container::XIndexContainer
     - Objects provide Python list access semantics
         num = len(obj)              # Number of elements
         val = obj[0]                # Access by index
         val1,val2 = obj[2:4]        # Access by slice
         val1,val2 = obj[0:3:2]      # Access by extended slice
         if val in obj: ...          # Test value presence
         for val in obj: ...         # Implicit iterator (values)
         itr = iter(obj)             # Named iterator (values)
         obj[0] = val                # Replace by index
         obj[2:4] = val1,val2        # Replace by slice
         obj[0:3:2] = val1,val2      # Replace by extended slice
         obj[2:3] = val1,val2        # Insert/replace by slice
         obj[2:2] = (val,)           # Insert by slice
         obj[2:4] = (val,)           # Replace/delete by slice
         obj[2:3] = ()               # Delete by slice (implicit)
         del obj[0]                  # Delete by index
         del obj[2:4]                # Delete by slice

     com::sun::star::container::XNameAccess
     com::sun::star::container::XNameReplace
     com::sun::star::container::XNameContainer
     - Objects provide Python dict access semantics
         num = len(obj)              # Number of keys
         val = obj[key]              # Access by key
         if key in obj: ...          # Test key presence
         for key in obj: ...         # Implicit iterator (keys)
         itr = iter(obj)             # Named iterator (keys)
         obj[key] = val              # Replace by key
         obj[key] = val              # Insert by key
         del obj[key]                # Delete by key

     com::sun::star::container::XEnumerationAccess
     - Objects provide Python iterable semantics
         for val in obj: ...         # Implicit iterator
         itr = iter(obj)             # Named iterator

     com::sun::star::container::XEnumeration
     - Objects provide Python iterator semantics
         for val in itr: ...         # Iteration of named iterator
         if val in itr: ...          # Test value presence

     Objects which implement both XIndex* and XName* are supported, and
     respond to both integer and string keys. However, iterating over
     such an object will return the keys (like a Python dict) rather than
     the values (like a Python list).

     2. Cell ranges
     ==============

     A custom behaviour is applied to objects which implement
     com::sun::star::table::XCellRange to allow their cells and cell
     ranges to be addressed by subscript, in the style of a Python list
     or dict (read-only). This is applicable to Calc spreadsheet sheets,
     Writer text tables and cell ranges created upon these.
         cell = cellrange[0,0]       # Access cell by indices
         rng = cellrange[0,1:2]      # Access cell range by index,slice
         rng = cellrange[1:2,0]      # Access cell range by slice,index
         rng = cellrange[0:1,2:3]    # Access cell range by slices
         rng = cellrange['A1:B2']    # Access cell range by descriptor
         rng = cellrange['Name']     # Access cell range by name

     Note that the indices used are in Python/C order, and differ from
     the arguments to methods provided by XCellRange.
     - The statement cellrange[r,c], which returns the cell from row r
     and column c, is equivalent to calling
         XCellRange::getCellByPosition(c,r)
     - The statement cellrange[t:b,l:r], which returns a cell range
     covering rows t to b(non-inclusive) and columns l to r(non-
     inclusive), is equivalent to calling
         XCellRange::getCellRangeByPosition(l,t,r-1,b-1).

     In contrast to the handling of objects implementing XIndex*,
     extended slice syntax is not supported. Negative indices (from-end
     addresses) are supported only for objects which also implement
     com::sun::star::table::XColumnRowRange (currently Calc spreadsheet
     sheets and cell ranges created upon these). For such objects, the
     following syntax is also available:
         rng = cellrange[0]          # Access cell range by row index
         rng = cellrange[0,:]        # Access cell range by row index
         rng = cellrange[:,0]        # Access cell range by column index

     3. Elimination of explicit Any
     ==============================

     PyUNO has not previously been able to cope with certain method
     arguments which are typed as Any but require a sequence of specific
     type to be passed. This is a particular issue for container
     interfaces such as XIndexContainer and XNameContainer.

     The existing solution to dealing with such methods is to use a
     special method to pass an explicitly typed Any, giving code such as:

         index = doc.createInstance("com.sun.star.text.ContentIndex");
         ...
         uno.invoke( index.LevelParagraphStyles , "replaceByIndex",
                     (0, uno.Any("[]string", ('Caption',))) )

     The new Pythonic container access is able to correctly infer the
     expected type of the sequences required by these arguments. In the
     new style, the above call to .replaceByIndex() can instead be
     written:

         index.LevelParagraphStyles[0] = ('Caption',)

     4. List and iterator arguments
     ==============================

     Wherever a UNO API expects a sequence, a Python list or iterator can
     now be passed. This enables the use of list comprehensions and
     generator expressions for method calls and property assignments.

     Example:

         tbl = doc.createInstance('com.sun.star.text.TextTable')
         tbl.initialize(10,10)
         # ... insert table ...
         # Assign numbers 0..99 to the cells using a generator expression
         tbl.Data = ((y for y in range(10*x,10*x + 10)) for x in range(10))

     5. Tolerant struct initialisation
     =================================

     Previously, a UNO struct could be created fully uninitialised, or by
     passing a combination of positional and/or named arguments to its
     constructor. However, if any arguments were passed, all members were
     required to be initialised or an exception was thrown.
     This requirement is relaxed such that when all arguments passed to a
     struct constructor are by name, some may be omitted. The existing
     requirement that all members must be explicitly initialised when
     some constructor arguments are unnamed (positional) is not affected.

     Example:

         from com.sun.star.beans import PropertyValue
         prop = PropertyValue(Name='foo', Value='bar')





More information about the LibreOffice mailing list