Files
libreoffice/pyuno/source/module/pyuno.cxx

1794 lines
56 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/config.h>
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
#include <algorithm>
#include <cassert>
#include "pyuno_impl.hxx"
#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/thread.h>
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
#include <typelib/typedescription.hxx>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XMaterialHolder.hpp>
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
#include <com/sun/star/container/XElementAccess.hpp>
#include <com/sun/star/container/XEnumeration.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/container/XIndexContainer.hpp>
#include <com/sun/star/container/XIndexReplace.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/container/XNameReplace.hpp>
using com::sun::star::uno::Sequence;
using com::sun::star::uno::Reference;
using com::sun::star::uno::XInterface;
using com::sun::star::uno::Any;
using com::sun::star::uno::makeAny;
using com::sun::star::uno::UNO_QUERY;
using com::sun::star::uno::Type;
using com::sun::star::uno::TypeClass;
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
using com::sun::star::uno::TypeDescription;
using com::sun::star::uno::RuntimeException;
using com::sun::star::uno::Exception;
using com::sun::star::uno::XComponentContext;
using com::sun::star::lang::XSingleServiceFactory;
using com::sun::star::lang::XServiceInfo;
using com::sun::star::lang::XTypeProvider;
using com::sun::star::script::XTypeConverter;
using com::sun::star::script::XInvocation2;
using com::sun::star::beans::XMaterialHolder;
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
using com::sun::star::container::XElementAccess;
using com::sun::star::container::XEnumeration;
using com::sun::star::container::XEnumerationAccess;
using com::sun::star::container::XIndexAccess;
using com::sun::star::container::XIndexContainer;
using com::sun::star::container::XIndexReplace;
using com::sun::star::container::XNameAccess;
using com::sun::star::container::XNameContainer;
using com::sun::star::container::XNameReplace;
namespace pyuno
{
PyObject *PyUNO_str( PyObject * self );
void PyUNO_del (PyObject* self)
{
PyUNO* me = reinterpret_cast< PyUNO* > (self);
{
PyThreadDetach antiguard;
delete me->members;
}
PyObject_Del (self);
}
OUString val2str( const void * pVal, typelib_TypeDescriptionReference * pTypeRef , sal_Int32 mode )
{
assert( pVal );
if (pTypeRef->eTypeClass == typelib_TypeClass_VOID)
return OUString("void");
OUStringBuffer buf( 64 );
buf.append( '(' );
buf.append( pTypeRef->pTypeName );
buf.append( ')' );
switch (pTypeRef->eTypeClass)
{
case typelib_TypeClass_INTERFACE:
{
buf.append( "0x" );
buf.append( reinterpret_cast< sal_IntPtr >(*static_cast<void * const *>(pVal)), 16 );
if( VAL2STR_MODE_DEEP == mode )
{
buf.append( "{" ); Reference< XInterface > r = *static_cast<Reference< XInterface > const *>(pVal);
Reference< XServiceInfo > serviceInfo( r, UNO_QUERY);
Reference< XTypeProvider > typeProvider(r,UNO_QUERY);
if( serviceInfo.is() )
{
buf.append("implementationName=" );
buf.append(serviceInfo->getImplementationName() );
buf.append(", supportedServices={" );
Sequence< OUString > seq = serviceInfo->getSupportedServiceNames();
for( int i = 0 ; i < seq.getLength() ; i ++ )
{
buf.append( seq[i] );
if( i +1 != seq.getLength() )
buf.append( "," );
}
buf.append("}");
}
if( typeProvider.is() )
{
buf.append(", supportedInterfaces={" );
Sequence< Type > seq (typeProvider->getTypes());
for( int i = 0 ; i < seq.getLength() ; i ++ )
{
buf.append(seq[i].getTypeName());
if( i +1 != seq.getLength() )
buf.append( "," );
}
buf.append("}");
}
buf.append( "}" );
}
break;
}
case typelib_TypeClass_STRUCT:
case typelib_TypeClass_EXCEPTION:
{
buf.append( "{ " );
typelib_TypeDescription * pTypeDescr = 0;
TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
assert( pTypeDescr );
typelib_CompoundTypeDescription * pCompType = reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr);
sal_Int32 nDescr = pCompType->nMembers;
if (pCompType->pBaseTypeDescription)
{
buf.append( val2str( pVal, pCompType->pBaseTypeDescription->aBase.pWeakRef, mode ) );
if (nDescr)
buf.append( ", " );
}
typelib_TypeDescriptionReference ** ppTypeRefs = pCompType->ppTypeRefs;
sal_Int32 * pMemberOffsets = pCompType->pMemberOffsets;
rtl_uString ** ppMemberNames = pCompType->ppMemberNames;
for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos )
{
buf.append( ppMemberNames[nPos] );
buf.append( " = " );
typelib_TypeDescription * pMemberType = 0;
TYPELIB_DANGER_GET( &pMemberType, ppTypeRefs[nPos] );
buf.append( val2str( static_cast<char const *>(pVal) + pMemberOffsets[nPos], pMemberType->pWeakRef, mode ) );
TYPELIB_DANGER_RELEASE( pMemberType );
if (nPos < (nDescr -1))
buf.append( ", " );
}
TYPELIB_DANGER_RELEASE( pTypeDescr );
buf.append( " }" );
break;
}
case typelib_TypeClass_SEQUENCE:
{
typelib_TypeDescription * pTypeDescr = 0;
TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
uno_Sequence * pSequence = *static_cast<uno_Sequence * const *>(pVal);
typelib_TypeDescription * pElementTypeDescr = 0;
TYPELIB_DANGER_GET( &pElementTypeDescr, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType );
sal_Int32 nElementSize = pElementTypeDescr->nSize;
2011-05-07 20:35:03 +01:00
sal_Int32 nElements = pSequence->nElements;
if (nElements)
{
buf.append( "{ " );
char * pElements = pSequence->elements;
for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
{
buf.append( val2str( pElements + (nElementSize * nPos), pElementTypeDescr->pWeakRef, mode ) );
if (nPos < (nElements -1))
buf.append( ", " );
}
buf.append( " }" );
}
else
{
buf.append( "{}" );
}
TYPELIB_DANGER_RELEASE( pElementTypeDescr );
TYPELIB_DANGER_RELEASE( pTypeDescr );
break;
}
case typelib_TypeClass_ANY:
buf.append( "{ " );
buf.append( val2str( static_cast<uno_Any const *>(pVal)->pData,
static_cast<uno_Any const *>(pVal)->pType ,
mode) );
buf.append( " }" );
break;
case typelib_TypeClass_TYPE:
buf.append( (*static_cast<typelib_TypeDescriptionReference * const *>(pVal))->pTypeName );
break;
case typelib_TypeClass_STRING:
buf.append( '\"' );
buf.append( *static_cast<rtl_uString * const *>(pVal) );
buf.append( '\"' );
break;
case typelib_TypeClass_ENUM:
{
typelib_TypeDescription * pTypeDescr = 0;
TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
sal_Int32 * pValues = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->pEnumValues;
sal_Int32 nPos = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nEnumValues;
while (nPos--)
{
if (pValues[nPos] == *static_cast<int const *>(pVal))
break;
}
if (nPos >= 0)
buf.append( reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->ppEnumNames[nPos] );
else
buf.append( '?' );
TYPELIB_DANGER_RELEASE( pTypeDescr );
break;
}
case typelib_TypeClass_BOOLEAN:
if (*static_cast<sal_Bool const *>(pVal))
buf.append( "true" );
else
buf.append( "false" );
break;
case typelib_TypeClass_CHAR:
buf.append( '\'' );
buf.append( *static_cast<sal_Unicode const *>(pVal) );
buf.append( '\'' );
break;
case typelib_TypeClass_FLOAT:
buf.append( *static_cast<float const *>(pVal) );
break;
case typelib_TypeClass_DOUBLE:
buf.append( *static_cast<double const *>(pVal) );
break;
case typelib_TypeClass_BYTE:
buf.append( "0x" );
buf.append( (sal_Int32)*static_cast<sal_Int8 const *>(pVal), 16 );
break;
case typelib_TypeClass_SHORT:
buf.append( "0x" );
buf.append( (sal_Int32)*static_cast<sal_Int16 const *>(pVal), 16 );
break;
case typelib_TypeClass_UNSIGNED_SHORT:
buf.append( "0x" );
buf.append( (sal_Int32)*static_cast<sal_uInt16 const *>(pVal), 16 );
break;
case typelib_TypeClass_LONG:
buf.append( "0x" );
buf.append( *static_cast<sal_Int32 const *>(pVal), 16 );
break;
case typelib_TypeClass_UNSIGNED_LONG:
buf.append( "0x" );
buf.append( (sal_Int64)*static_cast<sal_uInt32 const *>(pVal), 16 );
break;
case typelib_TypeClass_HYPER:
case typelib_TypeClass_UNSIGNED_HYPER:
buf.append( "0x" );
#if defined(__GNUC__) && defined(SPARC)
// I guess this really should check if there are strict alignment
// requirements, not just "GCC on SPARC".
{
sal_Int64 aVal;
*(sal_Int32 *)&aVal = *(sal_Int32 *)pVal;
*((sal_Int32 *)&aVal +1)= *((sal_Int32 *)pVal +1);
buf.append( aVal, 16 );
}
#else
buf.append( *static_cast<sal_Int64 const *>(pVal), 16 );
#endif
break;
case typelib_TypeClass_VOID:
case typelib_TypeClass_UNKNOWN:
case typelib_TypeClass_SERVICE:
case typelib_TypeClass_MODULE:
default:
buf.append( '?' );
}
return buf.makeStringAndClear();
}
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
sal_Int32 lcl_PyNumber_AsSal_Int32( PyObject *pObj )
{
// Check object is an index
PyRef rIndex( PyNumber_Index( pObj ), SAL_NO_ACQUIRE );
if ( !rIndex.is() )
return -1;
// Convert Python number to platform long, then check actual value against
// bounds of sal_Int32
int nOverflow;
long nResult = PyLong_AsLongAndOverflow( pObj, &nOverflow );
if ( nOverflow || nResult > SAL_MAX_INT32 || nResult < SAL_MIN_INT32) {
PyErr_SetString( PyExc_IndexError, "Python int too large to convert to UNO long" );
return -1;
}
return nResult;
}
int lcl_PySlice_GetIndicesEx( PyObject *pObject, sal_Int32 nLen, sal_Int32 *nStart, sal_Int32 *nStop, sal_Int32 *nStep, sal_Int32 *nSliceLength )
{
Py_ssize_t nStart_ssize, nStop_ssize, nStep_ssize, nSliceLength_ssize;
int nResult = PySlice_GetIndicesEx(
#if PY_VERSION_HEX >= 0x030200f0
pObject,
#else
reinterpret_cast<PySliceObject*>(pObject),
#endif
nLen, &nStart_ssize, &nStop_ssize, &nStep_ssize, &nSliceLength_ssize );
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
if (nResult == -1)
return -1;
if ( nStart_ssize > SAL_MAX_INT32 || nStart_ssize < SAL_MIN_INT32
|| nStop_ssize > SAL_MAX_INT32 || nStop_ssize < SAL_MIN_INT32
|| nStep_ssize > SAL_MAX_INT32 || nStep_ssize < SAL_MIN_INT32
|| nSliceLength_ssize > SAL_MAX_INT32 || nSliceLength_ssize < SAL_MIN_INT32 )
{
PyErr_SetString( PyExc_IndexError, "Python int too large to convert to UNO long" );
return -1;
}
*nStart = (sal_Int32)nStart_ssize;
*nStop = (sal_Int32)nStop_ssize;
*nStep = (sal_Int32)nStep_ssize;
*nSliceLength = (sal_Int32)nSliceLength_ssize;
return 0;
}
bool lcl_hasInterfaceByName( Any const &object, OUString const & interfaceName )
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
{
Reference< XInterface > xInterface( object, UNO_QUERY );
TypeDescription typeDesc( interfaceName );
Any aInterface = xInterface->queryInterface( typeDesc.get()->pWeakRef );
return aInterface.hasValue();
}
PyObject *PyUNO_repr( PyObject * self )
{
PyUNO *me = reinterpret_cast<PyUNO *>(self);
PyObject * ret = 0;
if( me->members->wrappedObject.getValueType().getTypeClass()
== com::sun::star::uno::TypeClass_EXCEPTION )
{
Reference< XMaterialHolder > rHolder(me->members->xInvocation,UNO_QUERY);
if( rHolder.is() )
{
Any a = rHolder->getMaterial();
Exception e;
a >>= e;
ret = ustring2PyUnicode(e.Message ).getAcquired();
}
}
else
{
ret = PyUNO_str( self );
}
return ret;
}
PyObject *PyUNO_invoke( PyObject *object, const char *name , PyObject *args )
{
PyRef ret;
try
{
Runtime runtime;
PyRef paras,callable;
if( PyObject_IsInstance( object, getPyUnoClass().get() ) )
{
PyUNO* me = reinterpret_cast<PyUNO*>(object);
OUString attrName = OUString::createFromAscii(name);
if (! me->members->xInvocation->hasMethod (attrName))
{
OUStringBuffer buf;
buf.append( "Attribute " );
buf.append( attrName );
buf.append( " unknown" );
throw RuntimeException( buf.makeStringAndClear() );
}
callable = PyUNO_callable_new (
me->members->xInvocation,
attrName,
ACCEPT_UNO_ANY);
paras = args;
}
else
{
// clean the tuple from uno.Any !
int size = PyTuple_Size( args );
{ // for CC, keeping ref-count of tuple being 1
paras = PyRef(PyTuple_New( size ), SAL_NO_ACQUIRE);
}
for( int i = 0 ; i < size ;i ++ )
{
PyObject * element = PyTuple_GetItem( args , i );
if( PyObject_IsInstance( element , getAnyClass( runtime ).get() ) )
{
element = PyObject_GetAttrString(
element, "value" );
}
else
{
Py_XINCREF( element );
}
PyTuple_SetItem( paras.get(), i , element );
}
callable = PyRef( PyObject_GetAttrString( object , name ), SAL_NO_ACQUIRE );
if( !callable.is() )
return 0;
}
ret = PyRef( PyObject_CallObject( callable.get(), paras.get() ), SAL_NO_ACQUIRE );
}
2011-12-21 21:57:16 +09:00
catch (const ::com::sun::star::lang::IllegalArgumentException &e)
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
2011-12-21 21:57:16 +09:00
catch (const ::com::sun::star::script::CannotConvertException &e)
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
2011-12-21 21:57:16 +09:00
catch (const ::com::sun::star::uno::RuntimeException &e)
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
2011-12-21 21:57:16 +09:00
catch (const ::com::sun::star::uno::Exception &e)
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
return ret.getAcquired();
}
PyObject *PyUNO_str( PyObject * self )
{
PyUNO *me = reinterpret_cast<PyUNO *>(self);
OStringBuffer buf;
if( me->members->wrappedObject.getValueType().getTypeClass()
== com::sun::star::uno::TypeClass_STRUCT ||
me->members->wrappedObject.getValueType().getTypeClass()
== com::sun::star::uno::TypeClass_EXCEPTION)
{
Reference< XMaterialHolder > rHolder(me->members->xInvocation,UNO_QUERY);
if( rHolder.is() )
{
2003-05-24 10:00:56 +00:00
PyThreadDetach antiguard;
Any a = rHolder->getMaterial();
OUString s = val2str( a.getValue(), a.getValueType().getTypeLibType() );
buf.append( OUStringToOString(s,RTL_TEXTENCODING_ASCII_US) );
}
}
else
{
// a common UNO object
2003-05-24 10:00:56 +00:00
PyThreadDetach antiguard;
buf.append( "pyuno object " );
OUString s = val2str( me->members->wrappedObject.getValue(),
me->members->wrappedObject.getValueType().getTypeLibType() );
buf.append( OUStringToOString(s,RTL_TEXTENCODING_ASCII_US) );
}
return PyStr_FromString( buf.getStr());
}
PyObject* PyUNO_dir (PyObject* self)
{
PyUNO* me = reinterpret_cast<PyUNO*>(self);
PyObject* member_list = NULL;
Sequence<OUString> oo_member_list;
try
{
oo_member_list = me->members->xInvocation->getMemberNames ();
member_list = PyList_New (oo_member_list.getLength ());
for (int i = 0; i < oo_member_list.getLength (); i++)
{
// setitem steals a reference
PyList_SetItem (member_list, i, ustring2PyString(oo_member_list[i]).getAcquired() );
}
}
catch( const RuntimeException &e )
{
raisePyExceptionWithAny( makeAny(e) );
}
return member_list;
}
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
sal_Int32 lcl_detach_getLength( PyUNO *me )
{
PyThreadDetach antiguard;
// If both XIndexContainer and XNameContainer are implemented, it is
// assumed that getCount() gives the same result as the number of names
// returned by getElementNames(), or the user may be surprised.
// For XIndexContainer
Reference< XIndexAccess > xIndexAccess( me->members->wrappedObject, UNO_QUERY );
if ( xIndexAccess.is() )
{
return xIndexAccess->getCount();
}
// For XNameContainer
// Not terribly efficient - get the count of all the names
Reference< XNameAccess > xNameAccess( me->members->wrappedObject, UNO_QUERY );
if ( xNameAccess.is() )
{
return xNameAccess->getElementNames().getLength();
}
return -1;
}
int PyUNO_bool( PyObject* self )
{
PyUNO* me = reinterpret_cast<PyUNO*>(self);
try
{
int nLen = lcl_detach_getLength( me );
if (nLen >= 0)
return nLen == 0 ? 0 : 1;
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
// Anything which doesn't have members is a scalar object and therefore true
return 1;
}
catch( const ::com::sun::star::uno::RuntimeException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
return -1;
}
Py_ssize_t PyUNO_len( PyObject* self )
{
PyUNO* me = reinterpret_cast<PyUNO*>(self);
try
{
int nLen = lcl_detach_getLength( me );
if (nLen >= 0)
return nLen;
PyErr_SetString( PyExc_TypeError, "object has no len()" );
}
catch( const ::com::sun::star::uno::RuntimeException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
return -1;
}
void lcl_getRowsColumns( PyUNO* me, sal_Int32& nRows, sal_Int32& nColumns )
{
Sequence<short> aOutParamIndex;
Sequence<Any> aOutParam;
Sequence<Any> aParams;
Any aRet;
aRet = me->members->xInvocation->invoke ( "getRows", aParams, aOutParamIndex, aOutParam );
Reference< XIndexAccess > xIndexAccessRows( aRet, UNO_QUERY );
nRows = xIndexAccessRows->getCount();
aRet = me->members->xInvocation->invoke ( "getColumns", aParams, aOutParamIndex, aOutParam );
Reference< XIndexAccess > xIndexAccessCols( aRet, UNO_QUERY );
nColumns = xIndexAccessCols->getCount();
}
PyRef lcl_indexToSlice( PyRef rIndex )
{
Py_ssize_t nIndex = PyNumber_AsSsize_t( rIndex.get(), PyExc_IndexError );
if (nIndex == -1 && PyErr_Occurred())
return NULL;
PyRef rStart( PyLong_FromSsize_t( nIndex ), SAL_NO_ACQUIRE );
PyRef rStop( PyLong_FromSsize_t( nIndex+1 ), SAL_NO_ACQUIRE );
PyRef rStep( PyLong_FromLong( 1 ), SAL_NO_ACQUIRE );
PyRef rSlice( PySlice_New( rStart.get(), rStop.get(), rStep.get() ), SAL_NO_ACQUIRE );
return rSlice;
}
PyObject* lcl_getitem_XCellRange( PyUNO* me, PyObject* pKey )
{
Runtime runtime;
Sequence<short> aOutParamIndex;
Sequence<Any> aOutParam;
Sequence<Any> aParams;
Any aRet;
// Single string key is sugar for getCellRangeByName()
if ( PyStr_Check( pKey ) ) {
aParams.realloc (1);
aParams[0] <<= pyString2ustring( pKey );
{
PyThreadDetach antiguard;
aRet = me->members->xInvocation->invoke (
"getCellRangeByName", aParams, aOutParamIndex, aOutParam );
}
PyRef rRet = runtime.any2PyObject ( aRet );
return rRet.getAcquired();
}
PyRef rKey0, rKey1;
if ( PyIndex_Check( pKey ) )
{
// [0] is equivalent to [0,:]
rKey0 = pKey;
rKey1 = PySlice_New( NULL, NULL, NULL );
}
else if ( PyTuple_Check( pKey ) && (PyTuple_Size( pKey ) == 2) )
{
rKey0 = PyTuple_GetItem( pKey, 0 );
rKey1 = PyTuple_GetItem( pKey, 1 );
}
else
{
PyErr_SetString( PyExc_KeyError, "invalid subscript" );
return NULL;
}
// If both keys are indices, return the corresponding cell
if ( PyIndex_Check( rKey0.get() ) && PyIndex_Check( rKey1.get() ))
{
sal_Int32 nKey0_s = lcl_PyNumber_AsSal_Int32( rKey0.get() );
sal_Int32 nKey1_s = lcl_PyNumber_AsSal_Int32( rKey1.get() );
if ( ((nKey0_s == -1) || (nKey1_s == -1)) && PyErr_Occurred() )
return NULL;
aParams.realloc( 2 );
aParams[0] <<= nKey1_s;
aParams[1] <<= nKey0_s;
{
PyThreadDetach antiguard;
aRet = me->members->xInvocation->invoke (
"getCellByPosition", aParams, aOutParamIndex, aOutParam );
}
PyRef rRet = runtime.any2PyObject( aRet );
return rRet.getAcquired();
}
// If either argument is an index, coerce it to a slice
if ( PyIndex_Check( rKey0.get() ) )
rKey0 = lcl_indexToSlice( rKey0 );
if ( PyIndex_Check( rKey1.get() ) )
rKey1 = lcl_indexToSlice( rKey1 );
// If both arguments are slices, return the corresponding cell range
if ( PySlice_Check( rKey0.get() ) && PySlice_Check( rKey1.get() ) )
{
sal_Int32 nLen0 = SAL_MAX_INT32, nLen1 = SAL_MAX_INT32;
sal_Int32 nStart0 = 0, nStop0 = 0, nStep0 = 0, nSliceLength0 = 0;
sal_Int32 nStart1 = 0, nStop1 = 0, nStep1 = 0, nSliceLength1 = 0;
{
PyThreadDetach antiguard;
if ( lcl_hasInterfaceByName( me->members->wrappedObject, "com.sun.star.table.XColumnRowRange" ) )
{
lcl_getRowsColumns (me, nLen0, nLen1);
}
}
int nSuccess1 = lcl_PySlice_GetIndicesEx( rKey0.get(), nLen0, &nStart0, &nStop0, &nStep0, &nSliceLength0 );
int nSuccess2 = lcl_PySlice_GetIndicesEx( rKey1.get(), nLen1, &nStart1, &nStop1, &nStep1, &nSliceLength1 );
if ( ((nSuccess1 == -1) || (nSuccess2 == -1)) && PyErr_Occurred() )
return NULL;
if ( nSliceLength0 <= 0 || nSliceLength1 <= 0 )
{
PyErr_SetString( PyExc_KeyError, "invalid number of rows or columns" );
return NULL;
}
if ( nStep0 == 1 && nStep1 == 1 )
{
aParams.realloc (4);
aParams[0] <<= nStart1;
aParams[1] <<= nStart0;
aParams[2] <<= nStop1 - 1;
aParams[3] <<= nStop0 - 1;
{
PyThreadDetach antiguard;
aRet = me->members->xInvocation->invoke (
"getCellRangeByPosition", aParams, aOutParamIndex, aOutParam );
}
PyRef rRet = runtime.any2PyObject( aRet );
return rRet.getAcquired();
}
PyErr_SetString( PyExc_KeyError, "step != 1 not supported" );
return NULL;
}
PyErr_SetString( PyExc_KeyError, "invalid subscript" );
return NULL;
}
PyObject* lcl_getitem_index( PyUNO *me, PyObject *pKey, Runtime& runtime )
{
Any aRet;
sal_Int32 nIndex;
nIndex = lcl_PyNumber_AsSal_Int32( pKey );
if (nIndex == -1 && PyErr_Occurred())
return NULL;
{
PyThreadDetach antiguard;
Reference< XIndexAccess > xIndexAccess( me->members->wrappedObject, UNO_QUERY );
if ( xIndexAccess.is() )
{
if (nIndex < 0)
nIndex += xIndexAccess->getCount();
aRet = xIndexAccess->getByIndex( nIndex );
}
}
if ( aRet.hasValue() )
{
PyRef rRet ( runtime.any2PyObject( aRet ) );
return rRet.getAcquired();
}
return NULL;
}
PyObject* lcl_getitem_slice( PyUNO *me, PyObject *pKey )
{
Runtime runtime;
Reference< XIndexAccess > xIndexAccess;
sal_Int32 nLen = 0;
{
PyThreadDetach antiguard;
xIndexAccess.set( me->members->wrappedObject, UNO_QUERY );
if ( xIndexAccess.is() )
nLen = xIndexAccess->getCount();
}
if ( xIndexAccess.is() )
{
sal_Int32 nStart = 0, nStop = 0, nStep = 0, nSliceLength = 0;
int nSuccess = lcl_PySlice_GetIndicesEx(pKey, nLen, &nStart, &nStop, &nStep, &nSliceLength);
if ( nSuccess == -1 && PyErr_Occurred() )
return NULL;
PyRef rTuple( PyTuple_New( nSliceLength ), SAL_NO_ACQUIRE, NOT_NULL );
sal_Int32 nCur, i;
for ( nCur = nStart, i = 0; i < nSliceLength; nCur += nStep, i++ )
{
Any aRet;
{
PyThreadDetach antiguard;
aRet = xIndexAccess->getByIndex( nCur );
}
PyRef rRet = runtime.any2PyObject( aRet );
PyTuple_SetItem( rTuple.get(), i, rRet.getAcquired() );
}
return rTuple.getAcquired();
}
return NULL;
}
PyObject* lcl_getitem_string( PyUNO *me, PyObject *pKey, Runtime& runtime )
{
OUString sKey = pyString2ustring( pKey );
Any aRet;
{
PyThreadDetach antiguard;
Reference< XNameAccess > xNameAccess( me->members->wrappedObject, UNO_QUERY );
if ( xNameAccess.is() )
{
aRet = xNameAccess->getByName( sKey );
}
}
if ( aRet.hasValue() )
{
PyRef rRet = runtime.any2PyObject( aRet );
return rRet.getAcquired();
}
return NULL;
}
PyObject* PyUNO_getitem( PyObject *self, PyObject *pKey )
{
PyUNO* me = reinterpret_cast<PyUNO*>(self);
Runtime runtime;
try
{
// XIndexAccess access by index
if ( PyIndex_Check( pKey ) )
{
PyObject* pRet = lcl_getitem_index( me, pKey, runtime );
if ( pRet != NULL || PyErr_Occurred() )
return pRet;
}
// XIndexAccess access by slice
if ( PySlice_Check( pKey ) )
{
PyObject* pRet = lcl_getitem_slice( me, pKey );
if ( pRet != NULL || PyErr_Occurred() )
return pRet;
}
// XNameAccess access by key
if ( PyStr_Check( pKey ) )
{
PyObject* pRet = lcl_getitem_string( me, pKey, runtime );
if ( pRet != NULL )
return pRet;
}
// XCellRange/XColumnRowRange specialisation
// Uses reflection as we can't have a hard dependency on XCellRange here
bool hasXCellRange = false;
{
PyThreadDetach antiguard;
hasXCellRange = lcl_hasInterfaceByName( me->members->wrappedObject, "com.sun.star.table.XCellRange" );
}
if ( hasXCellRange )
{
return lcl_getitem_XCellRange( me, pKey );
}
// If the object is an XIndexAccess and/or XNameAccess, but the
// key passed wasn't suitable, give a TypeError which specifically
// describes this
Reference< XIndexAccess > xIndexAccess( me->members->wrappedObject, UNO_QUERY );
Reference< XNameAccess > xNameAccess( me->members->wrappedObject, UNO_QUERY );
if ( xIndexAccess.is() || xNameAccess.is() )
{
PyErr_SetString( PyExc_TypeError, "subscription with invalid type" );
return NULL;
}
PyErr_SetString( PyExc_TypeError, "object is not subscriptable" );
}
catch( const ::com::sun::star::lang::IndexOutOfBoundsException )
{
PyErr_SetString( PyExc_IndexError, "index out of range" );
}
catch( const ::com::sun::star::container::NoSuchElementException )
{
PyErr_SetString( PyExc_KeyError, "key not found" );
}
catch( const com::sun::star::script::CannotConvertException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const com::sun::star::lang::IllegalArgumentException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const ::com::sun::star::lang::WrappedTargetException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const ::com::sun::star::uno::RuntimeException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
return NULL;
}
int lcl_setitem_index( PyUNO *me, PyObject *pKey, PyObject *pValue )
{
Runtime runtime;
Reference< XIndexContainer > xIndexContainer;
Reference< XIndexReplace > xIndexReplace;
sal_Int32 nIndex = lcl_PyNumber_AsSal_Int32( pKey );
if ( nIndex == -1 && PyErr_Occurred() )
return 0;
bool isTuple = false;
Any aValue;
if ( pValue != NULL )
{
isTuple = PyTuple_Check( pValue );
try
{
aValue <<= runtime.pyObject2Any( pValue );
}
catch ( const ::com::sun::star::uno::RuntimeException )
{
// TODO pyObject2Any can't convert e.g. dicts but only throws
// RuntimeException on failure. Fixing this will require an audit of
// all the rest of PyUNO
throw ::com::sun::star::script::CannotConvertException();
}
}
{
PyThreadDetach antiguard;
xIndexContainer.set( me->members->wrappedObject, UNO_QUERY );
if ( xIndexContainer.is() )
xIndexReplace.set( xIndexContainer, UNO_QUERY );
else
xIndexReplace.set( me->members->wrappedObject, UNO_QUERY );
if ( xIndexReplace.is() && nIndex < 0 )
nIndex += xIndexReplace->getCount();
// XIndexReplace replace by index
if ( (pValue != NULL) && xIndexReplace.is() )
{
if ( isTuple )
{
// Apply type specialisation to ensure the correct kind of sequence is passed
Type aType = xIndexReplace->getElementType();
aValue = runtime.getImpl()->cargo->xTypeConverter->convertTo( aValue, aType );
}
xIndexReplace->replaceByIndex( nIndex, aValue );
return 0;
}
// XIndexContainer remove by index
if ( (pValue == NULL) && xIndexContainer.is() )
{
xIndexContainer->removeByIndex( nIndex );
return 0;
}
}
PyErr_SetString( PyExc_TypeError, "cannot assign to object" );
return 1;
}
int lcl_setitem_slice( PyUNO *me, PyObject *pKey, PyObject *pValue )
{
// XIndexContainer insert/remove/replace by slice
Runtime runtime;
Reference< XIndexReplace > xIndexReplace;
Reference< XIndexContainer > xIndexContainer;
sal_Int32 nLen = 0;
{
PyThreadDetach antiguard;
xIndexContainer.set( me->members->wrappedObject, UNO_QUERY );
if ( xIndexContainer.is() )
xIndexReplace.set( xIndexContainer, UNO_QUERY );
else
xIndexReplace.set( me->members->wrappedObject, UNO_QUERY );
if ( xIndexReplace.is() )
nLen = xIndexReplace->getCount();
}
if ( xIndexReplace.is() )
{
sal_Int32 nStart = 0, nStop = 0, nStep = 0, nSliceLength = 0;
int nSuccess = lcl_PySlice_GetIndicesEx( pKey, nLen, &nStart, &nStop, &nStep, &nSliceLength );
if ( (nSuccess == -1) && PyErr_Occurred() )
return 0;
if ( pValue == NULL )
{
pValue = PyTuple_New( 0 );
}
if ( !PyTuple_Check (pValue) )
{
PyErr_SetString( PyExc_TypeError, "value is not a tuple" );
return 1;
}
Py_ssize_t nTupleLength_ssize = PyTuple_Size( pValue );
if ( nTupleLength_ssize > SAL_MAX_INT32 )
{
PyErr_SetString( PyExc_ValueError, "tuple too large" );
return 1;
}
sal_Int32 nTupleLength = (sal_Int32)nTupleLength_ssize;
if ( (nTupleLength != nSliceLength) && (nStep != 1) )
{
PyErr_SetString( PyExc_ValueError, "number of items assigned must be equal" );
return 1;
}
if ( (nTupleLength != nSliceLength) && !xIndexContainer.is() )
{
PyErr_SetString( PyExc_ValueError, "cannot change length" );
return 1;
}
sal_Int32 nCur, i;
sal_Int32 nMax = ::std::max( nSliceLength, nTupleLength );
for ( nCur = nStart, i = 0; i < nMax; nCur += nStep, i++ )
{
if ( i < nTupleLength )
{
PyRef rItem = PyTuple_GetItem( pValue, i );
bool isTuple = PyTuple_Check( rItem.get() );
Any aItem;
try
{
aItem <<= runtime.pyObject2Any( rItem.get() );
}
catch ( const ::com::sun::star::uno::RuntimeException )
{
// TODO pyObject2Any can't convert e.g. dicts but only throws
// RuntimeException on failure. Fixing this will require an audit of
// all the rest of PyUNO
throw ::com::sun::star::script::CannotConvertException();
}
{
PyThreadDetach antiguard;
if ( isTuple )
{
// Apply type specialisation to ensure the correct kind of sequence is passed
Type aType = xIndexReplace->getElementType();
aItem = runtime.getImpl()->cargo->xTypeConverter->convertTo( aItem, aType );
}
if ( i < nSliceLength )
{
xIndexReplace->replaceByIndex( nCur, aItem );
}
else
{
xIndexContainer->insertByIndex( nCur, aItem );
}
}
}
else
{
PyThreadDetach antiguard;
xIndexContainer->removeByIndex( nCur );
nCur--;
}
}
return 0;
}
PyErr_SetString( PyExc_TypeError, "cannot assign to object" );
return 1;
}
int lcl_setitem_string( PyUNO *me, PyObject *pKey, PyObject *pValue )
{
Runtime runtime;
OUString sKey = pyString2ustring( pKey );
bool isTuple = false;
Any aValue;
if ( pValue != NULL)
{
isTuple = PyTuple_Check( pValue );
try
{
aValue <<= runtime.pyObject2Any( pValue );
}
catch( const ::com::sun::star::uno::RuntimeException )
{
// TODO pyObject2Any can't convert e.g. dicts but only throws
// RuntimeException on failure. Fixing this will require an audit of
// all the rest of PyUNO
throw ::com::sun::star::script::CannotConvertException();
}
}
{
PyThreadDetach antiguard;
Reference< XNameContainer > xNameContainer( me->members->wrappedObject, UNO_QUERY );
Reference< XNameReplace > xNameReplace;
if ( xNameContainer.is() )
xNameReplace.set( xNameContainer, UNO_QUERY );
else
xNameReplace.set( me->members->wrappedObject, UNO_QUERY );
if ( xNameReplace.is() )
{
if ( isTuple && aValue.hasValue() )
{
// Apply type specialisation to ensure the correct kind of sequence is passed
Type aType = xNameReplace->getElementType();
aValue = runtime.getImpl()->cargo->xTypeConverter->convertTo( aValue, aType );
}
if ( aValue.hasValue() )
{
if ( xNameContainer.is() )
{
try {
xNameContainer->insertByName( sKey, aValue );
return 0;
}
catch( com::sun::star::container::ElementExistException )
{
// Fall through, try replace instead
}
}
xNameReplace->replaceByName( sKey, aValue );
return 0;
}
else if ( xNameContainer.is() )
{
xNameContainer->removeByName( sKey );
return 0;
}
}
}
PyErr_SetString( PyExc_TypeError, "cannot assign to object" );
return 1;
}
int PyUNO_setitem( PyObject *self, PyObject *pKey, PyObject *pValue )
{
PyUNO* me = reinterpret_cast<PyUNO*>(self);
try
{
if ( PyIndex_Check( pKey ) )
{
return lcl_setitem_index( me, pKey, pValue );
}
else if ( PySlice_Check( pKey ) )
{
return lcl_setitem_slice( me, pKey, pValue );
}
else if ( PyStr_Check( pKey ) )
{
return lcl_setitem_string( me, pKey, pValue );
}
PyErr_SetString( PyExc_TypeError, "list index has invalid type" );
}
catch( const ::com::sun::star::lang::IndexOutOfBoundsException )
{
PyErr_SetString( PyExc_IndexError, "list index out of range" );
}
catch( const ::com::sun::star::container::NoSuchElementException )
{
PyErr_SetString( PyExc_KeyError, "key not found" );
}
catch( const ::com::sun::star::lang::IllegalArgumentException )
{
PyErr_SetString( PyExc_TypeError, "value has invalid type" );
}
catch( com::sun::star::script::CannotConvertException )
{
PyErr_SetString( PyExc_TypeError, "value has invalid type" );
}
catch( const ::com::sun::star::container::ElementExistException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const::com::sun::star::lang::WrappedTargetException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const ::com::sun::star::uno::RuntimeException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
return 1;
}
PyObject* PyUNO_iter( PyObject *self )
{
PyUNO* me = reinterpret_cast<PyUNO*>(self);
try
{
Reference< XEnumerationAccess > xEnumerationAccess;
Reference< XEnumeration > xEnumeration;
Reference< XIndexAccess > xIndexAccess;
Reference< XNameAccess > xNameAccess;
{
PyThreadDetach antiguard;
xEnumerationAccess.set( me->members->wrappedObject, UNO_QUERY );
if ( xEnumerationAccess.is() )
xEnumeration = xEnumerationAccess->createEnumeration();
else
xEnumeration.set( me->members->wrappedObject, UNO_QUERY );
if ( !xEnumeration.is() )
xIndexAccess.set( me->members->wrappedObject, UNO_QUERY );
if ( !xIndexAccess.is() )
xNameAccess.set( me->members->wrappedObject, UNO_QUERY );
}
// XEnumerationAccess iterator
// XEnumeration iterator
if (xEnumeration.is())
{
return PyUNO_iterator_new( xEnumeration );
}
// XIndexAccess iterator
if ( xIndexAccess.is() )
{
// We'd like to be able to use PySeqIter_New() here, but we're not
// allowed to because we also implement the mapping protocol
return PyUNO_list_iterator_new( xIndexAccess );
}
// XNameAccess iterator
if (xNameAccess.is())
{
// There's no generic mapping iterator, but we can cobble our own
// together using PySeqIter_New()
Runtime runtime;
Any aRet;
{
PyThreadDetach antiguard;
aRet <<= xNameAccess->getElementNames();
}
PyRef rNames = runtime.any2PyObject( aRet );
return PySeqIter_New( rNames.getAcquired() );
}
PyErr_SetString ( PyExc_TypeError, "object is not iterable" );
}
catch( com::sun::star::script::CannotConvertException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( com::sun::star::lang::IllegalArgumentException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const ::com::sun::star::uno::RuntimeException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
return NULL;
}
int PyUNO_contains( PyObject *self, PyObject *pKey )
{
PyUNO* me = reinterpret_cast<PyUNO*>(self);
Runtime runtime;
try
{
Any aValue;
try
{
aValue <<= runtime.pyObject2Any( pKey );
}
catch( const ::com::sun::star::uno::RuntimeException )
{
// TODO pyObject2Any can't convert e.g. dicts but only throws
// RuntimeException on failure. Fixing this will require an audit of
// all the rest of PyUNO
throw ::com::sun::star::script::CannotConvertException();
}
// XNameAccess is tried first, because checking key presence is much more
// useful for objects which implement both XIndexAccess and XNameAccess
// For XNameAccess
if ( PyStr_Check( pKey ) )
{
OUString sKey;
aValue >>= sKey;
Reference< XNameAccess > xNameAccess;
{
PyThreadDetach antiguard;
xNameAccess.set( me->members->wrappedObject, UNO_QUERY );
if ( xNameAccess.is() )
{
bool hasKey = xNameAccess->hasByName( sKey );
return hasKey ? 1 : 0;
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
}
}
}
// For any other type of PyUNO iterable: Ugly iterative search by
// content (XIndexAccess, XEnumerationAccess, XEnumeration)
PyRef rIterator( PyUNO_iter( self ), SAL_NO_ACQUIRE );
if ( rIterator.is() )
{
PyObject* pItem;
while ( (pItem = PyIter_Next( rIterator.get() )) )
{
PyRef rItem( pItem, SAL_NO_ACQUIRE );
if ( PyObject_RichCompareBool( pKey, rItem.get(), Py_EQ ) == 1 )
{
return 1;
}
}
return 0;
}
PyErr_SetString( PyExc_TypeError, "argument is not iterable" );
}
catch( const com::sun::star::script::CannotConvertException )
{
PyErr_SetString( PyExc_TypeError, "invalid type passed as left argument to 'in'" );
}
catch( const ::com::sun::star::container::NoSuchElementException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const ::com::sun::star::lang::IndexOutOfBoundsException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const com::sun::star::lang::IllegalArgumentException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const ::com::sun::star::lang::WrappedTargetException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
catch( const ::com::sun::star::uno::RuntimeException &e )
{
raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
}
return -1;
}
PyObject* PyUNO_getattr (PyObject* self, char* name)
{
PyUNO* me;
try
{
Runtime runtime;
me = reinterpret_cast<PyUNO*>(self);
if (strcmp (name, "__dict__") == 0)
{
Py_INCREF (Py_TYPE(me)->tp_dict);
return Py_TYPE(me)->tp_dict;
}
if (strcmp (name, "__class__") == 0)
{
if( me->members->wrappedObject.getValueTypeClass() ==
com::sun::star::uno::TypeClass_STRUCT ||
me->members->wrappedObject.getValueTypeClass() ==
com::sun::star::uno::TypeClass_EXCEPTION )
{
return getClass(
me->members->wrappedObject.getValueType().getTypeName(), runtime ).getAcquired();
}
Py_INCREF (Py_None);
return Py_None;
}
OUString attrName( OUString::createFromAscii( name ) );
//We need to find out if it's a method...
if (me->members->xInvocation->hasMethod (attrName))
{
//Create a callable object to invoke this...
PyRef ret = PyUNO_callable_new (
me->members->xInvocation,
attrName);
Py_XINCREF( ret.get() );
return ret.get();
}
//or a property
if (me->members->xInvocation->hasProperty ( attrName))
{
//Return the value of the property
2003-05-24 10:00:56 +00:00
Any anyRet;
{
PyThreadDetach antiguard;
anyRet = me->members->xInvocation->getValue (attrName);
}
PyRef ret = runtime.any2PyObject(anyRet);
Py_XINCREF( ret.get() );
return ret.get();
}
//or else...
PyErr_SetString (PyExc_AttributeError, name);
}
2011-12-21 21:57:16 +09:00
catch( const com::sun::star::reflection::InvocationTargetException & e )
{
raisePyExceptionWithAny( e.TargetException );
}
2011-12-21 21:57:16 +09:00
catch( const com::sun::star::beans::UnknownPropertyException & e )
{
raisePyExceptionWithAny( makeAny(e) );
}
2011-12-21 21:57:16 +09:00
catch( const com::sun::star::lang::IllegalArgumentException &e )
{
raisePyExceptionWithAny( makeAny(e) );
}
2011-12-21 21:57:16 +09:00
catch( const com::sun::star::script::CannotConvertException &e )
{
raisePyExceptionWithAny( makeAny(e) );
}
2011-12-21 21:57:16 +09:00
catch( const RuntimeException &e )
{
raisePyExceptionWithAny( makeAny(e) );
}
return NULL;
}
int PyUNO_setattr (PyObject* self, char* name, PyObject* value)
{
PyUNO* me;
me = reinterpret_cast<PyUNO*>(self);
try
{
Runtime runtime;
Any val= runtime.pyObject2Any(value, ACCEPT_UNO_ANY);
OUString attrName( OUString::createFromAscii( name ) );
{
PyThreadDetach antiguard;
if (me->members->xInvocation->hasProperty (attrName))
{
me->members->xInvocation->setValue (attrName, val);
return 0; //Keep with Python's boolean system
}
}
}
2011-12-21 21:57:16 +09:00
catch( const com::sun::star::reflection::InvocationTargetException & e )
{
raisePyExceptionWithAny( e.TargetException );
return 1;
}
2011-12-21 21:57:16 +09:00
catch( const com::sun::star::beans::UnknownPropertyException & e )
{
raisePyExceptionWithAny( makeAny(e) );
return 1;
}
2011-12-21 21:57:16 +09:00
catch( const com::sun::star::script::CannotConvertException &e )
{
raisePyExceptionWithAny( makeAny(e) );
return 1;
}
2011-12-21 21:57:16 +09:00
catch( const RuntimeException & e )
{
raisePyExceptionWithAny( makeAny( e ) );
return 1;
}
PyErr_SetString (PyExc_AttributeError, name);
return 1; //as above.
}
// ensure object identity and struct equality
2011-05-07 20:35:03 +01:00
static PyObject* PyUNO_cmp( PyObject *self, PyObject *that, int op )
{
PyObject *result;
2011-05-07 20:35:03 +01:00
if(op != Py_EQ && op != Py_NE)
{
PyErr_SetString(PyExc_TypeError, "only '==' and '!=' comparisons are defined");
return 0;
2011-05-07 20:35:03 +01:00
}
if( self == that )
{
result = (op == Py_EQ ? Py_True : Py_False);
Py_INCREF(result);
return result;
2011-05-07 20:35:03 +01:00
}
try
{
Runtime runtime;
if( PyObject_IsInstance( that, getPyUnoClass().get() ) )
{
PyUNO *me = reinterpret_cast< PyUNO*> ( self );
PyUNO *other = reinterpret_cast< PyUNO *> (that );
com::sun::star::uno::TypeClass tcMe = me->members->wrappedObject.getValueTypeClass();
com::sun::star::uno::TypeClass tcOther = other->members->wrappedObject.getValueTypeClass();
if( tcMe == tcOther )
{
if( tcMe == com::sun::star::uno::TypeClass_STRUCT ||
tcMe == com::sun::star::uno::TypeClass_EXCEPTION )
{
Reference< XMaterialHolder > xMe( me->members->xInvocation,UNO_QUERY);
Reference< XMaterialHolder > xOther( other->members->xInvocation,UNO_QUERY );
if( xMe->getMaterial() == xOther->getMaterial() )
2011-05-07 20:35:03 +01:00
{
result = (op == Py_EQ ? Py_True : Py_False);
Py_INCREF(result);
return result;
2011-05-07 20:35:03 +01:00
}
}
else if( tcMe == com::sun::star::uno::TypeClass_INTERFACE )
{
if( me->members->wrappedObject == other->members->wrappedObject )
2011-05-07 20:35:03 +01:00
{
result = (op == Py_EQ ? Py_True : Py_False);
Py_INCREF(result);
return result;
2011-05-07 20:35:03 +01:00
}
}
}
}
}
2011-12-21 21:57:16 +09:00
catch( const com::sun::star::uno::RuntimeException & e)
{
raisePyExceptionWithAny( makeAny( e ) );
}
result = (op == Py_EQ ? Py_False : Py_True);
Py_INCREF(result);
return result;
}
static PyMethodDef PyUNOMethods[] =
{
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
{"__dir__", reinterpret_cast<PyCFunction>(PyUNO_dir), METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
};
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
static PyNumberMethods PyUNONumberMethods[] =
{
nullptr, /* nb_add */
nullptr, /* nb_subtract */
nullptr, /* nb_multiply */
#if PY_MAJOR_VERSION < 3
nullptr, /* nb_divide */
#endif
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
nullptr, /* nb_remainder */
nullptr, /* nb_divmod */
nullptr, /* nb_power */
nullptr, /* nb_negative */
nullptr, /* nb_positive */
nullptr, /* nb_absolute */
PyUNO_bool, /* nb_bool */
nullptr, /* nb_invert */
nullptr, /* nb_lshift */
nullptr, /* nb_rshift */
nullptr, /* nb_and */
nullptr, /* nb_xor */
nullptr, /* nb_or */
#if PY_MAJOR_VERSION < 3
nullptr, /* nb_coerce */
#endif
nullptr, /* nb_int */
nullptr, /* nb_reserved */
nullptr, /* nb_float */
#if PY_MAJOR_VERSION < 3
nullptr, /* nb_oct */
nullptr, /* nb_hex */
#endif
nullptr, /* nb_inplace_add */
nullptr, /* nb_inplace_subtract */
nullptr, /* nb_inplace_multiply */
#if PY_MAJOR_VERSION < 3
nullptr, /* nb_inplace_divide */
#endif
nullptr, /* nb_inplace_remainder */
nullptr, /* nb_inplace_power */
nullptr, /* nb_inplace_lshift */
nullptr, /* nb_inplace_rshift */
nullptr, /* nb_inplace_and */
nullptr, /* nb_inplace_xor */
nullptr, /* nb_inplace_or */
nullptr, /* nb_floor_divide */
nullptr, /* nb_true_divide */
nullptr, /* nb_inplace_floor_divide */
nullptr, /* nb_inplace_true_divide */
nullptr, /* nb_index */
};
static PySequenceMethods PyUNOSequenceMethods[] =
{
nullptr, /* sq_length */
nullptr, /* sq_concat */
nullptr, /* sq_repeat */
nullptr, /* sq_item */
nullptr, /* sq_slice */
nullptr, /* sq_ass_item */
nullptr, /* sq_ass_slice */
PyUNO_contains, /* sq_contains */
nullptr, /* sq_inplace_concat */
nullptr /* sq_inplace_repeat */
};
static PyMappingMethods PyUNOMappingMethods[] =
{
PyUNO_len, /* mp_length */
PyUNO_getitem, /* mp_subscript */
PyUNO_setitem, /* mp_ass_subscript */
};
static PyTypeObject PyUNOType =
{
2011-05-07 20:35:03 +01:00
PyVarObject_HEAD_INIT( &PyType_Type, 0 )
"pyuno",
sizeof (PyUNO),
0,
PyUNO_del,
nullptr,
PyUNO_getattr,
PyUNO_setattr,
/* this type does not exist in Python 3: (cmpfunc) */ 0,
PyUNO_repr,
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
PyUNONumberMethods,
PyUNOSequenceMethods,
PyUNOMappingMethods,
nullptr,
nullptr,
PyUNO_str,
nullptr,
nullptr,
NULL,
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
Py_TPFLAGS_HAVE_ITER | Py_TPFLAGS_HAVE_RICHCOMPARE | Py_TPFLAGS_HAVE_SEQUENCE_IN,
NULL,
nullptr,
nullptr,
PyUNO_cmp,
0,
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') Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978 Reviewed-on: https://gerrit.libreoffice.org/16272 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matthew Francis <mjay.francis@gmail.com>
2015-06-01 18:34:04 +08:00
PyUNO_iter,
nullptr,
PyUNOMethods,
NULL,
NULL,
NULL,
NULL,
nullptr,
nullptr,
0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
NULL,
NULL,
NULL,
NULL,
NULL,
nullptr
#if PY_VERSION_HEX >= 0x02060000
, 0
#endif
#if PY_VERSION_HEX >= 0x03040000
, 0
#endif
};
int PyUNO_initType()
{
return PyType_Ready(&PyUNOType);
}
PyRef getPyUnoClass()
{
return PyRef( reinterpret_cast< PyObject * > ( &PyUNOType ) );
}
PyObject* PyUNO_new (
const Any & targetInterface, const Reference<XSingleServiceFactory> &ssf)
{
Reference<XInterface> tmp_interface;
targetInterface >>= tmp_interface;
if (!tmp_interface.is ())
{
// empty reference !
Py_INCREF( Py_None );
return Py_None;
}
return PyUNO_new_UNCHECKED (targetInterface, ssf);
}
PyObject* PyUNO_new_UNCHECKED (
const Any &targetInterface,
const Reference<XSingleServiceFactory> &ssf )
{
Reference<XInterface> tmp_interface;
Reference<XInvocation2> tmp_invocation;
{
PyThreadDetach antiguard;
Sequence<Any> arguments(1);
arguments[0] <<= targetInterface;
tmp_interface = ssf->createInstanceWithArguments(arguments);
tmp_invocation.set(tmp_interface, UNO_QUERY);
if (!tmp_invocation.is() && tmp_interface.is()) {
throw RuntimeException("XInvocation2 not implemented, cannot interact with object");
}
}
if (!tmp_interface.is())
{
Py_INCREF( Py_None );
return Py_None;
}
PyUNO* self = PyObject_New (PyUNO, &PyUNOType);
if (self == NULL)
return NULL; // == error
self->members = new PyUNOInternals();
self->members->xInvocation = tmp_invocation;
self->members->wrappedObject = targetInterface;
return reinterpret_cast<PyObject*>(self);
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */