~canonical-livepatch-dependencies/canonical-livepatch-service-dependencies/twisted

« back to all changes in this revision

Viewing changes to twisted/test/test_reflect.py

  • Committer: Free Ekanayaka
  • Date: 2016-07-01 12:22:33 UTC
  • Revision ID: free.ekanayaka@canonical.com-20160701122233-nh55w514zwzoz1ip
Tags: upstream-16.2.0
ImportĀ upstreamĀ versionĀ 16.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
"""
 
5
Test cases for the L{twisted.python.reflect} module.
 
6
"""
 
7
 
 
8
from __future__ import division, absolute_import
 
9
 
 
10
import os
 
11
import weakref
 
12
from collections import deque
 
13
 
 
14
from twisted.python.compat import _PY3
 
15
from twisted.trial import unittest
 
16
from twisted.trial.unittest import SynchronousTestCase as TestCase
 
17
from twisted.python import reflect
 
18
from twisted.python.reflect import (
 
19
    accumulateMethods, prefixedMethods, prefixedMethodNames,
 
20
    addMethodNamesToDict, fullyQualifiedName)
 
21
from twisted.python.versions import Version
 
22
 
 
23
 
 
24
class Base(object):
 
25
    """
 
26
    A no-op class which can be used to verify the behavior of
 
27
    method-discovering APIs.
 
28
    """
 
29
 
 
30
    def method(self):
 
31
        """
 
32
        A no-op method which can be discovered.
 
33
        """
 
34
 
 
35
 
 
36
 
 
37
class Sub(Base):
 
38
    """
 
39
    A subclass of a class with a method which can be discovered.
 
40
    """
 
41
 
 
42
 
 
43
 
 
44
class Separate(object):
 
45
    """
 
46
    A no-op class with methods with differing prefixes.
 
47
    """
 
48
 
 
49
    def good_method(self):
 
50
        """
 
51
        A no-op method which a matching prefix to be discovered.
 
52
        """
 
53
 
 
54
 
 
55
    def bad_method(self):
 
56
        """
 
57
        A no-op method with a mismatched prefix to not be discovered.
 
58
        """
 
59
 
 
60
 
 
61
 
 
62
class AccumulateMethodsTests(TestCase):
 
63
    """
 
64
    Tests for L{accumulateMethods} which finds methods on a class hierarchy and
 
65
    adds them to a dictionary.
 
66
    """
 
67
 
 
68
    def test_ownClass(self):
 
69
        """
 
70
        If x is and instance of Base and Base defines a method named method,
 
71
        L{accumulateMethods} adds an item to the given dictionary with
 
72
        C{"method"} as the key and a bound method object for Base.method value.
 
73
        """
 
74
        x = Base()
 
75
        output = {}
 
76
        accumulateMethods(x, output)
 
77
        self.assertEqual({"method": x.method}, output)
 
78
 
 
79
 
 
80
    def test_baseClass(self):
 
81
        """
 
82
        If x is an instance of Sub and Sub is a subclass of Base and Base
 
83
        defines a method named method, L{accumulateMethods} adds an item to the
 
84
        given dictionary with C{"method"} as the key and a bound method object
 
85
        for Base.method as the value.
 
86
        """
 
87
        x = Sub()
 
88
        output = {}
 
89
        accumulateMethods(x, output)
 
90
        self.assertEqual({"method": x.method}, output)
 
91
 
 
92
 
 
93
    def test_prefix(self):
 
94
        """
 
95
        If a prefix is given, L{accumulateMethods} limits its results to
 
96
        methods beginning with that prefix.  Keys in the resulting dictionary
 
97
        also have the prefix removed from them.
 
98
        """
 
99
        x = Separate()
 
100
        output = {}
 
101
        accumulateMethods(x, output, 'good_')
 
102
        self.assertEqual({'method': x.good_method}, output)
 
103
 
 
104
 
 
105
 
 
106
class PrefixedMethodsTests(TestCase):
 
107
    """
 
108
    Tests for L{prefixedMethods} which finds methods on a class hierarchy and
 
109
    adds them to a dictionary.
 
110
    """
 
111
 
 
112
    def test_onlyObject(self):
 
113
        """
 
114
        L{prefixedMethods} returns a list of the methods discovered on an
 
115
        object.
 
116
        """
 
117
        x = Base()
 
118
        output = prefixedMethods(x)
 
119
        self.assertEqual([x.method], output)
 
120
 
 
121
 
 
122
    def test_prefix(self):
 
123
        """
 
124
        If a prefix is given, L{prefixedMethods} returns only methods named
 
125
        with that prefix.
 
126
        """
 
127
        x = Separate()
 
128
        output = prefixedMethods(x, 'good_')
 
129
        self.assertEqual([x.good_method], output)
 
130
 
 
131
 
 
132
 
 
133
class PrefixedMethodNamesTests(TestCase):
 
134
    """
 
135
    Tests for L{prefixedMethodNames}.
 
136
    """
 
137
    def test_method(self):
 
138
        """
 
139
        L{prefixedMethodNames} returns a list including methods with the given
 
140
        prefix defined on the class passed to it.
 
141
        """
 
142
        self.assertEqual(["method"], prefixedMethodNames(Separate, "good_"))
 
143
 
 
144
 
 
145
    def test_inheritedMethod(self):
 
146
        """
 
147
        L{prefixedMethodNames} returns a list included methods with the given
 
148
        prefix defined on base classes of the class passed to it.
 
149
        """
 
150
        class Child(Separate):
 
151
            pass
 
152
        self.assertEqual(["method"], prefixedMethodNames(Child, "good_"))
 
153
 
 
154
 
 
155
 
 
156
class AddMethodNamesToDictTests(TestCase):
 
157
    """
 
158
    Tests for L{addMethodNamesToDict}.
 
159
    """
 
160
    def test_baseClass(self):
 
161
        """
 
162
        If C{baseClass} is passed to L{addMethodNamesToDict}, only methods which
 
163
        are a subclass of C{baseClass} are added to the result dictionary.
 
164
        """
 
165
        class Alternate(object):
 
166
            pass
 
167
 
 
168
        class Child(Separate, Alternate):
 
169
            def good_alternate(self):
 
170
                pass
 
171
 
 
172
        result = {}
 
173
        addMethodNamesToDict(Child, result, 'good_', Alternate)
 
174
        self.assertEqual({'alternate': 1}, result)
 
175
 
 
176
 
 
177
 
 
178
class Summer(object):
 
179
    """
 
180
    A class we look up as part of the LookupsTests.
 
181
    """
 
182
 
 
183
    def reallySet(self):
 
184
        """
 
185
        Do something.
 
186
        """
 
187
 
 
188
 
 
189
 
 
190
class LookupsTests(TestCase):
 
191
    """
 
192
    Tests for L{namedClass}, L{namedModule}, and L{namedAny}.
 
193
    """
 
194
 
 
195
    def test_namedClassLookup(self):
 
196
        """
 
197
        L{namedClass} should return the class object for the name it is passed.
 
198
        """
 
199
        self.assertIdentical(
 
200
            reflect.namedClass("twisted.test.test_reflect.Summer"),
 
201
            Summer)
 
202
 
 
203
 
 
204
    def test_namedModuleLookup(self):
 
205
        """
 
206
        L{namedModule} should return the module object for the name it is
 
207
        passed.
 
208
        """
 
209
        from twisted.python import monkey
 
210
        self.assertIdentical(
 
211
            reflect.namedModule("twisted.python.monkey"), monkey)
 
212
 
 
213
 
 
214
    def test_namedAnyPackageLookup(self):
 
215
        """
 
216
        L{namedAny} should return the package object for the name it is passed.
 
217
        """
 
218
        import twisted.python
 
219
        self.assertIdentical(
 
220
            reflect.namedAny("twisted.python"), twisted.python)
 
221
 
 
222
 
 
223
    def test_namedAnyModuleLookup(self):
 
224
        """
 
225
        L{namedAny} should return the module object for the name it is passed.
 
226
        """
 
227
        from twisted.python import monkey
 
228
        self.assertIdentical(
 
229
            reflect.namedAny("twisted.python.monkey"), monkey)
 
230
 
 
231
 
 
232
    def test_namedAnyClassLookup(self):
 
233
        """
 
234
        L{namedAny} should return the class object for the name it is passed.
 
235
        """
 
236
        self.assertIdentical(
 
237
            reflect.namedAny("twisted.test.test_reflect.Summer"),
 
238
            Summer)
 
239
 
 
240
 
 
241
    def test_namedAnyAttributeLookup(self):
 
242
        """
 
243
        L{namedAny} should return the object an attribute of a non-module,
 
244
        non-package object is bound to for the name it is passed.
 
245
        """
 
246
        # Note - not assertIs because unbound method lookup creates a new
 
247
        # object every time.  This is a foolishness of Python's object
 
248
        # implementation, not a bug in Twisted.
 
249
        self.assertEqual(
 
250
            reflect.namedAny(
 
251
                "twisted.test.test_reflect.Summer.reallySet"),
 
252
            Summer.reallySet)
 
253
 
 
254
 
 
255
    def test_namedAnySecondAttributeLookup(self):
 
256
        """
 
257
        L{namedAny} should return the object an attribute of an object which
 
258
        itself was an attribute of a non-module, non-package object is bound to
 
259
        for the name it is passed.
 
260
        """
 
261
        self.assertIdentical(
 
262
            reflect.namedAny(
 
263
                "twisted.test.test_reflect."
 
264
                "Summer.reallySet.__doc__"),
 
265
            Summer.reallySet.__doc__)
 
266
 
 
267
 
 
268
    def test_importExceptions(self):
 
269
        """
 
270
        Exceptions raised by modules which L{namedAny} causes to be imported
 
271
        should pass through L{namedAny} to the caller.
 
272
        """
 
273
        self.assertRaises(
 
274
            ZeroDivisionError,
 
275
            reflect.namedAny, "twisted.test.reflect_helper_ZDE")
 
276
        # Make sure that there is post-failed-import cleanup
 
277
        self.assertRaises(
 
278
            ZeroDivisionError,
 
279
            reflect.namedAny, "twisted.test.reflect_helper_ZDE")
 
280
        self.assertRaises(
 
281
            ValueError,
 
282
            reflect.namedAny, "twisted.test.reflect_helper_VE")
 
283
        # Modules which themselves raise ImportError when imported should
 
284
        # result in an ImportError
 
285
        self.assertRaises(
 
286
            ImportError,
 
287
            reflect.namedAny, "twisted.test.reflect_helper_IE")
 
288
 
 
289
 
 
290
    def test_attributeExceptions(self):
 
291
        """
 
292
        If segments on the end of a fully-qualified Python name represents
 
293
        attributes which aren't actually present on the object represented by
 
294
        the earlier segments, L{namedAny} should raise an L{AttributeError}.
 
295
        """
 
296
        self.assertRaises(
 
297
            AttributeError,
 
298
            reflect.namedAny, "twisted.nosuchmoduleintheworld")
 
299
        # ImportError behaves somewhat differently between "import
 
300
        # extant.nonextant" and "import extant.nonextant.nonextant", so test
 
301
        # the latter as well.
 
302
        self.assertRaises(
 
303
            AttributeError,
 
304
            reflect.namedAny, "twisted.nosuch.modulein.theworld")
 
305
        self.assertRaises(
 
306
            AttributeError,
 
307
            reflect.namedAny,
 
308
            "twisted.test.test_reflect.Summer.nosuchattribute")
 
309
 
 
310
 
 
311
    def test_invalidNames(self):
 
312
        """
 
313
        Passing a name which isn't a fully-qualified Python name to L{namedAny}
 
314
        should result in one of the following exceptions:
 
315
         - L{InvalidName}: the name is not a dot-separated list of Python
 
316
           objects
 
317
         - L{ObjectNotFound}: the object doesn't exist
 
318
         - L{ModuleNotFound}: the object doesn't exist and there is only one
 
319
           component in the name
 
320
        """
 
321
        err = self.assertRaises(reflect.ModuleNotFound, reflect.namedAny,
 
322
                                'nosuchmoduleintheworld')
 
323
        self.assertEqual(str(err), "No module named 'nosuchmoduleintheworld'")
 
324
 
 
325
        # This is a dot-separated list, but it isn't valid!
 
326
        err = self.assertRaises(reflect.ObjectNotFound, reflect.namedAny,
 
327
                                "@#$@(#.!@(#!@#")
 
328
        self.assertEqual(str(err), "'@#$@(#.!@(#!@#' does not name an object")
 
329
 
 
330
        err = self.assertRaises(reflect.ObjectNotFound, reflect.namedAny,
 
331
                                "tcelfer.nohtyp.detsiwt")
 
332
        self.assertEqual(
 
333
            str(err),
 
334
            "'tcelfer.nohtyp.detsiwt' does not name an object")
 
335
 
 
336
        err = self.assertRaises(reflect.InvalidName, reflect.namedAny, '')
 
337
        self.assertEqual(str(err), 'Empty module name')
 
338
 
 
339
        for invalidName in ['.twisted', 'twisted.', 'twisted..python']:
 
340
            err = self.assertRaises(
 
341
                reflect.InvalidName, reflect.namedAny, invalidName)
 
342
            self.assertEqual(
 
343
                str(err),
 
344
                "name must be a string giving a '.'-separated list of Python "
 
345
                "identifiers, not %r" % (invalidName,))
 
346
 
 
347
 
 
348
    def test_requireModuleImportError(self):
 
349
        """
 
350
        When module import fails with ImportError it returns the specified
 
351
        default value.
 
352
        """
 
353
        for name in ['nosuchmtopodule', 'no.such.module']:
 
354
            default = object()
 
355
 
 
356
            result = reflect.requireModule(name, default=default)
 
357
 
 
358
            self.assertIs(result, default)
 
359
 
 
360
 
 
361
    def test_requireModuleDefaultNone(self):
 
362
        """
 
363
        When module import fails it returns C{None} by default.
 
364
        """
 
365
        result = reflect.requireModule('no.such.module')
 
366
 
 
367
        self.assertIs(None, result)
 
368
 
 
369
 
 
370
    def test_requireModuleRequestedImport(self):
 
371
        """
 
372
        When module import succeed it returns the module and not the default
 
373
        value.
 
374
        """
 
375
        from twisted.python import monkey
 
376
        default = object()
 
377
 
 
378
        self.assertIs(
 
379
            reflect.requireModule('twisted.python.monkey', default=default),
 
380
            monkey,
 
381
            )
 
382
 
 
383
 
 
384
 
 
385
class Breakable(object):
 
386
 
 
387
    breakRepr = False
 
388
    breakStr = False
 
389
 
 
390
    def __str__(self):
 
391
        if self.breakStr:
 
392
            raise RuntimeError("str!")
 
393
        else:
 
394
            return '<Breakable>'
 
395
 
 
396
 
 
397
    def __repr__(self):
 
398
        if self.breakRepr:
 
399
            raise RuntimeError("repr!")
 
400
        else:
 
401
            return 'Breakable()'
 
402
 
 
403
 
 
404
 
 
405
class BrokenType(Breakable, type):
 
406
    breakName = False
 
407
 
 
408
    def get___name__(self):
 
409
        if self.breakName:
 
410
            raise RuntimeError("no name")
 
411
        return 'BrokenType'
 
412
    __name__ = property(get___name__)
 
413
 
 
414
 
 
415
 
 
416
BTBase = BrokenType('BTBase', (Breakable,),
 
417
                    {"breakRepr": True,
 
418
                     "breakStr": True})
 
419
 
 
420
 
 
421
 
 
422
class NoClassAttr(Breakable):
 
423
    __class__ = property(lambda x: x.not_class)
 
424
 
 
425
 
 
426
 
 
427
class SafeReprTests(TestCase):
 
428
    """
 
429
    Tests for L{reflect.safe_repr} function.
 
430
    """
 
431
 
 
432
    def test_workingRepr(self):
 
433
        """
 
434
        L{reflect.safe_repr} produces the same output as C{repr} on a working
 
435
        object.
 
436
        """
 
437
        xs = ([1, 2, 3], b'a')
 
438
        self.assertEqual(list(map(reflect.safe_repr, xs)), list(map(repr, xs)))
 
439
 
 
440
 
 
441
    def test_brokenRepr(self):
 
442
        """
 
443
        L{reflect.safe_repr} returns a string with class name, address, and
 
444
        traceback when the repr call failed.
 
445
        """
 
446
        b = Breakable()
 
447
        b.breakRepr = True
 
448
        bRepr = reflect.safe_repr(b)
 
449
        self.assertIn("Breakable instance at 0x", bRepr)
 
450
        # Check that the file is in the repr, but without the extension as it
 
451
        # can be .py/.pyc
 
452
        self.assertIn(os.path.splitext(__file__)[0], bRepr)
 
453
        self.assertIn("RuntimeError: repr!", bRepr)
 
454
 
 
455
 
 
456
    def test_brokenStr(self):
 
457
        """
 
458
        L{reflect.safe_repr} isn't affected by a broken C{__str__} method.
 
459
        """
 
460
        b = Breakable()
 
461
        b.breakStr = True
 
462
        self.assertEqual(reflect.safe_repr(b), repr(b))
 
463
 
 
464
 
 
465
    def test_brokenClassRepr(self):
 
466
        class X(BTBase):
 
467
            breakRepr = True
 
468
        reflect.safe_repr(X)
 
469
        reflect.safe_repr(X())
 
470
 
 
471
 
 
472
    def test_brokenReprIncludesID(self):
 
473
        """
 
474
        C{id} is used to print the ID of the object in case of an error.
 
475
 
 
476
        L{safe_repr} includes a traceback after a newline, so we only check
 
477
        against the first line of the repr.
 
478
        """
 
479
        class X(BTBase):
 
480
            breakRepr = True
 
481
 
 
482
        xRepr = reflect.safe_repr(X)
 
483
        xReprExpected = ('<BrokenType instance at 0x%x with repr error:'
 
484
                         % (id(X),))
 
485
        self.assertEqual(xReprExpected, xRepr.split('\n')[0])
 
486
 
 
487
 
 
488
    def test_brokenClassStr(self):
 
489
        class X(BTBase):
 
490
            breakStr = True
 
491
        reflect.safe_repr(X)
 
492
        reflect.safe_repr(X())
 
493
 
 
494
 
 
495
    def test_brokenClassAttribute(self):
 
496
        """
 
497
        If an object raises an exception when accessing its C{__class__}
 
498
        attribute, L{reflect.safe_repr} uses C{type} to retrieve the class
 
499
        object.
 
500
        """
 
501
        b = NoClassAttr()
 
502
        b.breakRepr = True
 
503
        bRepr = reflect.safe_repr(b)
 
504
        self.assertIn("NoClassAttr instance at 0x", bRepr)
 
505
        self.assertIn(os.path.splitext(__file__)[0], bRepr)
 
506
        self.assertIn("RuntimeError: repr!", bRepr)
 
507
 
 
508
 
 
509
    def test_brokenClassNameAttribute(self):
 
510
        """
 
511
        If a class raises an exception when accessing its C{__name__} attribute
 
512
        B{and} when calling its C{__str__} implementation, L{reflect.safe_repr}
 
513
        returns 'BROKEN CLASS' instead of the class name.
 
514
        """
 
515
        class X(BTBase):
 
516
            breakName = True
 
517
        xRepr = reflect.safe_repr(X())
 
518
        self.assertIn("<BROKEN CLASS AT 0x", xRepr)
 
519
        self.assertIn(os.path.splitext(__file__)[0], xRepr)
 
520
        self.assertIn("RuntimeError: repr!", xRepr)
 
521
 
 
522
 
 
523
 
 
524
class SafeStrTests(TestCase):
 
525
    """
 
526
    Tests for L{reflect.safe_str} function.
 
527
    """
 
528
 
 
529
    def test_workingStr(self):
 
530
        x = [1, 2, 3]
 
531
        self.assertEqual(reflect.safe_str(x), str(x))
 
532
 
 
533
 
 
534
    def test_brokenStr(self):
 
535
        b = Breakable()
 
536
        b.breakStr = True
 
537
        reflect.safe_str(b)
 
538
 
 
539
 
 
540
    def test_workingAscii(self):
 
541
        """
 
542
        L{safe_str} for C{str} with ascii-only data should return the
 
543
        value unchanged.
 
544
        """
 
545
        x = 'a'
 
546
        self.assertEqual(reflect.safe_str(x), 'a')
 
547
 
 
548
 
 
549
    def test_workingUtf8_2(self):
 
550
        """
 
551
        L{safe_str} for C{str} with utf-8 encoded data should return the
 
552
        value unchanged.
 
553
        """
 
554
        x = b't\xc3\xbcst'
 
555
        self.assertEqual(reflect.safe_str(x), x)
 
556
 
 
557
 
 
558
    def test_workingUtf8_3(self):
 
559
        """
 
560
        L{safe_str} for C{bytes} with utf-8 encoded data should return
 
561
        the value decoded into C{str}.
 
562
        """
 
563
        x = b't\xc3\xbcst'
 
564
        self.assertEqual(reflect.safe_str(x), x.decode('utf-8'))
 
565
 
 
566
    if _PY3:
 
567
        # TODO: after something like python.compat.nativeUtf8String is
 
568
        # introduced, use that one for assertEqual. Then we can combine
 
569
        # test_workingUtf8_* tests into one without needing _PY3.
 
570
        # nativeUtf8String is needed for Python 3 anyway.
 
571
        test_workingUtf8_2.skip = ("Skip Python 2 specific test for utf-8 str")
 
572
    else:
 
573
        test_workingUtf8_3.skip = (
 
574
            "Skip Python 3 specific test for utf-8 bytes")
 
575
 
 
576
 
 
577
    def test_brokenUtf8(self):
 
578
        """
 
579
        Use str() for non-utf8 bytes: "b'non-utf8'"
 
580
        """
 
581
        x = b'\xff'
 
582
        xStr = reflect.safe_str(x)
 
583
        self.assertEqual(xStr, str(x))
 
584
 
 
585
 
 
586
    def test_brokenRepr(self):
 
587
        b = Breakable()
 
588
        b.breakRepr = True
 
589
        reflect.safe_str(b)
 
590
 
 
591
 
 
592
    def test_brokenClassStr(self):
 
593
        class X(BTBase):
 
594
            breakStr = True
 
595
        reflect.safe_str(X)
 
596
        reflect.safe_str(X())
 
597
 
 
598
 
 
599
    def test_brokenClassRepr(self):
 
600
        class X(BTBase):
 
601
            breakRepr = True
 
602
        reflect.safe_str(X)
 
603
        reflect.safe_str(X())
 
604
 
 
605
 
 
606
    def test_brokenClassAttribute(self):
 
607
        """
 
608
        If an object raises an exception when accessing its C{__class__}
 
609
        attribute, L{reflect.safe_str} uses C{type} to retrieve the class
 
610
        object.
 
611
        """
 
612
        b = NoClassAttr()
 
613
        b.breakStr = True
 
614
        bStr = reflect.safe_str(b)
 
615
        self.assertIn("NoClassAttr instance at 0x", bStr)
 
616
        self.assertIn(os.path.splitext(__file__)[0], bStr)
 
617
        self.assertIn("RuntimeError: str!", bStr)
 
618
 
 
619
 
 
620
    def test_brokenClassNameAttribute(self):
 
621
        """
 
622
        If a class raises an exception when accessing its C{__name__} attribute
 
623
        B{and} when calling its C{__str__} implementation, L{reflect.safe_str}
 
624
        returns 'BROKEN CLASS' instead of the class name.
 
625
        """
 
626
        class X(BTBase):
 
627
            breakName = True
 
628
        xStr = reflect.safe_str(X())
 
629
        self.assertIn("<BROKEN CLASS AT 0x", xStr)
 
630
        self.assertIn(os.path.splitext(__file__)[0], xStr)
 
631
        self.assertIn("RuntimeError: str!", xStr)
 
632
 
 
633
 
 
634
 
 
635
class FilenameToModuleTests(TestCase):
 
636
    """
 
637
    Test L{filenameToModuleName} detection.
 
638
    """
 
639
 
 
640
    def setUp(self):
 
641
        self.path = os.path.join(self.mktemp(), "fakepackage", "test")
 
642
        os.makedirs(self.path)
 
643
        with open(os.path.join(self.path, "__init__.py"), "w") as f:
 
644
            f.write("")
 
645
        with open(os.path.join(os.path.dirname(self.path), "__init__.py"),
 
646
                  "w") as f:
 
647
            f.write("")
 
648
 
 
649
 
 
650
    def test_directory(self):
 
651
        """
 
652
        L{filenameToModuleName} returns the correct module (a package) given a
 
653
        directory.
 
654
        """
 
655
        module = reflect.filenameToModuleName(self.path)
 
656
        self.assertEqual(module, 'fakepackage.test')
 
657
        module = reflect.filenameToModuleName(self.path + os.path.sep)
 
658
        self.assertEqual(module, 'fakepackage.test')
 
659
 
 
660
 
 
661
    def test_file(self):
 
662
        """
 
663
        L{filenameToModuleName} returns the correct module given the path to
 
664
        its file.
 
665
        """
 
666
        module = reflect.filenameToModuleName(
 
667
            os.path.join(self.path, 'test_reflect.py'))
 
668
        self.assertEqual(module, 'fakepackage.test.test_reflect')
 
669
 
 
670
 
 
671
    def test_bytes(self):
 
672
        """
 
673
        L{filenameToModuleName} returns the correct module given a C{bytes}
 
674
        path to its file.
 
675
        """
 
676
        module = reflect.filenameToModuleName(
 
677
            os.path.join(self.path.encode("utf-8"), b'test_reflect.py'))
 
678
        # Module names are always native string:
 
679
        self.assertEqual(module, 'fakepackage.test.test_reflect')
 
680
 
 
681
 
 
682
 
 
683
class FullyQualifiedNameTests(TestCase):
 
684
    """
 
685
    Test for L{fullyQualifiedName}.
 
686
    """
 
687
 
 
688
    def _checkFullyQualifiedName(self, obj, expected):
 
689
        """
 
690
        Helper to check that fully qualified name of C{obj} results to
 
691
        C{expected}.
 
692
        """
 
693
        self.assertEqual(fullyQualifiedName(obj), expected)
 
694
 
 
695
 
 
696
    def test_package(self):
 
697
        """
 
698
        L{fullyQualifiedName} returns the full name of a package and a
 
699
        subpackage.
 
700
        """
 
701
        import twisted
 
702
        self._checkFullyQualifiedName(twisted, 'twisted')
 
703
        import twisted.python
 
704
        self._checkFullyQualifiedName(twisted.python, 'twisted.python')
 
705
 
 
706
 
 
707
    def test_module(self):
 
708
        """
 
709
        L{fullyQualifiedName} returns the name of a module inside a package.
 
710
        """
 
711
        import twisted.python.compat
 
712
        self._checkFullyQualifiedName(
 
713
            twisted.python.compat, 'twisted.python.compat')
 
714
 
 
715
 
 
716
    def test_class(self):
 
717
        """
 
718
        L{fullyQualifiedName} returns the name of a class and its module.
 
719
        """
 
720
        self._checkFullyQualifiedName(
 
721
            FullyQualifiedNameTests,
 
722
            '%s.FullyQualifiedNameTests' % (__name__,))
 
723
 
 
724
 
 
725
    def test_function(self):
 
726
        """
 
727
        L{fullyQualifiedName} returns the name of a function inside its module.
 
728
        """
 
729
        self._checkFullyQualifiedName(
 
730
            fullyQualifiedName, "twisted.python.reflect.fullyQualifiedName")
 
731
 
 
732
 
 
733
    def test_boundMethod(self):
 
734
        """
 
735
        L{fullyQualifiedName} returns the name of a bound method inside its
 
736
        class and its module.
 
737
        """
 
738
        self._checkFullyQualifiedName(
 
739
            self.test_boundMethod,
 
740
            "%s.%s.test_boundMethod" % (__name__, self.__class__.__name__))
 
741
 
 
742
 
 
743
    def test_unboundMethod(self):
 
744
        """
 
745
        L{fullyQualifiedName} returns the name of an unbound method inside its
 
746
        class and its module.
 
747
        """
 
748
        self._checkFullyQualifiedName(
 
749
            self.__class__.test_unboundMethod,
 
750
            "%s.%s.test_unboundMethod" % (__name__, self.__class__.__name__))
 
751
 
 
752
 
 
753
class ObjectGrepTests(unittest.TestCase):
 
754
    if _PY3:
 
755
        # This is to be removed when fixing #6986
 
756
        skip = "twisted.python.reflect.objgrep hasn't been ported to Python 3"
 
757
 
 
758
 
 
759
    def test_dictionary(self):
 
760
        """
 
761
        Test references search through a dictionnary, as a key or as a value.
 
762
        """
 
763
        o = object()
 
764
        d1 = {None: o}
 
765
        d2 = {o: None}
 
766
 
 
767
        self.assertIn("[None]", reflect.objgrep(d1, o, reflect.isSame))
 
768
        self.assertIn("{None}", reflect.objgrep(d2, o, reflect.isSame))
 
769
 
 
770
    def test_list(self):
 
771
        """
 
772
        Test references search through a list.
 
773
        """
 
774
        o = object()
 
775
        L = [None, o]
 
776
 
 
777
        self.assertIn("[1]", reflect.objgrep(L, o, reflect.isSame))
 
778
 
 
779
    def test_tuple(self):
 
780
        """
 
781
        Test references search through a tuple.
 
782
        """
 
783
        o = object()
 
784
        T = (o, None)
 
785
 
 
786
        self.assertIn("[0]", reflect.objgrep(T, o, reflect.isSame))
 
787
 
 
788
    def test_instance(self):
 
789
        """
 
790
        Test references search through an object attribute.
 
791
        """
 
792
        class Dummy:
 
793
            pass
 
794
        o = object()
 
795
        d = Dummy()
 
796
        d.o = o
 
797
 
 
798
        self.assertIn(".o", reflect.objgrep(d, o, reflect.isSame))
 
799
 
 
800
    def test_weakref(self):
 
801
        """
 
802
        Test references search through a weakref object.
 
803
        """
 
804
        class Dummy:
 
805
            pass
 
806
        o = Dummy()
 
807
        w1 = weakref.ref(o)
 
808
 
 
809
        self.assertIn("()", reflect.objgrep(w1, o, reflect.isSame))
 
810
 
 
811
    def test_boundMethod(self):
 
812
        """
 
813
        Test references search through method special attributes.
 
814
        """
 
815
        class Dummy:
 
816
            def dummy(self):
 
817
                pass
 
818
        o = Dummy()
 
819
        m = o.dummy
 
820
 
 
821
        self.assertIn(".__self__",
 
822
                      reflect.objgrep(m, m.__self__, reflect.isSame))
 
823
        self.assertIn(".__self__.__class__",
 
824
                      reflect.objgrep(m, m.__self__.__class__, reflect.isSame))
 
825
        self.assertIn(".__func__",
 
826
                      reflect.objgrep(m, m.__func__, reflect.isSame))
 
827
 
 
828
    def test_everything(self):
 
829
        """
 
830
        Test references search using complex set of objects.
 
831
        """
 
832
        class Dummy:
 
833
            def method(self):
 
834
                pass
 
835
 
 
836
        o = Dummy()
 
837
        D1 = {(): "baz", None: "Quux", o: "Foosh"}
 
838
        L = [None, (), D1, 3]
 
839
        T = (L, {}, Dummy())
 
840
        D2 = {0: "foo", 1: "bar", 2: T}
 
841
        i = Dummy()
 
842
        i.attr = D2
 
843
        m = i.method
 
844
        w = weakref.ref(m)
 
845
 
 
846
        self.assertIn("().__self__.attr[2][0][2]{'Foosh'}",
 
847
                      reflect.objgrep(w, o, reflect.isSame))
 
848
 
 
849
    def test_depthLimit(self):
 
850
        """
 
851
        Test the depth of references search.
 
852
        """
 
853
        a = []
 
854
        b = [a]
 
855
        c = [a, b]
 
856
        d = [a, c]
 
857
 
 
858
        self.assertEqual(['[0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=1))
 
859
        self.assertEqual(['[0]', '[1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=2))
 
860
        self.assertEqual(['[0]', '[1][0]', '[1][1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=3))
 
861
 
 
862
 
 
863
    def test_deque(self):
 
864
        """
 
865
        Test references search through a deque object.
 
866
        """
 
867
        o = object()
 
868
        D = deque()
 
869
        D.append(None)
 
870
        D.append(o)
 
871
 
 
872
        self.assertIn("[1]", reflect.objgrep(D, o, reflect.isSame))
 
873
 
 
874
 
 
875
class GetClassTests(unittest.TestCase):
 
876
    if _PY3:
 
877
        oldClassNames = ['type']
 
878
    else:
 
879
        oldClassNames = ['class', 'classobj']
 
880
 
 
881
    def test_old(self):
 
882
        class OldClass:
 
883
            pass
 
884
        old = OldClass()
 
885
        self.assertIn(reflect.getClass(OldClass).__name__, self.oldClassNames)
 
886
        self.assertEqual(reflect.getClass(old).__name__, 'OldClass')
 
887
 
 
888
    def test_new(self):
 
889
        class NewClass(object):
 
890
            pass
 
891
        new = NewClass()
 
892
        self.assertEqual(reflect.getClass(NewClass).__name__, 'type')
 
893
        self.assertEqual(reflect.getClass(new).__name__, 'NewClass')
 
894
 
 
895
 
 
896
if not _PY3:
 
897
    # The functions tested below are deprecated but still used by external
 
898
    # projects like Nevow 0.10. They are not going to be ported to Python 3
 
899
    # (hence the condition above) and will be removed as soon as no project used
 
900
    # by Twisted will depend on these functions. Also, have a look at the
 
901
    # comments related to those functions in twisted.python.reflect.
 
902
    class DeprecationTests(unittest.TestCase):
 
903
        """
 
904
        Test deprecations in twisted.python.reflect
 
905
        """
 
906
 
 
907
        def test_allYourBase(self):
 
908
            """
 
909
            Test deprecation of L{reflect.allYourBase}. See #5481 for removal.
 
910
            """
 
911
            self.callDeprecated(
 
912
                (Version("Twisted", 11, 0, 0), "inspect.getmro"),
 
913
                reflect.allYourBase, DeprecationTests)
 
914
 
 
915
 
 
916
        def test_accumulateBases(self):
 
917
            """
 
918
            Test deprecation of L{reflect.accumulateBases}. See #5481 for removal.
 
919
            """
 
920
            l = []
 
921
            self.callDeprecated(
 
922
                (Version("Twisted", 11, 0, 0), "inspect.getmro"),
 
923
                reflect.accumulateBases, DeprecationTests, l, None)
 
924
 
 
925
 
 
926
        def test_getcurrent(self):
 
927
            """
 
928
            Test deprecation of L{reflect.getcurrent}.
 
929
            """
 
930
 
 
931
            class C:
 
932
                pass
 
933
 
 
934
            self.callDeprecated(
 
935
                Version("Twisted", 14, 0, 0),
 
936
                reflect.getcurrent, C)
 
937
 
 
938
 
 
939
        def test_isinst(self):
 
940
            """
 
941
            Test deprecation of L{reflect.isinst}.
 
942
            """
 
943
 
 
944
            self.callDeprecated(
 
945
                (Version("Twisted", 14, 0, 0), "isinstance"),
 
946
                reflect.isinst, object(), object)