1# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
2#
3# This file is part of the LibreOffice project.
4#
5# This Source Code Form is subject to the terms of the Mozilla Public
6# License, v. 2.0. If a copy of the MPL was not distributed with this
7# file, You can obtain one at http://mozilla.org/MPL/2.0/.
8#
9# This file incorporates work covered by the following license notice:
10#
11#   Licensed to the Apache Software Foundation (ASF) under one or more
12#   contributor license agreements. See the NOTICE file distributed
13#   with this work for additional information regarding copyright
14#   ownership. The ASF licenses this file to you under the Apache
15#   License, Version 2.0 (the "License"); you may not use this file
16#   except in compliance with the License. You may obtain a copy of
17#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18#
19import pyuno
20import sys
21import traceback
22import warnings
23
24# since on Windows sal3.dll no longer calls WSAStartup
25import socket
26
27# Some Python 2/3 compatibility code copied from the six library
28PY2 = sys.version_info[0] == 2
29
30if PY2:
31    six_string_types = basestring,
32else:
33    six_string_types = str,
34
35# All functions and variables starting with a underscore (_) must be
36# considered private and can be changed at any time. Don't use them.
37_component_context = pyuno.getComponentContext()
38
39
40def getComponentContext():
41    """Returns the UNO component context used to initialize the Python runtime."""
42
43    return _component_context
44
45
46def getCurrentContext():
47    """Returns the current context.
48
49    See http://udk.openoffice.org/common/man/concept/uno_contexts.html#current_context
50    for an explanation on the current context concept.
51    """
52
53    return pyuno.getCurrentContext()
54
55
56def setCurrentContext(newContext):
57    """Sets newContext as new UNO context.
58
59    The newContext must implement the XCurrentContext interface. The
60    implementation should handle the desired properties and delegate
61    unknown properties to the old context. Ensure that the old one
62    is reset when you leave your stack, see
63    http://udk.openoffice.org/common/man/concept/uno_contexts.html#current_context
64    """
65
66    return pyuno.setCurrentContext(newContext)
67
68
69def getConstantByName(constant):
70    """Looks up the value of an IDL constant by giving its explicit name."""
71
72    return pyuno.getConstantByName(constant)
73
74
75def getTypeByName(typeName):
76    """Returns a `uno.Type` instance of the type given by typeName.
77
78    If the type does not exist, a `com.sun.star.uno.RuntimeException` is raised.
79    """
80
81    return pyuno.getTypeByName(typeName)
82
83
84def createUnoStruct(typeName, *args, **kwargs):
85    """Creates a UNO struct or exception given by typeName.
86
87    Can be called with:
88
89    1) No additional argument.
90       In this case, you get a default constructed UNO structure.
91       (e.g. `createUnoStruct("com.sun.star.uno.Exception")`)
92    2) Exactly one additional argument that is an instance of typeName.
93       In this case, a copy constructed instance of typeName is returned
94       (e.g. `createUnoStruct("com.sun.star.uno.Exception" , e)`)
95    3) As many additional arguments as the number of elements within typeName
96       (e.g. `createUnoStruct("com.sun.star.uno.Exception", "foo error" , self)`).
97    4) Keyword arguments to give values for each element of the struct by name.
98    5) A mix of 3) and 4), such that each struct element is given a value exactly once,
99       either by a positional argument or by a keyword argument.
100
101    The additional and/or keyword arguments must match the type of each struct element,
102    otherwise an exception is thrown.
103    """
104
105    return getClass(typeName)(*args, **kwargs)
106
107
108def getClass(typeName):
109    """Returns the class of a concrete UNO exception, struct, or interface."""
110
111    return pyuno.getClass(typeName)
112
113
114def isInterface(obj):
115    """Returns True, when obj is a class of a UNO interface."""
116
117    return pyuno.isInterface(obj)
118
119
120def generateUuid():
121    """Returns a 16 byte sequence containing a newly generated uuid or guid.
122
123    For more information, see rtl/uuid.h.
124    """
125
126    return pyuno.generateUuid()
127
128
129def systemPathToFileUrl(systemPath):
130    """Returns a file URL for the given system path."""
131
132    return pyuno.systemPathToFileUrl(systemPath)
133
134
135def fileUrlToSystemPath(url):
136    """Returns a system path.
137
138    This path is determined by the system that the Python interpreter is running on.
139    """
140
141    return pyuno.fileUrlToSystemPath(url)
142
143
144def absolutize(path, relativeUrl):
145    """Returns an absolute file url from the given urls."""
146
147    return pyuno.absolutize(path, relativeUrl)
148
149
150class Enum:
151    """Represents a UNO enum.
152
153    Use an instance of this class to explicitly pass an enum to UNO.
154
155    :param typeName: The name of the enum as a string.
156    :param value: The actual value of this enum as a string.
157    """
158
159    def __init__(self, typeName, value):
160        self.typeName = typeName
161        self.value = value
162        pyuno.checkEnum(self)
163
164    def __repr__(self):
165        return "<Enum instance %s (%r)>" % (self.typeName, self.value)
166
167    def __eq__(self, that):
168        if not isinstance(that, Enum):
169            return False
170
171        return (self.typeName == that.typeName) and (self.value == that.value)
172
173    def __ne__(self,other):
174        return not self.__eq__(other)
175
176
177class Type:
178    """Represents a UNO type.
179
180    Use an instance of this class to explicitly pass a type to UNO.
181
182    :param typeName: Name of the UNO type
183    :param typeClass: Python Enum of TypeClass, see com/sun/star/uno/TypeClass.idl
184    """
185
186    def __init__(self, typeName, typeClass):
187        self.typeName = typeName
188        self.typeClass = typeClass
189        pyuno.checkType(self)
190
191    def __repr__(self):
192        return "<Type instance %s (%r)>" % (self.typeName, self.typeClass)
193
194    def __eq__(self, that):
195        if not isinstance(that, Type):
196            return False
197
198        return self.typeClass == that.typeClass and self.typeName == that.typeName
199
200    def __ne__(self,other):
201        return not self.__eq__(other)
202
203    def __hash__(self):
204        return self.typeName.__hash__()
205
206
207class Bool(object):
208    """Represents a UNO boolean.
209
210    Use an instance of this class to explicitly pass a boolean to UNO.
211
212    Note: This class is deprecated. Use Python's True and False directly instead.
213    """
214
215    def __new__(cls, value):
216        message = "The Bool class is deprecated. Use Python's True and False directly instead."
217        warnings.warn(message, DeprecationWarning)
218
219        if isinstance(value, six_string_types) and value == "true":
220            return True
221
222        if isinstance(value, six_string_types) and value == "false":
223            return False
224
225        if value:
226            return True
227
228        return False
229
230
231class Char:
232    """Represents a UNO char.
233
234    Use an instance of this class to explicitly pass a char to UNO.
235
236    For Python 2, this class only works with unicode objects. Creating
237    a Char instance with a normal str object or comparing a Char instance
238    to a normal str object will raise an AssertionError.
239
240    :param value: A Unicode string with length 1
241    """
242
243    def __init__(self, value):
244        if PY2:
245            assert isinstance(value, unicode), "Expected unicode object, got %s instead." % type(value)
246        else:
247            assert isinstance(value, str), "Expected str object, got %s instead." % type(value)
248
249        assert len(value) == 1, "Char value must have length of 1."
250
251        self.value = value
252
253    def __repr__(self):
254        return "<Char instance %s>" % (self.value,)
255
256    def __eq__(self, that):
257        if isinstance(that, six_string_types):
258            if len(that) > 1:
259                return False
260
261            return self.value == that[0]
262
263        if isinstance(that, Char):
264            return self.value == that.value
265
266        return False
267
268    def __ne__(self,other):
269        return not self.__eq__(other)
270
271
272class ByteSequence:
273    """Represents a UNO ByteSequence value.
274
275    Use an instance of this class to explicitly pass a byte sequence to UNO.
276
277    :param value: A string or bytesequence
278    """
279
280    def __init__(self, value):
281        if isinstance(value, bytes):
282            self.value = value
283
284        elif isinstance(value, ByteSequence):
285            self.value = value.value
286
287        else:
288            raise TypeError("Expected bytes object or ByteSequence, got %s instead." % type(value))
289
290    def __repr__(self):
291        return "<ByteSequence instance '%s'>" % (self.value,)
292
293    def __eq__(self, that):
294        if isinstance(that, bytes):
295            return self.value == that
296
297        if isinstance(that, ByteSequence):
298            return self.value == that.value
299
300        return False
301
302    def __len__(self):
303        return len(self.value)
304
305    def __getitem__(self, index):
306        return self.value[index]
307
308    def __iter__(self):
309        return self.value.__iter__()
310
311    def __add__(self, b):
312        if isinstance(b, bytes):
313            return ByteSequence(self.value + b)
314
315        elif isinstance(b, ByteSequence):
316            return ByteSequence(self.value + b.value)
317
318        else:
319            raise TypeError("Can't add ByteString and %s." % type(b))
320
321    def __hash__(self):
322        return self.value.hash()
323
324
325class Any:
326    """Represents a UNO Any value.
327
328    Use only in connection with uno.invoke() to pass an explicit typed Any.
329    """
330
331    def __init__(self, type, value):
332        if isinstance(type, Type):
333            self.type = type
334        else:
335            self.type = getTypeByName(type)
336
337        self.value = value
338
339
340def invoke(object, methodname, argTuple):
341    """Use this function to pass exactly typed Anys to the callee (using uno.Any)."""
342
343    return pyuno.invoke(object, methodname, argTuple)
344
345
346# -----------------------------------------------------------------------------
347# Don't use any functions beyond this point; private section, likely to change.
348# -----------------------------------------------------------------------------
349_builtin_import = __import__
350
351
352def _uno_import(name, *optargs, **kwargs):
353    """Overrides built-in import to allow directly importing LibreOffice classes."""
354
355    try:
356        return _builtin_import(name, *optargs, **kwargs)
357    except ImportError as e:
358        # process optargs
359        globals, locals, fromlist = list(optargs)[:3] + [kwargs.get('globals', {}), kwargs.get('locals', {}),
360                                                         kwargs.get('fromlist', [])][len(optargs):]
361
362        # from import form only, but skip if a uno lookup has already failed
363        if not fromlist or hasattr(e, '_uno_import_failed'):
364            raise
365
366        # hang onto exception for possible use on subsequent uno lookup failure
367        py_import_exc = e
368
369    mod = None
370    d = sys.modules
371
372    for module in name.split("."):
373        if module in d:
374            mod = d[module]
375        else:
376            # How to create a module ??
377            mod = pyuno.__class__(module)
378
379        d = mod.__dict__
380
381    RuntimeException = pyuno.getClass("com.sun.star.uno.RuntimeException")
382
383    for class_name in fromlist:
384        if class_name not in d:
385            failed = False
386
387            try:
388                # check for structs, exceptions or interfaces
389                d[class_name] = pyuno.getClass(name + "." + class_name)
390            except RuntimeException:
391                # check for enums
392                try:
393                    d[class_name] = Enum(name, class_name)
394                except RuntimeException:
395                    # check for constants
396                    try:
397                        d[class_name] = getConstantByName(name + "." + class_name)
398                    except RuntimeException:
399                        # check for constant group
400                        try:
401                            d[class_name] = _impl_getConstantGroupByName(name, class_name)
402                        except ValueError:
403                            failed = True
404
405            if failed:
406                # We have an import failure, but cannot distinguish between
407                # uno and non-uno errors as uno lookups are attempted for all
408                # "from xxx import yyy" imports following a python failure.
409                #
410                # In Python 3, the original python exception traceback is reused
411                # to help pinpoint the actual failing location.  Its original
412                # message, unlike Python 2, is unlikely to be helpful for uno
413                # failures, as it most commonly is just a top level module like
414                # 'com'.  So our exception appends the uno lookup failure.
415                # This is more ambiguous, but it plus the traceback should be
416                # sufficient to identify a root cause for python or uno issues.
417                #
418                # Our exception is raised outside of the nested exception
419                # handlers above, to avoid Python 3 nested exception
420                # information for the RuntimeExceptions during lookups.
421                #
422                # Finally, a private attribute is used to prevent further
423                # processing if this failure was in a nested import.  That
424                # keeps the exception relevant to the primary failure point,
425                # preventing us from re-processing our own import errors.
426
427                uno_import_exc = ImportError("%s (or '%s.%s' is unknown)" %
428                                             (py_import_exc, name, class_name))
429
430                if sys.version_info[0] >= 3:
431                    uno_import_exc = uno_import_exc.with_traceback(py_import_exc.__traceback__)
432
433                uno_import_exc._uno_import_failed = True
434                raise uno_import_exc
435
436    return mod
437
438
439try:
440    import __builtin__
441except ImportError:
442    import builtins as __builtin__
443
444# hook into the __import__ chain
445__builtin__.__dict__['__import__'] = _uno_import
446
447
448class _ConstantGroup(object):
449    """Represents a group of UNOIDL constants."""
450
451    __slots__ = ['_constants']
452
453    def __init__(self, constants):
454        self._constants = constants
455
456    def __dir__(self):
457        return self._constants.keys()
458
459    def __getattr__(self, name):
460        if name in self._constants:
461            return self._constants[name]
462
463        raise AttributeError("The constant '%s' could not be found." % name)
464
465
466def _impl_getConstantGroupByName(module, group):
467    """Gets UNOIDL constant group by name."""
468
469    constants = Enum('com.sun.star.uno.TypeClass', 'CONSTANTS')
470    one = Enum('com.sun.star.reflection.TypeDescriptionSearchDepth', 'ONE')
471    type_desc_mgr = _component_context.getValueByName('/singletons/com.sun.star.reflection.theTypeDescriptionManager')
472    type_descs = type_desc_mgr.createTypeDescriptionEnumeration(module, (constants,), one)
473    qualified_name = module + '.' + group
474
475    for type_desc in type_descs:
476        if type_desc.Name == qualified_name:
477            return _ConstantGroup(dict(
478                (c.Name.split('.')[-1], c.ConstantValue)
479                for c in type_desc.Constants))
480
481    raise ValueError("The constant group '%s' could not be found." % qualified_name)
482
483
484def _uno_struct__init__(self, *args, **kwargs):
485    """Initializes a UNO struct.
486
487    Referenced from the pyuno shared library.
488
489    This function can be called with either an already constructed UNO struct, which it
490    will then just reference without copying, or with arguments to create a new UNO struct.
491    """
492
493    # Check to see if this function was passed an existing UNO struct
494    if len(kwargs) == 0 and len(args) == 1 and getattr(args[0], "__class__", None) == self.__class__:
495        self.__dict__['value'] = args[0]
496    else:
497        struct, used = pyuno._createUnoStructHelper(self.__class__.__pyunostruct__, args, **kwargs)
498
499        for kwarg in kwargs.keys():
500            if not used.get(kwarg):
501                RuntimeException = pyuno.getClass("com.sun.star.uno.RuntimeException")
502                raise RuntimeException("_uno_struct__init__: unused keyword argument '%s'." % kwarg, None)
503
504        self.__dict__["value"] = struct
505
506
507def _uno_struct__getattr__(self, name):
508    """Gets attribute from UNO struct.
509
510    Referenced from the pyuno shared library.
511    """
512
513    return getattr(self.__dict__["value"], name)
514
515
516def _uno_struct__setattr__(self, name, value):
517    """Sets attribute on UNO struct.
518
519    Referenced from the pyuno shared library.
520    """
521
522    return setattr(self.__dict__["value"], name, value)
523
524
525def _uno_struct__repr__(self):
526    """Converts a UNO struct to a printable string.
527
528    Referenced from the pyuno shared library.
529    """
530
531    return repr(self.__dict__["value"])
532
533
534def _uno_struct__str__(self):
535    """Converts a UNO struct to a string."""
536
537    return str(self.__dict__["value"])
538
539def _uno_struct__ne__(self, other):
540    return not self.__eq__(other)
541
542def _uno_struct__eq__(self, that):
543    """Compares two UNO structs.
544
545    Referenced from the pyuno shared library.
546    """
547
548    if hasattr(that, "value"):
549        return self.__dict__["value"] == that.__dict__["value"]
550
551    return False
552
553
554def _uno_extract_printable_stacktrace(trace):
555    """Extracts a printable stacktrace.
556
557    Referenced from pyuno shared lib and pythonscript.py.
558    """
559
560    return ''.join(traceback.format_tb(trace))
561
562# vim: set shiftwidth=4 softtabstop=4 expandtab:
563