This file is indexed.

/usr/lib/python2.7/dist-packages/traits/util/event_tracer.py is in python-traits 4.6.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
#------------------------------------------------------------------------------
#
#  Copyright (c) 2013, Enthought, Inc.
#  All rights reserved.
#
#  This software is provided without warranty under the terms of the BSD
#  license included in enthought/LICENSE.txt and may be redistributed only
#  under the conditions described in the aforementioned license.  The license
#  is also available online at http://www.enthought.com/licenses/BSD.txt
#
#  Thanks for using Enthought open source!
#
#------------------------------------------------------------------------------
""" Record trait change events in single and multi-threaded environments.

"""
import inspect
import os
import threading
from contextlib import contextmanager
from datetime import datetime

from traits import trait_notifiers


CHANGEMSG = (
    u"{time} {direction:-{direction}{length}} {name!r} changed from "
    u"{old!r} to {new!r} in {class_name!r}\n")
CALLINGMSG = u"{time} {action:>{gap}}: {handler!r} in {source}\n"
EXITMSG = (
    u"{time} {direction:-{direction}{length}} "
    u"EXIT: {handler!r}{exception}\n")
SPACES_TO_ALIGN_WITH_CHANGE_MESSAGE = 9


class SentinelRecord(object):
    """ Sentinel record to separate groups of chained change event dispatches.

    """
    __slots__ = ()

    def __unicode__(self):
        return u'\n'


class ChangeMessageRecord(object):
    """ Message record for a change event dispatch.

    """

    __slots__ = ('time', 'indent', 'name', 'old', 'new', 'class_name')

    def __init__(self, time, indent, name, old, new, class_name):
        #: Time stamp in UTC.
        self.time = time
        #: Depth level in a chain of trait change dispatches.
        self.indent = indent
        #: The name of the trait that changed
        self.name = name
        #: The old value.
        self.old = old
        #: The new value.
        self.new = new
        #: The name of the class that the trait change took place.
        self.class_name = class_name

    def __unicode__(self):
        length = self.indent * 2
        return CHANGEMSG.format(
            time=self.time,
            direction='>',
            name=self.name,
            old=self.old,
            new=self.new,
            class_name=self.class_name,
            length=length,
        )


class CallingMessageRecord(object):
    """ Message record for a change handler call.

    """

    __slots__ = ('time', 'indent', 'handler', 'source')

    def __init__(self, time, indent, handler, source):
        #: Time stamp in UTC.
        self.time = time
        #: Depth level of the call in a chain of trait change dispatches.
        self.indent = indent
        #: The traits change handler that is called.
        self.handler = handler
        #: The source file where the handler was defined.
        self.source = source

    def __unicode__(self):
        gap = self.indent * 2 + SPACES_TO_ALIGN_WITH_CHANGE_MESSAGE
        return CALLINGMSG.format(
            time=self.time,
            action='CALLING',
            handler=self.handler,
            source=self.source,
            gap=gap)


class ExitMessageRecord(object):
    """ Message record for returning from a change event dispatch.

    """

    __slots__ = ('time', 'indent', 'handler', 'exception')

    def __init__(self, time, indent, handler, exception):
        #: Time stamp in UTC.
        self.time = time
        #: Depth level of the exit in a chain of trait change dispatch.
        self.indent = indent
        #: The traits change handler that is called.
        self.handler = handler
        #: The exception type (if one took place)
        self.exception = exception

    def __unicode__(self):
        length = self.indent * 2
        return EXITMSG.format(
            time=self.time,
            direction='<',
            handler=self.handler,
            exception=self.exception,
            length=length,
        )


class RecordContainer(object):
    """ A simple record container.

     This class is commonly used to hold records from a single thread.

    """

    def __init__(self):
        self._records = []

    def record(self, record):
        """ Add the record into the container.

        """

        self._records.append(record)

    def save_to_file(self, filename):
        """ Save the records into a file.

        """
        with open(filename, 'w') as fh:
            for record in self._records:
                fh.write(unicode(record))


class MultiThreadRecordContainer(object):
    """ A container of record containers that are used by separate threads.

    Each record container is mapped to a thread name id. When a RecordContainer
    does not exist for a specific thread a new empty RecordContainer will be
    created on request.


    """

    def __init__(self):
        self._creation_lock = threading.Lock()
        self._record_containers = {}

    def get_change_event_collector(self, thread_name):
        """ Return the dedicated RecordContainer for the thread.

        If no RecordContainer is found for `thread_name` then a new
        RecordContainer is created.

        """
        with self._creation_lock:
            container = self._record_containers.get(thread_name)
            if container is None:
                container = RecordContainer()
                self._record_containers[thread_name] = container
            return container

    def save_to_directory(self, directory_name):
        """ Save records files into the directory.

        Each RecordContainer will dump its records on a separate file named
        <thread_name>.trace.

        """
        with self._creation_lock:
            containers = self._record_containers
            for thread_name, container in containers.iteritems():
                filename = os.path.join(
                    directory_name, '{0}.trace'.format(thread_name))
                container.save_to_file(filename)


class ChangeEventRecorder(object):
    """ A single thread trait change event recorder.

    """

    def __init__(self, container):
        """ Class constructor

        Parameters
        ----------
        container : MultiThreadRecordContainer
           An container to store the records for each trait change.

        """
        self.indent = 1
        self.container = container

    def pre_tracer(self, obj, name, old, new, handler):
        """ Record a string representation of the trait change dispatch

        """
        indent = self.indent
        time = datetime.utcnow().isoformat(' ')
        container = self.container
        container.record(
            ChangeMessageRecord(
                time=time,
                indent=indent,
                name=name,
                old=old,
                new=new,
                class_name=obj.__class__.__name__,
            ),
        )

        container.record(
            CallingMessageRecord(
                time=time,
                indent=indent,
                handler=handler.__name__,
                source=inspect.getsourcefile(handler),
            ),
        )
        self.indent += 1

    def post_tracer(self, obj, name, old, new, handler, exception=None):
        """ Record a string representation of the trait change return

        """
        time = datetime.utcnow().isoformat(' ')
        self.indent -= 1
        indent = self.indent
        if exception:
            exception_msg = ' [EXCEPTION: {}]'.format(exception)
        else:
            exception_msg = ''

        container = self.container

        container.record(
            ExitMessageRecord(
                time=time,
                indent=indent,
                handler=handler.__name__,
                exception=exception_msg,
            ),
        )

        if indent == 1:
            container.record(SentinelRecord())


class MultiThreadChangeEventRecorder(object):
    """ A thread aware trait change recorder.

    The class manages multiple ChangeEventRecorders which record trait change
    events for each thread in a separate file.

    """

    def __init__(self, container):
        """ Object constructor

        Parameters
        ----------
        container : MultiThreadChangeEventRecorder
            The container of RecordContainers to keep the trait change records
            for each thread.

        """
        self.tracers = {}
        self._tracer_lock = threading.Lock()
        self.container = container

    def close(self):
        """ Close and stop all logging.

        """
        with self._tracer_lock:
            self.tracers = {}

    def pre_tracer(self, obj, name, old, new, handler):
        """ The traits pre event tracer.

        This method should be set as the global pre event tracer for traits.

        """
        tracer = self._get_tracer()
        tracer.pre_tracer(obj, name, old, new, handler)

    def post_tracer(self, obj, name, old, new, handler, exception=None):
        """ The traits post event tracer.

        This method should be set as the global post event tracer for traits.

        """
        tracer = self._get_tracer()
        tracer.post_tracer(obj, name, old, new, handler, exception=exception)

    def _get_tracer(self):
        with self._tracer_lock:
            thread = threading.current_thread().name
            if thread not in self.tracers:
                container = self.container
                thread_container = container.get_change_event_collector(
                    thread)
                tracer = ChangeEventRecorder(thread_container)
                self.tracers[thread] = tracer
                return tracer
            else:
                return self.tracers[thread]


@contextmanager
def record_events():
    """ Multi-threaded trait change event tracer.

    Usage
    -----
    ::

        >>> from trace_recorder import record_events
        >>> with record_events() as change_event_container:
        ...     my_model.some_trait = True
        >>> change_event_container.save_to_directory('C:\\dev\\trace')

    This will install a tracer that will record all events that occur from
    setting of some_trait on the my_model instance.

    The results will be stored in one file per running thread in the
    directory 'C:\\dev\\trace'.  The files are named after the thread being
    traced.

    """
    container = MultiThreadRecordContainer()
    recorder = MultiThreadChangeEventRecorder(container=container)
    trait_notifiers.set_change_event_tracers(
        pre_tracer=recorder.pre_tracer, post_tracer=recorder.post_tracer)

    try:
        yield container
    finally:
        trait_notifiers.clear_change_event_tracers()
        recorder.close()