~mshinke/nvdajp/betterBraille

« back to all changes in this revision

Viewing changes to source/NVDAObjects/__init__.py

  • Committer: Masataka Shinke
  • Date: 2011-10-25 12:35:26 UTC
  • mfrom: (4175.1.10 jpmain)
  • mto: (4175.1.36 jpmain)
  • mto: This revision was merged to the branch mainline in revision 4193.
  • Revision ID: mshinke@users.sourceforge.jp-20111025123526-ze527a2rl3z0g2ky
lp:~nishimotz/nvdajp/main : 4185 をマージ

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
import weakref
12
12
from logHandler import log
13
13
import eventHandler
 
14
from displayModel import DisplayModelTextInfo
14
15
import baseObject
15
16
import speech
16
17
import api
18
19
import config
19
20
import controlTypes
20
21
import appModuleHandler
21
 
import virtualBufferHandler
 
22
import treeInterceptorHandler
22
23
import braille
 
24
import globalPluginHandler
23
25
 
24
26
class NVDAObjectTextInfo(textInfos.offsets.OffsetsTextInfo):
 
27
        """A default TextInfo which is used to enable text review of information about widgets that don't support text content.
 
28
        The L{NVDAObject.basicText} attribute is used as the text to expose.
 
29
        """
 
30
 
 
31
        def _get_unit_mouseChunk(self):
 
32
                return textInfos.UNIT_STORY
25
33
 
26
34
        def _getStoryText(self):
27
35
                return self.obj.basicText
45
53
        def __call__(self,chooseBestAPI=True,**kwargs):
46
54
                if chooseBestAPI:
47
55
                        APIClass=self.findBestAPIClass(kwargs)
 
56
                        if not APIClass: return None
48
57
                else:
49
58
                        APIClass=self
50
59
 
63
72
                        obj.findOverlayClasses(clsList)
64
73
                else:
65
74
                        clsList.append(APIClass)
66
 
                # Allow app modules to add overlay classes.
 
75
                # Allow app modules to choose overlay classes.
67
76
                appModule=obj.appModule
68
77
                if appModule and "chooseNVDAObjectOverlayClasses" in appModule.__class__.__dict__:
69
78
                        appModule.chooseNVDAObjectOverlayClasses(obj, clsList)
 
79
                # Allow global plugins to choose overlay classes.
 
80
                for plugin in globalPluginHandler.runningPlugins:
 
81
                        if "chooseNVDAObjectOverlayClasses" in plugin.__class__.__dict__:
 
82
                                plugin.chooseNVDAObjectOverlayClasses(obj, clsList)
70
83
 
71
84
                # Determine the bases for the new class.
72
85
                bases=[]
73
86
                for index in xrange(len(clsList)):
74
 
                        # A class doesn't need to be a base if it is already a subclass of a previous base.
 
87
                        # A class doesn't need to be a base if it is already implicitly included by being a superclass of a previous base.
75
88
                        if index==0 or not issubclass(clsList[index-1],clsList[index]):
76
89
                                bases.append(clsList[index])
77
90
 
99
112
                        initFunc=cls.__dict__.get("initOverlayClass")
100
113
                        if initFunc:
101
114
                                initFunc(obj)
 
115
                        # Bind gestures specified on the class.
 
116
                        try:
 
117
                                obj.bindGestures(getattr(cls, "_%s__gestures" % cls.__name__))
 
118
                        except AttributeError:
 
119
                                pass
102
120
 
103
121
                # Allow app modules to make minor tweaks to the instance.
104
122
                if appModule and hasattr(appModule,"event_NVDAObject_init"):
106
124
 
107
125
                return obj
108
126
 
 
127
        @classmethod
 
128
        def clearDynamicClassCache(cls):
 
129
                """Clear the dynamic class cache.
 
130
                This should be called when a plugin is unloaded so that any used overlay classes in the unloaded plugin can be garbage collected.
 
131
                """
 
132
                cls._dynamicClassCache.clear()
 
133
 
109
134
class NVDAObject(baseObject.ScriptableObject):
110
 
        """
111
 
        NVDA's representation of a control or widget in the Operating System. Provides information such as a name, role, value, description etc.
 
135
        """NVDA's representation of a single control/widget.
 
136
        Every widget, regardless of how it is exposed by an application or the operating system, is represented by a single NVDAObject instance.
 
137
        This allows NVDA to work with all widgets in a uniform way.
 
138
        An NVDAObject provides information about the widget (e.g. its name, role and value),
 
139
        as well as functionality to manipulate it (e.g. perform an action or set focus).
 
140
        Events for the widget are handled by special event methods on the object.
 
141
        Commands triggered by input from the user can also be handled by special methods called scripts.
 
142
        See L{ScriptableObject} for more details.
 
143
        
 
144
        The only attribute that absolutely must be provided is L{processID}.
 
145
        However, subclasses should provide at least the L{name} and L{role} attributes in order for the object to be meaningful to the user.
 
146
        Attributes such as L{parent}, L{firstChild}, L{next} and L{previous} link an instance to other NVDAObjects in the hierarchy.
 
147
        In order to facilitate access to text exposed by a widget which supports text content (e.g. an editable text control),
 
148
        a L{textInfos.TextInfo} should be implemented and the L{TextInfo} attribute should specify this class.
 
149
        
 
150
        There are two main types of NVDAObject classes:
 
151
                * API classes, which provide the core functionality to work with objects exposed using a particular API (e.g. MSAA/IAccessible).
 
152
                * Overlay classes, which supplement the core functionality provided by an API class to handle a specific widget or type of widget.
 
153
        Most developers need only be concerned with overlay classes.
 
154
        The overlay classes to be used for an instance are determined using the L{findOverlayClasses} method on the API class.
 
155
        An L{AppModule} can also choose overlay classes for an instance using the L{AppModule.chooseNVDAObjectOverlayClasses} method.
112
156
        """
113
157
 
114
158
        __metaclass__=DynamicNVDAObjectType
115
159
        cachePropertiesByDefault = True
116
160
 
117
 
        TextInfo=NVDAObjectTextInfo #:The TextInfo class this object should use
 
161
        #: The TextInfo class this object should use to provide access to text.
 
162
        #: @type: type; L{textInfos.TextInfo}
 
163
        TextInfo=NVDAObjectTextInfo
118
164
 
119
165
        @classmethod
120
166
        def findBestAPIClass(cls,kwargs,relation=None):
135
181
                                        continue
136
182
                                if possibleAPIClass.kwargsFromSuper(kwargs,relation=relation):
137
183
                                        return possibleAPIClass.findBestAPIClass(kwargs,relation=relation)
138
 
                return newAPIClass
 
184
                return newAPIClass if newAPIClass is not NVDAObject else None
 
185
 
139
186
 
140
187
        @classmethod
141
188
        def getPossibleAPIClasses(cls,kwargs,relation=None):
194
241
                """
195
242
                kwargs={}
196
243
                APIClass=NVDAObject.findBestAPIClass(kwargs,relation=(x,y))
197
 
                return APIClass(chooseBestAPI=False,**kwargs)
 
244
                return APIClass(chooseBestAPI=False,**kwargs) if APIClass else None
198
245
 
199
246
        @staticmethod
200
247
        def objectWithFocus():
204
251
                """
205
252
                kwargs={}
206
253
                APIClass=NVDAObject.findBestAPIClass(kwargs,relation="focus")
207
 
                return APIClass(chooseBestAPI=False,**kwargs)
 
254
                return APIClass(chooseBestAPI=False,**kwargs) if APIClass else None
208
255
 
209
256
        @staticmethod
210
257
        def objectInForeground():
214
261
                """
215
262
                kwargs={}
216
263
                APIClass=NVDAObject.findBestAPIClass(kwargs,relation="foreground")
217
 
                return APIClass(chooseBestAPI=False,**kwargs)
 
264
                return APIClass(chooseBestAPI=False,**kwargs) if APIClass else None
 
265
 
218
266
 
219
267
        def __init__(self):
220
268
                super(NVDAObject,self).__init__()
244
292
                """
245
293
                return not self.__eq__(other)
246
294
 
247
 
        def _get_virtualBufferClass(self):
 
295
        def _get_treeInterceptorClass(self):
248
296
                """
249
 
                If this NVDAObject should use a virtualBuffer, then this property provides the L{virtualBuffers.VirtualBuffer} class it should use. 
 
297
                If this NVDAObject should use a treeInterceptor, then this property provides the L{treeInterceptorHandler.TreeInterceptor} class it should use. 
250
298
                If not then it should be not implemented.
251
299
                """
252
300
                raise NotImplementedError
253
301
 
254
 
        def _get_virtualBuffer(self):
255
 
                """Retreaves the virtualBuffer associated with this object.
256
 
                If a virtualBuffer has not been specifically set, the L{virtualBufferHandler} is asked if it can find a virtualBuffer containing this object.
257
 
                @return: the virtualBuffer
258
 
                @rtype: L{virtualBuffers.VirtualBuffer}
 
302
        def _get_treeInterceptor(self):
 
303
                """Retreaves the treeInterceptor associated with this object.
 
304
                If a treeInterceptor has not been specifically set, the L{treeInterceptorHandler} is asked if it can find a treeInterceptor containing this object.
 
305
                @return: the treeInterceptor
 
306
                @rtype: L{treeInterceptorHandler.TreeInterceptor}
259
307
                """ 
260
 
                if hasattr(self,'_virtualBuffer'):
261
 
                        v=self._virtualBuffer
262
 
                        if isinstance(v,weakref.ref):
263
 
                                v=v()
264
 
                        if v and v in virtualBufferHandler.runningTable:
265
 
                                return v
 
308
                if hasattr(self,'_treeInterceptor'):
 
309
                        ti=self._treeInterceptor
 
310
                        if isinstance(ti,weakref.ref):
 
311
                                ti=ti()
 
312
                        if ti and ti in treeInterceptorHandler.runningTable:
 
313
                                return ti
266
314
                        else:
267
 
                                self._virtualBuffer=None
 
315
                                self._treeInterceptor=None
268
316
                                return None
269
317
                else:
270
 
                        v=virtualBufferHandler.getVirtualBuffer(self)
271
 
                        if v:
272
 
                                self._virtualBuffer=weakref.ref(v)
273
 
                        return v
 
318
                        ti=treeInterceptorHandler.getTreeInterceptor(self)
 
319
                        if ti:
 
320
                                self._treeInterceptor=weakref.ref(ti)
 
321
                        return ti
274
322
 
275
 
        def _set_virtualBuffer(self,obj):
276
 
                """Specifically sets a virtualBuffer to be associated with this object.
 
323
        def _set_treeInterceptor(self,obj):
 
324
                """Specifically sets a treeInterceptor to be associated with this object.
277
325
                """
278
326
                if obj:
279
 
                        self._virtualBuffer=weakref.ref(obj)
 
327
                        self._treeInterceptor=weakref.ref(obj)
280
328
                else: #We can't point a weakref to None, so just set the private variable to None, it can handle that
281
 
                        self._virtualBuffer=None
 
329
                        self._treeInterceptor=None
282
330
 
283
331
        def _get_appModule(self):
284
332
                """Retreaves the appModule representing the application this object is a part of by asking L{appModuleHandler}.
375
423
                """
376
424
                return None
377
425
 
 
426
        def _get_container(self):
 
427
                """
 
428
                Exactly like parent, however another object at this same sibling level may be retreaved first (e.g. a groupbox). Mostly used when presenting context such as focus ancestry.
 
429
                """
 
430
                return self.parent
 
431
 
378
432
        def _get_next(self):
379
433
                """Retreaves the object directly after this object with the same parent.
380
434
                @return: the next object if it exists else None.
438
492
                """
439
493
                raise NotImplementedError
440
494
 
 
495
        tableCellCoordsInName=False #:True if the object's name contains the cell coordinates, such as 'A1'. Speech and Braille can choose to in this case not present the actual row and column information as the name is already enough.
 
496
 
441
497
        def _get_table(self):
442
498
                """Retreaves the object that represents the table that this object is contained in, if this object is a table cell.
443
499
                @rtype: L{NVDAObject}
464
520
                if controlTypes.STATE_INVISIBLE in states or controlTypes.STATE_UNAVAILABLE in states:
465
521
                        return self.presType_unavailable
466
522
                role=self.role
467
 
                if controlTypes.STATE_FOCUSED in states:
468
 
                        return self.presType_content
469
523
 
470
524
                #Static text should be content only if it really use usable text
471
525
                if role==controlTypes.ROLE_STATICTEXT:
472
526
                        text=self.makeTextInfo(textInfos.POSITION_ALL).text
473
527
                        return self.presType_content if text and not text.isspace() else self.presType_layout
474
528
 
475
 
                if role in (controlTypes.ROLE_UNKNOWN, controlTypes.ROLE_PANE, controlTypes.ROLE_ROOTPANE, controlTypes.ROLE_LAYEREDPANE, controlTypes.ROLE_SCROLLPANE, controlTypes.ROLE_SECTION,controlTypes.ROLE_PARAGRAPH,controlTypes.ROLE_TITLEBAR):
 
529
                if role in (controlTypes.ROLE_UNKNOWN, controlTypes.ROLE_PANE, controlTypes.ROLE_TEXTFRAME, controlTypes.ROLE_ROOTPANE, controlTypes.ROLE_LAYEREDPANE, controlTypes.ROLE_SCROLLPANE, controlTypes.ROLE_SECTION,controlTypes.ROLE_PARAGRAPH,controlTypes.ROLE_TITLEBAR,controlTypes.ROLE_LABEL):
476
530
                        return self.presType_layout
477
531
                name = self.name
478
532
                description = self.description
479
 
                if not name and not description and role in (controlTypes.ROLE_WINDOW,controlTypes.ROLE_LABEL,controlTypes.ROLE_PANEL, controlTypes.ROLE_PROPERTYPAGE, controlTypes.ROLE_TEXTFRAME, controlTypes.ROLE_GROUPING,controlTypes.ROLE_OPTIONPANE,controlTypes.ROLE_INTERNALFRAME,controlTypes.ROLE_FORM,controlTypes.ROLE_TABLEBODY):
480
 
                        return self.presType_layout
481
 
                if not name and not description and role in (controlTypes.ROLE_TABLE,controlTypes.ROLE_TABLEROW,controlTypes.ROLE_TABLECOLUMN,controlTypes.ROLE_TABLECELL) and not config.conf["documentFormatting"]["reportTables"]:
482
 
                        return self.presType_layout
 
533
                if not name and not description:
 
534
                        if role in (controlTypes.ROLE_WINDOW,controlTypes.ROLE_PANEL, controlTypes.ROLE_PROPERTYPAGE, controlTypes.ROLE_TEXTFRAME, controlTypes.ROLE_GROUPING,controlTypes.ROLE_OPTIONPANE,controlTypes.ROLE_INTERNALFRAME,controlTypes.ROLE_FORM,controlTypes.ROLE_TABLEBODY):
 
535
                                return self.presType_layout
 
536
                        if role == controlTypes.ROLE_TABLE and not config.conf["documentFormatting"]["reportTables"]:
 
537
                                return self.presType_layout
 
538
                        if role in (controlTypes.ROLE_TABLEROW,controlTypes.ROLE_TABLECOLUMN,controlTypes.ROLE_TABLECELL) and (not config.conf["documentFormatting"]["reportTables"] or not config.conf["documentFormatting"]["reportTableCellCoords"]):
 
539
                                return self.presType_layout
483
540
                if role in (controlTypes.ROLE_TABLEROW,controlTypes.ROLE_TABLECOLUMN):
484
541
                        try:
485
542
                                table=self.table
602
659
                """
603
660
                return False
604
661
 
 
662
        def _get_indexInParent(self):
 
663
                """The index of this object in its parent object.
 
664
                @return: The 0 based index, C{None} if there is no parent.
 
665
                @rtype: int
 
666
                @raise NotImplementedError: If not supported by the underlying object.
 
667
                """
 
668
                raise NotImplementedError
 
669
 
 
670
        def _get_flowsTo(self):
 
671
                """The object to which content flows from this object.
 
672
                @return: The object to which this object flows, C{None} if none.
 
673
                @rtype: L{NVDAObject}
 
674
                @raise NotImplementedError: If not supported by the underlying object.
 
675
                """
 
676
                raise NotImplementedError
 
677
 
 
678
        def _get_flowsFrom(self):
 
679
                """The object from which content flows to this object.
 
680
                @return: The object from which this object flows, C{None} if none.
 
681
                @rtype: L{NVDAObject}
 
682
                @raise NotImplementedError: If not supported by the underlying object.
 
683
                """
 
684
                raise NotImplementedError
 
685
 
 
686
        def _get_embeddingTextInfo(self):
 
687
                """Retrieve the parent text range which embeds this object.
 
688
                The returned text range will have its start positioned on the embedded object character associated with this object.
 
689
                That is, calling L{textInfos.TextInfo.getEmbeddedObject}() on the returned text range will return this object.
 
690
                @return: The text range for the embedded object character associated with this object or C{None} if this is not an embedded object.
 
691
                @rtype: L{textInfos.TextInfo}
 
692
                @raise NotImplementedError: If not supported.
 
693
                """
 
694
                raise NotImplementedError
 
695
 
605
696
        def _get_isPresentableFocusAncestor(self):
606
697
                """Determine if this object should be presented to the user in the focus ancestry.
607
698
                @return: C{True} if it should be presented in the focus ancestry, C{False} if not.
620
711
                """
621
712
                return None
622
713
 
623
 
        def speakDescendantObjects(self,hashList=None):
624
 
                """Speaks all the descendants of this object.
625
 
                """
626
 
                if hashList is None:
627
 
                        hashList=[]
628
 
                for child in self.children:
629
 
                        h=hash(child)
630
 
                        if h not in hashList:
631
 
                                hashList.append(h)
632
 
                                speech.speakObject(child)
633
 
                                child.speakDescendantObjects(hashList=hashList)
634
 
 
635
714
        def reportFocus(self):
636
715
                """Announces this object in a way suitable such that it gained focus.
637
716
                """
639
718
 
640
719
        def event_typedCharacter(self,ch):
641
720
                speech.speakTypedCharacters(ch)
642
 
 
 
721
                import winUser
 
722
                if config.conf["keyboard"]["beepForLowercaseWithCapslock"] and ch.islower() and winUser.getKeyState(winUser.VK_CAPITAL)&1:
 
723
                        import tones
 
724
                        tones.beep(3000,40)
643
725
 
644
726
        def event_mouseMove(self,x,y):
645
727
                if not self._mouseEntered and config.conf['mouse']['reportObjectRoleOnMouseEnter']:
651
733
                self._mouseEntered=True
652
734
                try:
653
735
                        info=self.makeTextInfo(textInfos.Point(x,y))
654
 
                        info.expand(info.unit_mouseChunk)
655
 
                except:
656
 
                        info=NVDAObjectTextInfo(self,textInfos.POSITION_ALL)
 
736
                except NotImplementedError:
 
737
                        info=NVDAObjectTextInfo(self,textInfos.POSITION_FIRST)
 
738
                except LookupError:
 
739
                        return
657
740
                if config.conf["reviewCursor"]["followMouse"]:
658
741
                        api.setReviewPosition(info)
659
 
                if not config.conf["mouse"]["reportTextUnderMouse"]:
660
 
                        return
 
742
                info.expand(info.unit_mouseChunk)
661
743
                oldInfo=getattr(self,'_lastMouseTextInfoObject',None)
662
744
                self._lastMouseTextInfoObject=info
663
745
                if not oldInfo or info.__class__!=oldInfo.__class__ or info.compareEndPoints(oldInfo,"startToStart")!=0 or info.compareEndPoints(oldInfo,"endToEnd")!=0:
721
803
        def event_caret(self):
722
804
                if self is api.getFocusObject() and not eventHandler.isPendingEvents("gainFocus"):
723
805
                        braille.handler.handleCaretMove(self)
724
 
                        if config.conf["reviewCursor"]["followCaret"]:
 
806
                        if config.conf["reviewCursor"]["followCaret"] and api.getNavigatorObject() is self: 
725
807
                                try:
726
808
                                        api.setReviewPosition(self.makeTextInfo(textInfos.POSITION_CARET))
727
809
                                except (NotImplementedError, RuntimeError):
728
810
                                        pass
729
811
 
 
812
        def _get_flatReviewPosition(self):
 
813
                """Locates a TextInfo positioned at this object, in the closest flat review."""
 
814
                parent=self.simpleParent
 
815
                while parent:
 
816
                        ti=parent.treeInterceptor
 
817
                        if ti and self in ti and ti.rootNVDAObject==parent:
 
818
                                return ti.makeTextInfo(self)
 
819
                        if issubclass(parent.TextInfo,DisplayModelTextInfo):
 
820
                                try:
 
821
                                        return parent.makeTextInfo(api.getReviewPosition().pointAtStart)
 
822
                                except (NotImplementedError,LookupError):
 
823
                                        pass
 
824
                                try:
 
825
                                        return parent.makeTextInfo(self)
 
826
                                except (NotImplementedError,RuntimeError):
 
827
                                        pass
 
828
                                return parent.makeTextInfo(textInfos.POSITION_FIRST)
 
829
                        parent=parent.simpleParent
 
830
 
730
831
        def _get_basicText(self):
731
832
                newTime=time.time()
732
833
                oldTime=getattr(self,'_basicTextTime',0)
733
834
                if newTime-oldTime>0.5:
734
 
                        self._basicText=" ".join([x for x in self.name, self.value, self.description if isinstance(x, basestring) and len(x) > 0 and not x.isspace()])
 
835
                        self._basicText=u" ".join([x for x in self.name, self.value, self.description if isinstance(x, basestring) and len(x) > 0 and not x.isspace()])
735
836
                        if len(self._basicText)==0:
736
 
                                self._basicText="\n"
 
837
                                self._basicText=u""
737
838
                else:
738
839
                        self._basicTextTime=newTime
739
840
                return self._basicText
741
842
        def makeTextInfo(self,position):
742
843
                return self.TextInfo(self,position)
743
844
 
744
 
class AutoSelectDetectionNVDAObject(NVDAObject):
745
 
 
746
 
        """Provides an NVDAObject with the means to detect if the text selection has changed, and if so to announce the change
747
 
        @ivar hasContentChangedSinceLastSelection: if True then the content has changed.
748
 
        @ivar hasContentChangedSinceLastSelection: boolean
749
 
        """
750
 
 
751
 
        def initAutoSelectDetection(self):
752
 
                """Initializes the autoSelect detection code so that it knows about what is currently selected."""
753
 
                try:
754
 
                        self._lastSelectionPos=self.makeTextInfo(textInfos.POSITION_SELECTION)
755
 
                except:
756
 
                        self._lastSelectionPos=None
757
 
                self.hasContentChangedSinceLastSelection=False
758
 
 
759
 
        def detectPossibleSelectionChange(self):
760
 
                """Detects if the selection has been changed, and if so it speaks the change."""
761
 
                oldInfo=getattr(self,'_lastSelectionPos',None)
762
 
                if not oldInfo:
763
 
                        return
764
 
                try:
765
 
                        newInfo=self.makeTextInfo(textInfos.POSITION_SELECTION)
766
 
                except:
767
 
                        self._lastSelectionPos=None
768
 
                        return
769
 
                self._lastSelectionPos=newInfo.copy()
770
 
                hasContentChanged=self.hasContentChangedSinceLastSelection
771
 
                self.hasContentChangedSinceLastSelection=False
772
 
                if hasContentChanged:
773
 
                        generalize=True
774
 
                else:
775
 
                        generalize=False
776
 
                speech.speakSelectionChange(oldInfo,newInfo,generalize=generalize)
 
845
        def _get_devInfo(self):
 
846
                """Information about this object useful to developers.
 
847
                Subclasses may extend this, calling the superclass property first.
 
848
                @return: A list of text strings providing information about this object useful to developers.
 
849
                @rtype: list of str
 
850
                """
 
851
                info = []
 
852
                try:
 
853
                        ret = repr(self.name)
 
854
                except Exception as e:
 
855
                        ret = "exception: %s" % e
 
856
                info.append("name: %s" % ret)
 
857
                try:
 
858
                        ret = self.role
 
859
                        for name, const in controlTypes.__dict__.iteritems():
 
860
                                if name.startswith("ROLE_") and ret == const:
 
861
                                        ret = name
 
862
                                        break
 
863
                except Exception as e:
 
864
                        ret = "exception: %s" % e
 
865
                info.append("role: %s" % ret)
 
866
                try:
 
867
                        stateConsts = dict((const, name) for name, const in controlTypes.__dict__.iteritems() if name.startswith("STATE_"))
 
868
                        ret = ", ".join(
 
869
                                stateConsts.get(state) or str(state)
 
870
                                for state in self.states)
 
871
                except Exception as e:
 
872
                        ret = "exception: %s" % e
 
873
                info.append("states: %s" % ret)
 
874
                try:
 
875
                        ret = repr(self)
 
876
                except Exception as e:
 
877
                        ret = "exception: %s" % e
 
878
                info.append("Python object: %s" % ret)
 
879
                try:
 
880
                        ret = repr(self.__class__.__mro__)
 
881
                except Exception as e:
 
882
                        ret = "exception: %s" % e
 
883
                info.append("Python class mro: %s" % ret)
 
884
                try:
 
885
                        ret = repr(self.description)
 
886
                except Exception as e:
 
887
                        ret = "exception: %s" % e
 
888
                info.append("description: %s" % ret)
 
889
                try:
 
890
                        ret = repr(self.location)
 
891
                except Exception as e:
 
892
                        ret = "exception: %s" % e
 
893
                info.append("location: %s" % ret)
 
894
                try:
 
895
                        ret = self.value
 
896
                        if isinstance(ret, basestring) and len(ret) > 100:
 
897
                                ret = "%r (truncated)" % ret[:100]
 
898
                        else:
 
899
                                ret = repr(ret)
 
900
                except Exception as e:
 
901
                        ret = "exception: %s" % e
 
902
                info.append("value: %s" % ret)
 
903
                try:
 
904
                        ret = repr(self.appModule)
 
905
                except Exception as e:
 
906
                        ret = "exception: %s" % e
 
907
                info.append("appModule: %s" % ret)
 
908
                try:
 
909
                        ret = repr(self.TextInfo)
 
910
                except Exception as e:
 
911
                        ret = "exception: %s" % e
 
912
                info.append("TextInfo: %s" % ret)
 
913
                return info