Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
grumpy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
grumpy
Commits
95ee26cc
Commit
95ee26cc
authored
Jan 17, 2017
by
YOU
Committed by
Dylan Trotter
Jan 17, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add unittest module (#140)
parent
23140d0c
Changes
14
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
4774 additions
and
2 deletions
+4774
-2
lib/os/path.py
lib/os/path.py
+1
-1
third_party/pypy/functools.py
third_party/pypy/functools.py
+4
-1
third_party/stdlib/test/__init__.py
third_party/stdlib/test/__init__.py
+1
-0
third_party/stdlib/test/seq_tests.py
third_party/stdlib/test/seq_tests.py
+414
-0
third_party/stdlib/test/test_support.py
third_party/stdlib/test/test_support.py
+1684
-0
third_party/stdlib/test/test_tuple.py
third_party/stdlib/test/test_tuple.py
+161
-0
third_party/stdlib/unittest/__init__.py
third_party/stdlib/unittest/__init__.py
+93
-0
third_party/stdlib/unittest_case.py
third_party/stdlib/unittest_case.py
+1091
-0
third_party/stdlib/unittest_loader.py
third_party/stdlib/unittest_loader.py
+323
-0
third_party/stdlib/unittest_result.py
third_party/stdlib/unittest_result.py
+202
-0
third_party/stdlib/unittest_runner.py
third_party/stdlib/unittest_runner.py
+205
-0
third_party/stdlib/unittest_signals.py
third_party/stdlib/unittest_signals.py
+79
-0
third_party/stdlib/unittest_suite.py
third_party/stdlib/unittest_suite.py
+305
-0
third_party/stdlib/unittest_util.py
third_party/stdlib/unittest_util.py
+211
-0
No files found.
lib/os/path.py
View file @
95ee26cc
...
...
@@ -15,7 +15,7 @@
""""Utilities for manipulating and inspecting OS paths."""
from
__go__.os
import
Stat
from
__go__.path.filepath
import
Abs
,
Clean
,
Dir
as
dirname
,
IsAbs
as
isabs
,
Join
# pylint: disable=g-multiple-import,unused-import
from
__go__.path.filepath
import
Abs
,
Base
as
basename
,
Clean
,
Dir
as
dirname
,
IsAbs
as
isabs
,
Join
# pylint: disable=g-multiple-import,unused-import
def
abspath
(
path
):
...
...
third_party/pypy/functools.py
View file @
95ee26cc
...
...
@@ -12,10 +12,13 @@ import _functools
partial
=
_functools
.
partial
reduce
=
_functools
.
reduce
def
setattr
(
d
,
k
,
v
):
d
.
__dict__
[
k
]
=
v
# update_wrapper() and wraps() are tools to help write
# wrapper functions that can handle naive introspection
WRAPPER_ASSIGNMENTS
=
(
'__module__'
,
'__name__'
,
'__doc__'
)
WRAPPER_ASSIGNMENTS
=
(
'__module__'
,
'__name__'
)
#, '__doc__'
WRAPPER_UPDATES
=
(
'__dict__'
,)
def
update_wrapper
(
wrapper
,
wrapped
,
...
...
third_party/stdlib/test/__init__.py
0 → 100644
View file @
95ee26cc
# Dummy file to make this directory a package.
third_party/stdlib/test/seq_tests.py
0 → 100644
View file @
95ee26cc
This diff is collapsed.
Click to expand it.
third_party/stdlib/test/test_support.py
0 → 100644
View file @
95ee26cc
This diff is collapsed.
Click to expand it.
third_party/stdlib/test/test_tuple.py
0 → 100644
View file @
95ee26cc
from
test
import
test_support
,
seq_tests
# import gc
class
TupleTest
(
seq_tests
.
CommonTest
):
type2test
=
tuple
def
test_constructors
(
self
):
super
(
TupleTest
,
self
).
test_constructors
()
# calling built-in types without argument must return empty
self
.
assertEqual
(
tuple
(),
())
t0_3
=
(
0
,
1
,
2
,
3
)
t0_3_bis
=
tuple
(
t0_3
)
self
.
assertTrue
(
t0_3
is
t0_3_bis
)
self
.
assertEqual
(
tuple
([]),
())
self
.
assertEqual
(
tuple
([
0
,
1
,
2
,
3
]),
(
0
,
1
,
2
,
3
))
self
.
assertEqual
(
tuple
(
''
),
())
self
.
assertEqual
(
tuple
(
'spam'
),
(
's'
,
'p'
,
'a'
,
'm'
))
def
test_truth
(
self
):
super
(
TupleTest
,
self
).
test_truth
()
self
.
assertTrue
(
not
())
self
.
assertTrue
((
42
,
))
def
test_len
(
self
):
super
(
TupleTest
,
self
).
test_len
()
self
.
assertEqual
(
len
(()),
0
)
self
.
assertEqual
(
len
((
0
,)),
1
)
self
.
assertEqual
(
len
((
0
,
1
,
2
)),
3
)
def
test_iadd
(
self
):
super
(
TupleTest
,
self
).
test_iadd
()
u
=
(
0
,
1
)
u2
=
u
u
+=
(
2
,
3
)
self
.
assertTrue
(
u
is
not
u2
)
def
test_imul
(
self
):
super
(
TupleTest
,
self
).
test_imul
()
u
=
(
0
,
1
)
u2
=
u
u
*=
3
self
.
assertTrue
(
u
is
not
u2
)
def
test_tupleresizebug
(
self
):
# Check that a specific bug in _PyTuple_Resize() is squashed.
def
f
():
for
i
in
range
(
1000
):
yield
i
self
.
assertEqual
(
list
(
tuple
(
f
())),
range
(
1000
))
def
test_hash
(
self
):
# See SF bug 942952: Weakness in tuple hash
# The hash should:
# be non-commutative
# should spread-out closely spaced values
# should not exhibit cancellation in tuples like (x,(x,y))
# should be distinct from element hashes: hash(x)!=hash((x,))
# This test exercises those cases.
# For a pure random hash and N=50, the expected number of occupied
# buckets when tossing 252,600 balls into 2**32 buckets
# is 252,592.6, or about 7.4 expected collisions. The
# standard deviation is 2.73. On a box with 64-bit hash
# codes, no collisions are expected. Here we accept no
# more than 15 collisions. Any worse and the hash function
# is sorely suspect.
N
=
50
base
=
range
(
N
)
xp
=
[(
i
,
j
)
for
i
in
base
for
j
in
base
]
inps
=
base
+
[(
i
,
j
)
for
i
in
base
for
j
in
xp
]
+
\
[(
i
,
j
)
for
i
in
xp
for
j
in
base
]
+
xp
+
zip
(
base
)
collisions
=
len
(
inps
)
-
len
(
set
(
map
(
hash
,
inps
)))
self
.
assertTrue
(
collisions
<=
15
)
def
test_repr
(
self
):
l0
=
tuple
()
l2
=
(
0
,
1
,
2
)
a0
=
self
.
type2test
(
l0
)
a2
=
self
.
type2test
(
l2
)
self
.
assertEqual
(
str
(
a0
),
repr
(
l0
))
self
.
assertEqual
(
str
(
a2
),
repr
(
l2
))
self
.
assertEqual
(
repr
(
a0
),
"()"
)
self
.
assertEqual
(
repr
(
a2
),
"(0, 1, 2)"
)
# def _not_tracked(self, t):
# # Nested tuples can take several collections to untrack
# gc.collect()
# gc.collect()
# self.assertFalse(gc.is_tracked(t), t)
# def _tracked(self, t):
# self.assertTrue(gc.is_tracked(t), t)
# gc.collect()
# gc.collect()
# self.assertTrue(gc.is_tracked(t), t)
# @test_support.cpython_only
# def test_track_literals(self):
# # Test GC-optimization of tuple literals
# x, y, z = 1.5, "a", []
# self._not_tracked(())
# self._not_tracked((1,))
# self._not_tracked((1, 2))
# self._not_tracked((1, 2, "a"))
# self._not_tracked((1, 2, (None, True, False, ()), int))
# self._not_tracked((object(),))
# self._not_tracked(((1, x), y, (2, 3)))
# # Tuples with mutable elements are always tracked, even if those
# # elements are not tracked right now.
# self._tracked(([],))
# self._tracked(([1],))
# self._tracked(({},))
# self._tracked((set(),))
# self._tracked((x, y, z))
# def check_track_dynamic(self, tp, always_track):
# x, y, z = 1.5, "a", []
# check = self._tracked if always_track else self._not_tracked
# check(tp())
# check(tp([]))
# check(tp(set()))
# check(tp([1, x, y]))
# check(tp(obj for obj in [1, x, y]))
# check(tp(set([1, x, y])))
# check(tp(tuple([obj]) for obj in [1, x, y]))
# check(tuple(tp([obj]) for obj in [1, x, y]))
# self._tracked(tp([z]))
# self._tracked(tp([[x, y]]))
# self._tracked(tp([{x: y}]))
# self._tracked(tp(obj for obj in [x, y, z]))
# self._tracked(tp(tuple([obj]) for obj in [x, y, z]))
# self._tracked(tuple(tp([obj]) for obj in [x, y, z]))
# @test_support.cpython_only
# def test_track_dynamic(self):
# # Test GC-optimization of dynamically constructed tuples.
# self.check_track_dynamic(tuple, False)
# @test_support.cpython_only
# def test_track_subtypes(self):
# # Tuple subtypes must always be tracked
# class MyTuple(tuple):
# pass
# self.check_track_dynamic(MyTuple, True)
# @test_support.cpython_only
# def test_bug7466(self):
# # Trying to untrack an unfinished tuple could crash Python
# self._not_tracked(tuple(gc.collect() for i in range(101)))
def
test_main
():
test_support
.
run_unittest
(
TupleTest
)
if
__name__
==
"__main__"
:
test_main
()
third_party/stdlib/unittest/__init__.py
0 → 100644
View file @
95ee26cc
"""
Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's
Smalltalk testing framework.
This module contains the core framework classes that form the basis of
specific test cases and suites (TestCase, TestSuite etc.), and also a
text-based utility class for running the tests and reporting the results
(TextTestRunner).
Simple usage:
import unittest
class IntegerArithmeticTestCase(unittest.TestCase):
def testAdd(self): ## test method names begin 'test*'
self.assertEqual((1 + 2), 3)
self.assertEqual(0 + 1, 1)
def testMultiply(self):
self.assertEqual((0 * 10), 0)
self.assertEqual((5 * 8), 40)
if __name__ == '__main__':
unittest.main()
Further information is available in the bundled documentation, and from
http://docs.python.org/library/unittest.html
Copyright (c) 1999-2003 Steve Purcell
Copyright (c) 2003-2010 Python Software Foundation
This module is free software, and you may redistribute it and/or modify
it under the same terms as Python itself, so long as this copyright message
and disclaimer are retained in their original form.
IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
"""
__all__
=
[
'TestResult'
,
'TestCase'
,
'TestSuite'
,
'TextTestRunner'
,
'TestLoader'
,
'FunctionTestCase'
,
'main'
,
'defaultTestLoader'
,
'SkipTest'
,
'skip'
,
'skipIf'
,
'skipUnless'
,
'expectedFailure'
,
'TextTestResult'
,
'installHandler'
,
'registerResult'
,
'removeResult'
,
'removeHandler'
]
# Expose obsolete functions for backwards compatibility
# __all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases'])
__all__
+=
([
'getTestCaseNames'
,
'makeSuite'
,
'findTestCases'
])
__unittest
=
True
import
unittest_result
import
unittest_case
import
unittest_suite
import
unittest_loader
# import unittest_main
import
unittest_runner
import
unittest_signals
# from .result import TestResult
# from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf,
# skipUnless, expectedFailure)
# from .suite import BaseTestSuite, TestSuite
# from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames,
# findTestCases)
# from .main import TestProgram, main
# from .runner import TextTestRunner, TextTestResult
# from .signals import installHandler, registerResult, removeResult, removeHandler
TestResult
=
unittest_result
.
TestResult
TestCase
,
FunctionTestCase
,
SkipTest
,
skip
,
skipIf
,
skipUnless
,
expectedFailure
=
\
unittest_case
.
TestCase
,
unittest_case
.
FunctionTestCase
,
unittest_case
.
SkipTest
,
\
unittest_case
.
skip
,
unittest_case
.
skipIf
,
unittest_case
.
skipUnless
,
\
unittest_case
.
expectedFailure
BaseTestSuite
,
TestSuite
=
unittest_suite
.
BaseTestSuite
,
unittest_suite
.
TestSuite
TestLoader
,
defaultTestLoader
,
makeSuite
,
getTestCaseNames
,
findTestCases
=
\
unittest_loader
.
TestLoader
,
unittest_loader
.
defaultTestLoader
,
unittest_loader
.
makeSuite
,
\
unittest_loader
.
getTestCaseNames
,
unittest_loader
.
findTestCases
# TestProgram, main = unittest_main.TestProgram, unittest_main.main
TextTestRunner
,
TextTestResult
=
unittest_runner
.
TextTestRunner
,
unittest_runner
.
TextTestResult
installHandler
,
registerResult
,
removeResult
,
removeHandler
=
\
unittest_signals
.
installHandler
,
unittest_signals
.
registerResult
,
\
unittest_signals
.
removeResult
,
unittest_signals
.
removeHandler
# deprecated
_TextTestResult
=
TextTestResult
third_party/stdlib/unittest_case.py
0 → 100644
View file @
95ee26cc
This diff is collapsed.
Click to expand it.
third_party/stdlib/unittest_loader.py
0 → 100644
View file @
95ee26cc
This diff is collapsed.
Click to expand it.
third_party/stdlib/unittest_result.py
0 → 100644
View file @
95ee26cc
"""Test result object"""
import
os
import
sys
import
traceback
# from StringIO import StringIO
import
StringIO
as
_StringIO
StringIO
=
_StringIO
.
StringIO
# from . import util
# from functools import wraps
import
unittest_util
as
util
import
functools
wraps
=
functools
.
wraps
__unittest
=
True
def
failfast
(
method
):
# @wraps(method)
def
inner
(
self
,
*
args
,
**
kw
):
if
getattr
(
self
,
'failfast'
,
False
):
self
.
stop
()
return
method
(
self
,
*
args
,
**
kw
)
inner
=
wraps
(
method
)(
inner
)
return
inner
STDOUT_LINE
=
'
\
n
Stdout:
\
n
%s'
STDERR_LINE
=
'
\
n
Stderr:
\
n
%s'
class
TestResult
(
object
):
"""Holder for test result information.
Test results are automatically managed by the TestCase and TestSuite
classes, and do not need to be explicitly manipulated by writers of tests.
Each instance holds the total number of tests run, and collections of
failures and errors that occurred among those test runs. The collections
contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
formatted traceback of the error that occurred.
"""
_previousTestClass
=
None
_testRunEntered
=
False
_moduleSetUpFailed
=
False
def
__init__
(
self
,
stream
=
None
,
descriptions
=
None
,
verbosity
=
None
):
self
.
failfast
=
False
self
.
failures
=
[]
self
.
errors
=
[]
self
.
testsRun
=
0
self
.
skipped
=
[]
self
.
expectedFailures
=
[]
self
.
unexpectedSuccesses
=
[]
self
.
shouldStop
=
False
self
.
buffer
=
False
self
.
_stdout_buffer
=
None
self
.
_stderr_buffer
=
None
self
.
_original_stdout
=
sys
.
stdout
self
.
_original_stderr
=
sys
.
stderr
self
.
_mirrorOutput
=
False
def
printErrors
(
self
):
"Called by TestRunner after test run"
def
startTest
(
self
,
test
):
"Called when the given test is about to be run"
self
.
testsRun
+=
1
self
.
_mirrorOutput
=
False
self
.
_setupStdout
()
def
_setupStdout
(
self
):
if
self
.
buffer
:
if
self
.
_stderr_buffer
is
None
:
self
.
_stderr_buffer
=
StringIO
()
self
.
_stdout_buffer
=
StringIO
()
sys
.
stdout
=
self
.
_stdout_buffer
sys
.
stderr
=
self
.
_stderr_buffer
def
startTestRun
(
self
):
"""Called once before any tests are executed.
See startTest for a method called before each test.
"""
def
stopTest
(
self
,
test
):
"""Called when the given test has been run"""
self
.
_restoreStdout
()
self
.
_mirrorOutput
=
False
def
_restoreStdout
(
self
):
if
self
.
buffer
:
if
self
.
_mirrorOutput
:
output
=
sys
.
stdout
.
getvalue
()
error
=
sys
.
stderr
.
getvalue
()
if
output
:
if
not
output
.
endswith
(
'
\
n
'
):
output
+=
'
\
n
'
self
.
_original_stdout
.
write
(
STDOUT_LINE
%
output
)
if
error
:
if
not
error
.
endswith
(
'
\
n
'
):
error
+=
'
\
n
'
self
.
_original_stderr
.
write
(
STDERR_LINE
%
error
)
sys
.
stdout
=
self
.
_original_stdout
sys
.
stderr
=
self
.
_original_stderr
self
.
_stdout_buffer
.
seek
(
0
)
self
.
_stdout_buffer
.
truncate
()
self
.
_stderr_buffer
.
seek
(
0
)
self
.
_stderr_buffer
.
truncate
()
def
stopTestRun
(
self
):
"""Called once after all tests are executed.
See stopTest for a method called after each test.
"""
# @failfast
def
addError
(
self
,
test
,
err
):
"""Called when an error has occurred. 'err' is a tuple of values as
returned by sys.exc_info().
"""
self
.
errors
.
append
((
test
,
self
.
_exc_info_to_string
(
err
,
test
)))
self
.
_mirrorOutput
=
True
addError
=
failfast
(
addError
)
# @failfast
def
addFailure
(
self
,
test
,
err
):
"""Called when an error has occurred. 'err' is a tuple of values as
returned by sys.exc_info()."""
self
.
failures
.
append
((
test
,
self
.
_exc_info_to_string
(
err
,
test
)))
self
.
_mirrorOutput
=
True
addFailure
=
failfast
(
addFailure
)
def
addSuccess
(
self
,
test
):
"Called when a test has completed successfully"
pass
def
addSkip
(
self
,
test
,
reason
):
"""Called when a test is skipped."""
self
.
skipped
.
append
((
test
,
reason
))
def
addExpectedFailure
(
self
,
test
,
err
):
"""Called when an expected failure/error occurred."""
self
.
expectedFailures
.
append
(
(
test
,
self
.
_exc_info_to_string
(
err
,
test
)))
# @failfast
def
addUnexpectedSuccess
(
self
,
test
):
"""Called when a test was expected to fail, but succeed."""
self
.
unexpectedSuccesses
.
append
(
test
)
addUnexpectedSuccess
=
failfast
(
addUnexpectedSuccess
)
def
wasSuccessful
(
self
):
"Tells whether or not this result was a success"
return
len
(
self
.
failures
)
==
len
(
self
.
errors
)
==
0
def
stop
(
self
):
"Indicates that the tests should be aborted"
self
.
shouldStop
=
True
def
_exc_info_to_string
(
self
,
err
,
test
):
"""Converts a sys.exc_info()-style tuple of values into a string."""
exctype
,
value
,
tb
=
err
# Skip test runner traceback levels
while
tb
and
self
.
_is_relevant_tb_level
(
tb
):
tb
=
tb
.
tb_next
if
exctype
is
test
.
failureException
:
# Skip assert*() traceback levels
length
=
self
.
_count_relevant_tb_levels
(
tb
)
msgLines
=
traceback
.
format_exception
(
exctype
,
value
,
tb
,
length
)
else
:
msgLines
=
traceback
.
format_exception
(
exctype
,
value
,
tb
)
if
self
.
buffer
:
output
=
sys
.
stdout
.
getvalue
()
error
=
sys
.
stderr
.
getvalue
()
if
output
:
if
not
output
.
endswith
(
'
\
n
'
):
output
+=
'
\
n
'
msgLines
.
append
(
STDOUT_LINE
%
output
)
if
error
:
if
not
error
.
endswith
(
'
\
n
'
):
error
+=
'
\
n
'
msgLines
.
append
(
STDERR_LINE
%
error
)
return
''
.
join
(
msgLines
)
def
_is_relevant_tb_level
(
self
,
tb
):
return
'__unittest'
in
tb
.
tb_frame
.
f_globals
def
_count_relevant_tb_levels
(
self
,
tb
):
length
=
0
while
tb
and
not
self
.
_is_relevant_tb_level
(
tb
):
length
+=
1
tb
=
tb
.
tb_next
return
length
def
__repr__
(
self
):
return
(
"<%s run=%i errors=%i failures=%i>"
%
(
util
.
strclass
(
self
.
__class__
),
self
.
testsRun
,
len
(
self
.
errors
),
len
(
self
.
failures
)))
third_party/stdlib/unittest_runner.py
0 → 100644
View file @
95ee26cc
"""Running tests"""
import
sys
import
time
# from . import result
# from .signals import registerResult
import
unittest_result
as
result
import
unittest_signals
registerResult
=
unittest_signals
.
registerResult
__unittest
=
True
class
_WritelnDecorator
(
object
):
"""Used to decorate file-like objects with a handy 'writeln' method"""
def
__init__
(
self
,
stream
):
self
.
stream
=
stream
def
__getattr__
(
self
,
attr
):
if
attr
in
(
'stream'
,
'__getstate__'
):
raise
AttributeError
(
attr
)
return
getattr
(
self
.
stream
,
attr
)
def
writeln
(
self
,
arg
=
None
):
if
arg
:
self
.
write
(
arg
)
self
.
write
(
'
\
n
'
)
# text-mode streams translate to \r\n if needed
def
write
(
self
,
arg
):
self
.
stream
.
write
(
arg
)
def
flush
(
self
):
pass
class
TextTestResult
(
result
.
TestResult
):
"""A test result class that can print formatted text results to a stream.
Used by TextTestRunner.
"""
separator1
=
'='
*
70
separator2
=
'-'
*
70
def
__init__
(
self
,
stream
,
descriptions
,
verbosity
):
super
(
TextTestResult
,
self
).
__init__
(
stream
,
descriptions
,
verbosity
)
self
.
stream
=
stream
self
.
showAll
=
verbosity
>
1
self
.
dots
=
verbosity
==
1
self
.
descriptions
=
descriptions
def
getDescription
(
self
,
test
):
doc_first_line
=
test
.
shortDescription
()
if
self
.
descriptions
and
doc_first_line
:
return
'
\
n
'
.
join
((
str
(
test
),
doc_first_line
))
else
:
return
str
(
test
)
def
startTest
(
self
,
test
):
super
(
TextTestResult
,
self
).
startTest
(
test
)
if
self
.
showAll
:
self
.
stream
.
write
(
self
.
getDescription
(
test
))
self
.
stream
.
write
(
" ... "
)
self
.
stream
.
flush
()
def
addSuccess
(
self
,
test
):
super
(
TextTestResult
,
self
).
addSuccess
(
test
)
if
self
.
showAll
:
self
.
stream
.
writeln
(
"ok"
)
elif
self
.
dots
:
self
.
stream
.
write
(
'.'
)
self
.
stream
.
flush
()
def
addError
(
self
,
test
,
err
):
super
(
TextTestResult
,
self
).
addError
(
test
,
err
)
if
self
.
showAll
:
self
.
stream
.
writeln
(
"ERROR"
)
elif
self
.
dots
:
self
.
stream
.
write
(
'E'
)
self
.
stream
.
flush
()
def
addFailure
(
self
,
test
,
err
):
super
(
TextTestResult
,
self
).
addFailure
(
test
,
err
)
if
self
.
showAll
:
self
.
stream
.
writeln
(
"FAIL"
)
elif
self
.
dots
:
self
.
stream
.
write
(
'F'
)
self
.
stream
.
flush
()
def
addSkip
(
self
,
test
,
reason
):
super
(
TextTestResult
,
self
).
addSkip
(
test
,
reason
)
if
self
.
showAll
:
self
.
stream
.
writeln
(
"skipped {0!r}"
.
format
(
reason
))
elif
self
.
dots
:
self
.
stream
.
write
(
"s"
)
self
.
stream
.
flush
()
def
addExpectedFailure
(
self
,
test
,
err
):
super
(
TextTestResult
,
self
).
addExpectedFailure
(
test
,
err
)
if
self
.
showAll
:
self
.
stream
.
writeln
(
"expected failure"
)
elif
self
.
dots
:
self
.
stream
.
write
(
"x"
)
self
.
stream
.
flush
()
def
addUnexpectedSuccess
(
self
,
test
):
super
(
TextTestResult
,
self
).
addUnexpectedSuccess
(
test
)
if
self
.
showAll
:
self
.
stream
.
writeln
(
"unexpected success"
)
elif
self
.
dots
:
self
.
stream
.
write
(
"u"
)
self
.
stream
.
flush
()
def
printErrors
(
self
):
if
self
.
dots
or
self
.
showAll
:
self
.
stream
.
writeln
()
self
.
printErrorList
(
'ERROR'
,
self
.
errors
)
self
.
printErrorList
(
'FAIL'
,
self
.
failures
)
def
printErrorList
(
self
,
flavour
,
errors
):
for
test
,
err
in
errors
:
self
.
stream
.
writeln
(
self
.
separator1
)
self
.
stream
.
writeln
(
"%s: %s"
%
(
flavour
,
self
.
getDescription
(
test
)))
self
.
stream
.
writeln
(
self
.
separator2
)
self
.
stream
.
writeln
(
"%s"
%
err
)
class
TextTestRunner
(
object
):
"""A test runner class that displays results in textual form.
It prints out the names of tests as they are run, errors as they
occur, and a summary of the results at the end of the test run.
"""
resultclass
=
TextTestResult
def
__init__
(
self
,
stream
=
sys
.
stderr
,
descriptions
=
True
,
verbosity
=
1
,
failfast
=
False
,
buffer
=
False
,
resultclass
=
None
):
self
.
stream
=
_WritelnDecorator
(
stream
)
self
.
descriptions
=
descriptions
self
.
verbosity
=
verbosity
self
.
failfast
=
failfast
self
.
buffer
=
buffer
if
resultclass
is
not
None
:
self
.
resultclass
=
resultclass
def
_makeResult
(
self
):
return
self
.
resultclass
(
self
.
stream
,
self
.
descriptions
,
self
.
verbosity
)
def
run
(
self
,
test
):
"Run the given test case or test suite."
result
=
self
.
_makeResult
()
registerResult
(
result
)
result
.
failfast
=
self
.
failfast
result
.
buffer
=
self
.
buffer
startTime
=
time
.
time
()
startTestRun
=
getattr
(
result
,
'startTestRun'
,
None
)
if
startTestRun
is
not
None
:
startTestRun
()
try
:
test
(
result
)
finally
:
stopTestRun
=
getattr
(
result
,
'stopTestRun'
,
None
)
if
stopTestRun
is
not
None
:
stopTestRun
()
stopTime
=
time
.
time
()
timeTaken
=
stopTime
-
startTime
result
.
printErrors
()
if
hasattr
(
result
,
'separator2'
):
self
.
stream
.
writeln
(
result
.
separator2
)
run
=
result
.
testsRun
# self.stream.writeln("Ran %d test%s in %.3fs" %
self
.
stream
.
writeln
(
"Ran %d test%s in %fs"
%
(
run
,
run
!=
1
and
"s"
or
""
,
timeTaken
))
self
.
stream
.
writeln
()
expectedFails
=
unexpectedSuccesses
=
skipped
=
0
try
:
results
=
map
(
len
,
(
result
.
expectedFailures
,
result
.
unexpectedSuccesses
,
result
.
skipped
))
except
AttributeError
:
pass
else
:
expectedFails
,
unexpectedSuccesses
,
skipped
=
results
infos
=
[]
if
not
result
.
wasSuccessful
():
self
.
stream
.
write
(
"FAILED"
)
failed
,
errored
=
map
(
len
,
(
result
.
failures
,
result
.
errors
))
if
failed
:
infos
.
append
(
"failures=%d"
%
failed
)
if
errored
:
infos
.
append
(
"errors=%d"
%
errored
)
else
:
self
.
stream
.
write
(
"OK"
)
if
skipped
:
infos
.
append
(
"skipped=%d"
%
skipped
)
if
expectedFails
:
infos
.
append
(
"expected failures=%d"
%
expectedFails
)
if
unexpectedSuccesses
:
infos
.
append
(
"unexpected successes=%d"
%
unexpectedSuccesses
)
if
infos
:
self
.
stream
.
writeln
(
" (%s)"
%
(
", "
.
join
(
infos
),))
else
:
self
.
stream
.
write
(
"
\
n
"
)
return
result
third_party/stdlib/unittest_signals.py
0 → 100644
View file @
95ee26cc
# TODO: support signal
# import signal
import
weakref
# from functools import wraps
import
functools
wraps
=
functools
.
wraps
__unittest
=
True
class
_InterruptHandler
(
object
):
pass
# def __init__(self, default_handler):
# self.called = False
# self.original_handler = default_handler
# if isinstance(default_handler, int):
# print 'signal not supported yet'
# if default_handler == signal.SIG_DFL:
# # Pretend it's signal.default_int_handler instead.
# default_handler = signal.default_int_handler
# elif default_handler == signal.SIG_IGN:
# # Not quite the same thing as SIG_IGN, but the closest we
# # can make it: do nothing.
# def default_handler(unused_signum, unused_frame):
# pass
# else:
# raise TypeError("expected SIGINT signal handler to be "
# "signal.SIG_IGN, signal.SIG_DFL, or a "
# "callable object")
# self.default_handler = default_handler
# def __call__(self, signum, frame):
# installed_handler = signal.getsignal(signal.SIGINT)
# if installed_handler is not self:
# # if we aren't the installed handler, then delegate immediately
# # to the default handler
# self.default_handler(signum, frame)
# if self.called:
# self.default_handler(signum, frame)
# self.called = True
# for result in _results.keys():
# result.stop()
_results
=
weakref
.
WeakKeyDictionary
()
def
registerResult
(
result
):
_results
[
result
]
=
1
def
removeResult
(
result
):
return
bool
(
_results
.
pop
(
result
,
None
))
_interrupt_handler
=
None
def
installHandler
():
global
_interrupt_handler
pass
# if _interrupt_handler is None:
# default_handler = signal.getsignal(signal.SIGINT)
# _interrupt_handler = _InterruptHandler(default_handler)
# signal.signal(signal.SIGINT, _interrupt_handler)
def
removeHandler
(
method
=
None
):
pass
# if method is not None:
# # @wraps(method)
# def inner(*args, **kwargs):
# initial = signal.getsignal(signal.SIGINT)
# removeHandler()
# try:
# return method(*args, **kwargs)
# finally:
# signal.signal(signal.SIGINT, initial)
# inner = wraps(method)(inner)
# return inner
# global _interrupt_handler
# if _interrupt_handler is not None:
# signal.signal(signal.SIGINT, _interrupt_handler.original_handler)
third_party/stdlib/unittest_suite.py
0 → 100644
View file @
95ee26cc
"""TestSuite"""
import
sys
# from . import case
# from . import util
import
unittest_case
as
case
import
unittest_util
as
util
__unittest
=
True
def
_call_if_exists
(
parent
,
attr
):
func
=
getattr
(
parent
,
attr
,
lambda
:
None
)
func
()
class
BaseTestSuite
(
object
):
"""A simple test suite that doesn't provide class or module shared fixtures.
"""
def
__init__
(
self
,
tests
=
()):
self
.
_tests
=
[]
self
.
addTests
(
tests
)
def
__repr__
(
self
):
return
"<%s tests=%s>"
%
(
util
.
strclass
(
self
.
__class__
),
list
(
self
))
def
__eq__
(
self
,
other
):
if
not
isinstance
(
other
,
self
.
__class__
):
return
NotImplemented
return
list
(
self
)
==
list
(
other
)
def
__ne__
(
self
,
other
):
return
not
self
==
other
# Can't guarantee hash invariant, so flag as unhashable
__hash__
=
None
def
__iter__
(
self
):
return
iter
(
self
.
_tests
)
def
countTestCases
(
self
):
cases
=
0
for
test
in
self
:
cases
+=
test
.
countTestCases
()
return
cases
def
addTest
(
self
,
test
):
# sanity checks
if
not
hasattr
(
test
,
'__call__'
):
raise
TypeError
(
"{} is not callable"
.
format
(
repr
(
test
)))
if
isinstance
(
test
,
type
)
and
issubclass
(
test
,
(
case
.
TestCase
,
TestSuite
)):
raise
TypeError
(
"TestCases and TestSuites must be instantiated "
"before passing them to addTest()"
)
self
.
_tests
.
append
(
test
)
def
addTests
(
self
,
tests
):
if
isinstance
(
tests
,
basestring
):
raise
TypeError
(
"tests must be an iterable of tests, not a string"
)
for
test
in
tests
:
self
.
addTest
(
test
)
def
run
(
self
,
result
):
for
test
in
self
:
if
result
.
shouldStop
:
break
test
(
result
)
return
result
def
__call__
(
self
,
*
args
,
**
kwds
):
return
self
.
run
(
*
args
,
**
kwds
)
def
debug
(
self
):
"""Run the tests without collecting errors in a TestResult"""
for
test
in
self
:
test
.
debug
()
class
TestSuite
(
BaseTestSuite
):
"""A test suite is a composite test consisting of a number of TestCases.
For use, create an instance of TestSuite, then add test case instances.
When all tests have been added, the suite can be passed to a test
runner, such as TextTestRunner. It will run the individual test cases
in the order in which they were added, aggregating the results. When
subclassing, do not forget to call the base class constructor.
"""
def
run
(
self
,
result
,
debug
=
False
):
topLevel
=
False
if
getattr
(
result
,
'_testRunEntered'
,
False
)
is
False
:
result
.
_testRunEntered
=
topLevel
=
True
for
test
in
self
:
if
result
.
shouldStop
:
break
if
_isnotsuite
(
test
):
self
.
_tearDownPreviousClass
(
test
,
result
)
self
.
_handleModuleFixture
(
test
,
result
)
self
.
_handleClassSetUp
(
test
,
result
)
result
.
_previousTestClass
=
test
.
__class__
if
(
getattr
(
test
.
__class__
,
'_classSetupFailed'
,
False
)
or
getattr
(
result
,
'_moduleSetUpFailed'
,
False
)):
continue
if
not
debug
:
test
(
result
)
else
:
test
.
debug
()
if
topLevel
:
self
.
_tearDownPreviousClass
(
None
,
result
)
self
.
_handleModuleTearDown
(
result
)
result
.
_testRunEntered
=
False
return
result
def
debug
(
self
):
"""Run the tests without collecting errors in a TestResult"""
debug
=
_DebugResult
()
self
.
run
(
debug
,
True
)
################################
def
_handleClassSetUp
(
self
,
test
,
result
):
previousClass
=
getattr
(
result
,
'_previousTestClass'
,
None
)
currentClass
=
test
.
__class__
if
currentClass
==
previousClass
:
return
if
result
.
_moduleSetUpFailed
:
return
if
getattr
(
currentClass
,
"__unittest_skip__"
,
False
):
return
try
:
currentClass
.
_classSetupFailed
=
False
except
TypeError
:
# test may actually be a function
# so its class will be a builtin-type
pass
setUpClass
=
getattr
(
currentClass
,
'setUpClass'
,
None
)
if
setUpClass
is
not
None
:
_call_if_exists
(
result
,
'_setupStdout'
)
try
:
setUpClass
()
except
Exception
as
e
:
if
isinstance
(
result
,
_DebugResult
):
raise
currentClass
.
_classSetupFailed
=
True
className
=
util
.
strclass
(
currentClass
)
errorName
=
'setUpClass (%s)'
%
className
self
.
_addClassOrModuleLevelException
(
result
,
e
,
errorName
)
finally
:
_call_if_exists
(
result
,
'_restoreStdout'
)
def
_get_previous_module
(
self
,
result
):
previousModule
=
None
previousClass
=
getattr
(
result
,
'_previousTestClass'
,
None
)
if
previousClass
is
not
None
:
previousModule
=
previousClass
.
__module__
return
previousModule
def
_handleModuleFixture
(
self
,
test
,
result
):
previousModule
=
self
.
_get_previous_module
(
result
)
currentModule
=
test
.
__class__
.
__module__
if
currentModule
==
previousModule
:
return
self
.
_handleModuleTearDown
(
result
)
result
.
_moduleSetUpFailed
=
False
try
:
module
=
sys
.
modules
[
currentModule
]
except
KeyError
:
return
setUpModule
=
getattr
(
module
,
'setUpModule'
,
None
)
if
setUpModule
is
not
None
:
_call_if_exists
(
result
,
'_setupStdout'
)
try
:
setUpModule
()
except
Exception
,
e
:
if
isinstance
(
result
,
_DebugResult
):
raise
result
.
_moduleSetUpFailed
=
True
errorName
=
'setUpModule (%s)'
%
currentModule
self
.
_addClassOrModuleLevelException
(
result
,
e
,
errorName
)
finally
:
_call_if_exists
(
result
,
'_restoreStdout'
)
def
_addClassOrModuleLevelException
(
self
,
result
,
exception
,
errorName
):
error
=
_ErrorHolder
(
errorName
)
addSkip
=
getattr
(
result
,
'addSkip'
,
None
)
if
addSkip
is
not
None
and
isinstance
(
exception
,
case
.
SkipTest
):
addSkip
(
error
,
str
(
exception
))
else
:
result
.
addError
(
error
,
sys
.
exc_info
())
def
_handleModuleTearDown
(
self
,
result
):
previousModule
=
self
.
_get_previous_module
(
result
)
if
previousModule
is
None
:
return
if
result
.
_moduleSetUpFailed
:
return
try
:
module
=
sys
.
modules
[
previousModule
]
except
KeyError
:
return
tearDownModule
=
getattr
(
module
,
'tearDownModule'
,
None
)
if
tearDownModule
is
not
None
:
_call_if_exists
(
result
,
'_setupStdout'
)
try
:
tearDownModule
()
except
Exception
as
e
:
if
isinstance
(
result
,
_DebugResult
):
raise
errorName
=
'tearDownModule (%s)'
%
previousModule
self
.
_addClassOrModuleLevelException
(
result
,
e
,
errorName
)
finally
:
_call_if_exists
(
result
,
'_restoreStdout'
)
def
_tearDownPreviousClass
(
self
,
test
,
result
):
previousClass
=
getattr
(
result
,
'_previousTestClass'
,
None
)
currentClass
=
test
.
__class__
if
currentClass
==
previousClass
:
return
if
getattr
(
previousClass
,
'_classSetupFailed'
,
False
):
return
if
getattr
(
result
,
'_moduleSetUpFailed'
,
False
):
return
if
getattr
(
previousClass
,
"__unittest_skip__"
,
False
):
return
tearDownClass
=
getattr
(
previousClass
,
'tearDownClass'
,
None
)
if
tearDownClass
is
not
None
:
_call_if_exists
(
result
,
'_setupStdout'
)
try
:
tearDownClass
()
except
Exception
,
e
:
if
isinstance
(
result
,
_DebugResult
):
raise
className
=
util
.
strclass
(
previousClass
)
errorName
=
'tearDownClass (%s)'
%
className
self
.
_addClassOrModuleLevelException
(
result
,
e
,
errorName
)
finally
:
_call_if_exists
(
result
,
'_restoreStdout'
)
class
_ErrorHolder
(
object
):
"""
Placeholder for a TestCase inside a result. As far as a TestResult
is concerned, this looks exactly like a unit test. Used to insert
arbitrary errors into a test suite run.
"""
# Inspired by the ErrorHolder from Twisted:
# http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py
# attribute used by TestResult._exc_info_to_string
failureException
=
None
def
__init__
(
self
,
description
):
self
.
description
=
description
def
id
(
self
):
return
self
.
description
def
shortDescription
(
self
):
return
None
def
__repr__
(
self
):
return
"<ErrorHolder description=%r>"
%
(
self
.
description
,)
def
__str__
(
self
):
return
self
.
id
()
def
run
(
self
,
result
):
# could call result.addError(...) - but this test-like object
# shouldn't be run anyway
pass
def
__call__
(
self
,
result
):
return
self
.
run
(
result
)
def
countTestCases
(
self
):
return
0
def
_isnotsuite
(
test
):
"A crude way to tell apart testcases and suites with duck-typing"
try
:
iter
(
test
)
except
TypeError
:
return
True
return
False
class
_DebugResult
(
object
):
"Used by the TestSuite to hold previous class when running in debug."
_previousTestClass
=
None
_moduleSetUpFailed
=
False
shouldStop
=
False
third_party/stdlib/unittest_util.py
0 → 100644
View file @
95ee26cc
"""Various utility functions."""
# from collections import namedtuple, OrderedDict
import
operator
_itemgetter
=
operator
.
itemgetter
_property
=
property
_tuple
=
tuple
__unittest
=
True
_MAX_LENGTH
=
80
def
safe_repr
(
obj
,
short
=
False
):
try
:
result
=
repr
(
obj
)
except
Exception
:
result
=
object
.
__repr__
(
obj
)
if
not
short
or
len
(
result
)
<
_MAX_LENGTH
:
return
result
return
result
[:
_MAX_LENGTH
]
+
' [truncated]...'
def
strclass
(
cls
):
return
"%s.%s"
%
(
cls
.
__module__
,
cls
.
__name__
)
def
sorted_list_difference
(
expected
,
actual
):
"""Finds elements in only one or the other of two, sorted input lists.
Returns a two-element tuple of lists. The first list contains those
elements in the "expected" list but not in the "actual" list, and the
second contains those elements in the "actual" list but not in the
"expected" list. Duplicate elements in either input list are ignored.
"""
i
=
j
=
0
missing
=
[]
unexpected
=
[]
while
True
:
try
:
e
=
expected
[
i
]
a
=
actual
[
j
]
if
e
<
a
:
missing
.
append
(
e
)
i
+=
1
while
expected
[
i
]
==
e
:
i
+=
1
elif
e
>
a
:
unexpected
.
append
(
a
)
j
+=
1
while
actual
[
j
]
==
a
:
j
+=
1
else
:
i
+=
1
try
:
while
expected
[
i
]
==
e
:
i
+=
1
finally
:
j
+=
1
while
actual
[
j
]
==
a
:
j
+=
1
except
IndexError
:
missing
.
extend
(
expected
[
i
:])
unexpected
.
extend
(
actual
[
j
:])
break
return
missing
,
unexpected
def
unorderable_list_difference
(
expected
,
actual
,
ignore_duplicate
=
False
):
"""Same behavior as sorted_list_difference but
for lists of unorderable items (like dicts).
As it does a linear search per item (remove) it
has O(n*n) performance.
"""
missing
=
[]
unexpected
=
[]
while
expected
:
item
=
expected
.
pop
()
try
:
actual
.
remove
(
item
)
except
ValueError
:
missing
.
append
(
item
)
if
ignore_duplicate
:
for
lst
in
expected
,
actual
:
try
:
while
True
:
lst
.
remove
(
item
)
except
ValueError
:
pass
if
ignore_duplicate
:
while
actual
:
item
=
actual
.
pop
()
unexpected
.
append
(
item
)
try
:
while
True
:
actual
.
remove
(
item
)
except
ValueError
:
pass
return
missing
,
unexpected
# anything left in actual is unexpected
return
missing
,
actual
# _Mismatch = namedtuple('Mismatch', 'actual expected value')
class
_Mismatch
(
tuple
):
'Mismatch(actual, expected, value)'
__slots__
=
()
_fields
=
(
'actual'
,
'expected'
,
'value'
)
def
__new__
(
_cls
,
actual
,
expected
,
value
):
'Create new instance of Mismatch(actual, expected, value)'
return
_tuple
.
__new__
(
_cls
,
(
actual
,
expected
,
value
))
# @classmethod
def
_make
(
cls
,
iterable
,
new
=
tuple
.
__new__
,
len
=
len
):
'Make a new Mismatch object from a sequence or iterable'
result
=
new
(
cls
,
iterable
)
if
len
(
result
)
!=
3
:
raise
TypeError
(
'Expected 3 arguments, got %d'
%
len
(
result
))
return
result
_make
=
classmethod
(
_make
)
def
__repr__
(
self
):
'Return a nicely formatted representation string'
return
'Mismatch(actual=%r, expected=%r, value=%r)'
%
self
def
_asdict
(
self
):
'Return a new OrderedDict which maps field names to their values'
# return OrderedDict(zip(self._fields, self))
return
dict
(
zip
(
self
.
_fields
,
self
))
def
_replace
(
_self
,
**
kwds
):
'Return a new Mismatch object replacing specified fields with new values'
result
=
_self
.
_make
(
map
(
kwds
.
pop
,
(
'actual'
,
'expected'
,
'value'
),
_self
))
if
kwds
:
raise
ValueError
(
'Got unexpected field names: %r'
%
kwds
.
keys
())
return
result
def
__getnewargs__
(
self
):
'Return self as a plain tuple. Used by copy and pickle.'
return
tuple
(
self
)
__dict__
=
_property
(
_asdict
)
def
__getstate__
(
self
):
'Exclude the OrderedDict from pickling'
pass
actual
=
_property
(
_itemgetter
(
0
),
doc
=
'Alias for field number 0'
)
expected
=
_property
(
_itemgetter
(
1
),
doc
=
'Alias for field number 1'
)
value
=
_property
(
_itemgetter
(
2
),
doc
=
'Alias for field number 2'
)
def
_count_diff_all_purpose
(
actual
,
expected
):
'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
# elements need not be hashable
s
,
t
=
list
(
actual
),
list
(
expected
)
m
,
n
=
len
(
s
),
len
(
t
)
NULL
=
object
()
result
=
[]
for
i
,
elem
in
enumerate
(
s
):
if
elem
is
NULL
:
continue
cnt_s
=
cnt_t
=
0
for
j
in
range
(
i
,
m
):
if
s
[
j
]
==
elem
:
cnt_s
+=
1
s
[
j
]
=
NULL
for
j
,
other_elem
in
enumerate
(
t
):
if
other_elem
==
elem
:
cnt_t
+=
1
t
[
j
]
=
NULL
if
cnt_s
!=
cnt_t
:
diff
=
_Mismatch
(
cnt_s
,
cnt_t
,
elem
)
result
.
append
(
diff
)
for
i
,
elem
in
enumerate
(
t
):
if
elem
is
NULL
:
continue
cnt_t
=
0
for
j
in
range
(
i
,
n
):
if
t
[
j
]
==
elem
:
cnt_t
+=
1
t
[
j
]
=
NULL
diff
=
_Mismatch
(
0
,
cnt_t
,
elem
)
result
.
append
(
diff
)
return
result
def
_ordered_count
(
iterable
):
'Return dict of element counts, in the order they were first seen'
c
=
{}
#OrderedDict()
for
elem
in
iterable
:
c
[
elem
]
=
c
.
get
(
elem
,
0
)
+
1
return
c
def
_count_diff_hashable
(
actual
,
expected
):
'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
# elements must be hashable
s
,
t
=
_ordered_count
(
actual
),
_ordered_count
(
expected
)
result
=
[]
for
elem
,
cnt_s
in
s
.
items
():
cnt_t
=
t
.
get
(
elem
,
0
)
if
cnt_s
!=
cnt_t
:
diff
=
_Mismatch
(
cnt_s
,
cnt_t
,
elem
)
result
.
append
(
diff
)
for
elem
,
cnt_t
in
t
.
items
():
if
elem
not
in
s
:
diff
=
_Mismatch
(
0
,
cnt_t
,
elem
)
result
.
append
(
diff
)
return
result
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment