Closed FichteFoll closed 8 years ago
That's not good! Thanks for trying it out and reporting the problem, @FichteFoll.
I can't seem to reproduce (Win 7, Py 3.5.0 32-bit, pytest-2.8.0.dev4, py-1.4.28), but I'll dig deeper. In the meantime, could you try adding a pytest.ini
file with the following?
[pytest]
norecursedirs = __pycache__
Showing which file has changed is a good idea. Just opened #39 for that.
Run like this ptw -v
and tell which file shows as changed.
My guess is that you have some pytest plugin installed (something that generates .py in its own folder on every run, like a plugin called hypothesis) and that is triggering the repeated run. Just run py.test
and it shows the plugins installed like this - plugins: cov-2.1.0, pep8-1.0.6
It is NOT a bug, you need to use ptw --ignore=dir_a,dir_b
where dir_a and dir_b are the autogenerated directories.
@bendtherules Thanks!
@FichteFoll Try what @bendtherules is suggesting to see if you can identify what file is causing the loop. Are you using any plugins by chance?
I have pytest-cov installed but am not using it in the ptw
call.
Using -v
did show me the files that changed (that should be default), but doesn't exactly help me since I have no idea what could cause the listed files to have changed.
Procedure:
send_self/__init__.py
x:\Dropbox\Code\Python\send_self>py.test.watch -v
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.8.3, py-1.4.31, pluggy-0.3.1
rootdir: x:\Dropbox\Code\Python\send_self, inifile:
plugins: cov-2.2.0
collected 47 items
tests\test_deferring_methods.py .............
tests\test_garbage_collection.py .......
tests\test_send_self_env.py ...................
tests\test_subgenerators.py ...
tests\test_wrappers.py .....
========================== 47 passed in 1.54 seconds ==========================
Changes detected in files:
modified: send_self\__init__.py
Rerunning: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.8.3, py-1.4.31, pluggy-0.3.1
rootdir: x:\Dropbox\Code\Python\send_self, inifile:
plugins: cov-2.2.0
collected 47 items
tests\test_deferring_methods.py .........
Changes detected in files:
modified: tests\test_deferring_methods.py
modified: tests\test_garbage_collection.py
modified: tests\test_send_self_env.py
modified: tests\test_subgenerators.py
modified: tests\test_wrappers.py
Rerunning: py.test
..============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.8.3, py-1.4.31, pluggy-0.3.1
rootdir: x:\Dropbox\Code\Python\send_self, inifile:
plugins: cov-2.2.0
collected 47 items
tests\test_deferring_methods.py ...........
Changes detected in files:
modified: tests\test_deferring_methods.py
modified: tests\test_garbage_collection.py
modified: tests\test_send_self_env.py
modified: tests\test_subgenerators.py
modified: tests\test_wrappers.py
Rerunning: py.test
.
tests\test_garbage_collection.py .......
tests\test_send_self_env.py ...................
tests\test_subgenerators.py ....
tests\test_wrappers.py ....============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.8.3, py-1.4.31, pluggy-0.3.1
rootdir: x:\Dropbox\Code\Python\send_self, inifile:
plugins: cov-2.2.0
collecting 13 items.
========================== 47 passed in 2.11 seconds ==========================
collected 47 items
tests\test_deferring_methods.py ............
tests\test_garbage_collection.py .
Changes detected in files:
modified: tests\test_deferring_methods.py
modified: tests\test_garbage_collection.py
modified: tests\test_send_self_env.py
modified: tests\test_subgenerators.py
modified: tests\test_wrappers.py
Rerunning: py.test
...^CBatchvorgang abbrechen (J/N)?
x:\Dropbox\Code\Python\send_self>
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
x:\Dropbox\Code\Python\send_self\tests\__init__.py:34: KeyboardInterrupt
========================== 17 passed in 1.66 seconds ==========================
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
x:\Dropbox\Code\Python\send_self\send_self\__init__.py:119: KeyboardInterrupt
========================== 10 passed in 1.05 seconds ==========================
The project in question is located at https://github.com/FichteFoll/send_self
I tried doing the same, but cant replicate the loop.
Can it happen because of something that dropbox does when any file gets modified? Can you try putting them in some other directory which is not tracked by dropbox?
I also suspected this and yes, you were right. This is something caused by Dropbox, or Boxcryptor. I wonder why though, it's certainly not transparent why these exact files are changed.
I tried inside Dropbox in Windows on my machine now and it seemed to work there.
Don't know what Boxcryptor is though, does it encrypt stuff? In that case, it might modify some attributes or something like that? So, does putting it in another place solve the problem?
Yes, this is only the case inside Boxcryptor.
It encrypts folders/files inside file sharing services like dropbox and mounts a virtual drive (x:\
for me) with the actual contents decrypted. Inside the actual dropbox folder you can then find things like Dropbox/.../send_self/__init__.py.bc
.
Either way, this is not an issue with ptw so I'm closing. Thanks for your help.
Maybe you could add a timeout to ptw however? I don't see a way of fixing boxcryptor (it's proprietary) and I couldn't find any help on this issue regarding file events.
Something like "within
Ok, can you also try ptw -v --poll
?
I am not sure how poll works, @joeyespo can tell. But it is written as "useful for VMs" - might as well be good for virtual drives.
Doesn't help, unfortunately.
Edit: I'll mess with Boxcryptor settings a bit.
Good to know about your suggestion, just that it is hard to understand whether the change was intentional or not.
Considering that tests itself can run for some long time, so changes within the test duration might even be intentional. But we can actually know when exactly each file was touched and give a cooldown time for each.
Best way might be to check for actual change in content.
Feel free to add it a bug report, I will try to look into it when I get time.
I checked into it, it doesnt seem to change the "Date Modified" attribute, but WatchDog reports it FileModifiedEvent. Maybe it changes some attribute?
Wow, something weird happened. I used --runner=""
and then, just touching the file in file browser triggers the modified event on WatchDog. I am guessing ReadDirectoryChangesW API used in Windows triggers it because the directory gets regenerated of sorts on every change. Effectively, every read action on a file also seem to trigger it.
I'll fiddle a bit with watchdog tomorrow and potentially post this as a bug report there if I can identify it as an actual bug.
I still find it strange that only the files within test/
get detected as changed - and only after I changed one file while the watcher was already running.
From the WatchDog Docs, run watchmedo log --patterns="*.py;*.txt" --ignore-directories --recursive
to monitor the events of only .py files. This will help you understand what ptw
sees as changes.
I can explain why only that files in that directory was modified, because they were read and executed by pytest. My bet is that, if you add a non-test file, i.e. named like abc.py
, it will not get modified.
@FichteFoll FWIW, I just published v4.0, which has much more robust watch & re-run logic. It also shows changes detected by default, adds --spool
for adding a delay to allow other filesystem events to enqueue (this might help you in particular), adds --wait
to prevent test run interruption, and only allows one instance of pytest to run at a time.
Run pip install --upgrade pytest-watch
to upgrade.
Even though this isn't an issue with pytest-watch, it might help with your Boxcryptor case. (I'm pretty curious if it will. Please let me know if you get a chance to try it out!)
Well, this is odd:
X:\Dropbox\Code\Python\resumeback>py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collected 51 items
tests\test_deferring_methods.py ............
tests\test_deferring_methods_py3.py .
tests\test_garbage_collection.py .......
tests\test_send_self_env.py ......................
tests\test_send_self_env_py3.py .
tests\test_subgenerators_py3.py ...
tests\test_wrappers.py .....
========================== 51 passed in 2.01 seconds ==========================
X:\Dropbox\Code\Python\resumeback>pytest-watch
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collecting 20 items
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
c:\python35\lib\site-packages\_pytest\capture.py:273: KeyboardInterrupt
======================== no tests ran in 0.31 seconds =========================
Change detected: tests\__init__.py
Change detected: tests\test_deferring_methods.py
Change detected: resumeback\__init__.py
Change detected: tests\test_deferring_methods_py3.py
Change detected: tests\test_garbage_collection.py
Change detected: tests\test_send_self_env.py
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collecting 13 items
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
c:\python35\lib\site-packages\_pytest\assertion\rewrite.py:477: KeyboardInterrupt
======================== no tests ran in 0.73 seconds =========================
Change detected: tests\__init__.py
Change detected: tests\test_deferring_methods.py
Change detected: resumeback\__init__.py
Change detected: tests\test_deferring_methods_py3.py
Change detected: tests\test_garbage_collection.py
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collecting 20 items
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
c:\python35\lib\site-packages\_pytest\capture.py:371: KeyboardInterrupt
======================== no tests ran in 0.29 seconds =========================
Change detected: tests\__init__.py
Change detected: tests\test_deferring_methods.py
Change detected: resumeback\__init__.py
Change detected: tests\test_deferring_methods_py3.py
Change detected: tests\test_garbage_collection.py
Change detected: tests\test_send_self_env.py
Running: py.test
X:\Dropbox\Code\Python\resumeback>
I only pressed Ctrl+C once, at the end where it terminated, however no actual test session is executed because it has seemingly been interrupted. Another bug?
That aside, I suppose it is even worse now with all files being detected as changed immediately?
Here's a console log with --fulltrace
:
X:\Dropbox\Code\Python\resumeback>pytest-watch -- --fulltrace
Running: py.test --fulltrace
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collecting 21 items
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
config = <_pytest.config.Config object at 0x00000000015F4940>
doit = <function _main at 0x000000000165B0D0>
def wrap_session(config, doit):
"""Skeleton command line program"""
session = Session(config)
session.exitstatus = EXIT_OK
initstate = 0
try:
try:
config._do_configure()
initstate = 1
config.hook.pytest_sessionstart(session=session)
initstate = 2
> session.exitstatus = doit(config, session) or 0
c:\python35\lib\site-packages\_pytest\main.py:94:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
config = <_pytest.config.Config object at 0x00000000015F4940>
session = <Session 'resumeback'>
def _main(config, session):
""" default command line protocol for initialization, session,
running tests and reporting. """
> config.hook.pytest_collection(session=session)
c:\python35\lib\site-packages\_pytest\main.py:124:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_HookCaller 'pytest_collection'>
kwargs = {'__multicall__': <_MultiCall 0 results, 0 meths, kwargs={'session': <Session 'resumeback'>, '__multicall__': <
_MultiCall 0 results, 0 meths, kwargs={...}>}>, 'session': <Session 'resumeback'>}
def __call__(self, **kwargs):
assert not self.is_historic()
> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:724:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.config.PytestPluginManager object at 0x000000000148BF28>
hook = <_HookCaller 'pytest_collection'>, methods = []
kwargs = {'__multicall__': <_MultiCall 0 results, 0 meths, kwargs={'session': <Session 'resumeback'>, '__multicall__': <
_MultiCall 0 results, 0 meths, kwargs={...}>}>, 'session': <Session 'resumeback'>}
def _hookexec(self, hook, methods, kwargs):
# called from all hookcaller instances.
# enable_tracing will set its own wrapping function at self._inner_hookexec
> return self._inner_hookexec(hook, methods, kwargs)
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:338:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
hook = <_HookCaller 'pytest_collection'>, methods = []
kwargs = {'__multicall__': <_MultiCall 0 results, 0 meths, kwargs={'session': <Session 'resumeback'>, '__multicall__': <
_MultiCall 0 results, 0 meths, kwargs={...}>}>, 'session': <Session 'resumeback'>}
self._inner_hookexec = lambda hook, methods, kwargs: \
> _MultiCall(methods, kwargs, hook.spec_opts).execute()
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:333:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_MultiCall 0 results, 0 meths, kwargs={'session': <Session 'resumeback'>, '__multicall__': <_MultiCall 0 results
, 0 meths, kwargs={...}>}>
def execute(self):
all_kwargs = self.kwargs
self.results = results = []
firstresult = self.specopts.get("firstresult")
while self.hook_impls:
hook_impl = self.hook_impls.pop()
args = [all_kwargs[argname] for argname in hook_impl.argnames]
if hook_impl.hookwrapper:
return _wrapped_call(hook_impl.function(*args), self.execute)
> res = hook_impl.function(*args)
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:596:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
session = <Session 'resumeback'>
def pytest_collection(session):
> return session.perform_collect()
c:\python35\lib\site-packages\_pytest\main.py:133:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Session 'resumeback'>, args = None, genitems = True
def perform_collect(self, args=None, genitems=True):
hook = self.config.hook
try:
> items = self._perform_collect(args, genitems)
c:\python35\lib\site-packages\_pytest\main.py:565:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Session 'resumeback'>, args = ['X:\\Dropbox\\Code\\Python\\resumeback']
genitems = True
def _perform_collect(self, args, genitems):
if args is None:
args = self.config.args
self.trace("perform_collect", self, args)
self.trace.root.indent += 1
self._notfound = []
self._initialpaths = set()
self._initialparts = []
self.items = items = []
for arg in args:
parts = self._parsearg(arg)
self._initialparts.append(parts)
self._initialpaths.add(parts[0])
rep = collect_one_node(self)
self.ihook.pytest_collectreport(report=rep)
self.trace.root.indent -= 1
if self._notfound:
errors = []
for arg, exc in self._notfound:
line = "(no name %r in any of %r)" % (arg, exc.args[0])
errors.append("not found: %s\n%s" % (arg, line))
#XXX: test this
raise pytest.UsageError(*errors)
if not genitems:
return rep.result
else:
if rep.passed:
for node in rep.result:
> self.items.extend(self.genitems(node))
c:\python35\lib\site-packages\_pytest\main.py:601:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Session 'resumeback'>, node = <Module 'tests/test_send_self_env.py'>
def genitems(self, node):
self.trace("genitems", node)
if isinstance(node, pytest.Item):
node.ihook.pytest_itemcollected(item=node)
yield node
else:
assert isinstance(node, pytest.Collector)
> rep = collect_one_node(node)
c:\python35\lib\site-packages\_pytest\main.py:739:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
collector = <Module 'tests/test_send_self_env.py'>
def collect_one_node(collector):
ihook = collector.ihook
ihook.pytest_collectstart(collector=collector)
> rep = ihook.pytest_make_collect_report(collector=collector)
c:\python35\lib\site-packages\_pytest\runner.py:416:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_HookCaller 'pytest_make_collect_report'>
kwargs = {'__multicall__': <_MultiCall 0 results, 0 meths, kwargs={'__multicall__': <_MultiCall 0 results, 0 meths, kwar
gs={...}>, 'collector': <Module 'tests/test_send_self_env.py'>}>, 'collector': <Module 'tests/test_send_self_env.py'>}
def __call__(self, **kwargs):
assert not self.is_historic()
> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:724:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.config.PytestPluginManager object at 0x000000000148BF28>
hook = <_HookCaller 'pytest_make_collect_report'>, methods = []
kwargs = {'__multicall__': <_MultiCall 0 results, 0 meths, kwargs={'__multicall__': <_MultiCall 0 results, 0 meths, kwar
gs={...}>, 'collector': <Module 'tests/test_send_self_env.py'>}>, 'collector': <Module 'tests/test_send_self_env.py'>}
def _hookexec(self, hook, methods, kwargs):
# called from all hookcaller instances.
# enable_tracing will set its own wrapping function at self._inner_hookexec
> return self._inner_hookexec(hook, methods, kwargs)
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:338:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
hook = <_HookCaller 'pytest_make_collect_report'>, methods = []
kwargs = {'__multicall__': <_MultiCall 0 results, 0 meths, kwargs={'__multicall__': <_MultiCall 0 results, 0 meths, kwar
gs={...}>, 'collector': <Module 'tests/test_send_self_env.py'>}>, 'collector': <Module 'tests/test_send_self_env.py'>}
self._inner_hookexec = lambda hook, methods, kwargs: \
> _MultiCall(methods, kwargs, hook.spec_opts).execute()
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:333:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_MultiCall 0 results, 0 meths, kwargs={'__multicall__': <_MultiCall 0 results, 0 meths, kwargs={...}>, 'collecto
r': <Module 'tests/test_send_self_env.py'>}>
def execute(self):
all_kwargs = self.kwargs
self.results = results = []
firstresult = self.specopts.get("firstresult")
while self.hook_impls:
hook_impl = self.hook_impls.pop()
args = [all_kwargs[argname] for argname in hook_impl.argnames]
if hook_impl.hookwrapper:
> return _wrapped_call(hook_impl.function(*args), self.execute)
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:595:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
wrap_controller = <generator object pytest_make_collect_report at 0x000000000366CCA8>
func = <bound method _MultiCall.execute of <_MultiCall 0 results, 0 meths, kwargs={'__multicall__': <_MultiCall 0 result
s, 0 meths, kwargs={...}>, 'collector': <Module 'tests/test_send_self_env.py'>}>>
def _wrapped_call(wrap_controller, func):
""" Wrap calling to a function with a generator which needs to yield
exactly once. The yield point will trigger calling the wrapped function
and return its _CallOutcome to the yield point. The generator then needs
to finish (raise StopIteration) in order for the wrapped call to complete.
"""
try:
next(wrap_controller) # first yield
except StopIteration:
_raise_wrapfail(wrap_controller, "did not yield")
call_outcome = _CallOutcome(func)
try:
> wrap_controller.send(call_outcome)
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:249:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.capture.CaptureManager object at 0x000000000362EFD0>
collector = <Module 'tests/test_send_self_env.py'>
@pytest.hookimpl(hookwrapper=True)
def pytest_make_collect_report(self, collector):
if isinstance(collector, pytest.File):
self.resumecapture()
outcome = yield
out, err = self.suspendcapture()
> rep = outcome.get_result()
c:\python35\lib\site-packages\_pytest\capture.py:113:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.vendored_packages.pluggy._CallOutcome object at 0x000000000373FCC0>
def get_result(self):
if self.excinfo is None:
return self.result
else:
ex = self.excinfo
if _py3:
> raise ex[1].with_traceback(ex[2])
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:278:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.vendored_packages.pluggy._CallOutcome object at 0x000000000373FCC0>
func = <bound method _MultiCall.execute of <_MultiCall 0 results, 0 meths, kwargs={'__multicall__': <_MultiCall 0 result
s, 0 meths, kwargs={...}>, 'collector': <Module 'tests/test_send_self_env.py'>}>>
def __init__(self, func):
try:
> self.result = func()
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:264:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_MultiCall 0 results, 0 meths, kwargs={'__multicall__': <_MultiCall 0 results, 0 meths, kwargs={...}>, 'collecto
r': <Module 'tests/test_send_self_env.py'>}>
def execute(self):
all_kwargs = self.kwargs
self.results = results = []
firstresult = self.specopts.get("firstresult")
while self.hook_impls:
hook_impl = self.hook_impls.pop()
args = [all_kwargs[argname] for argname in hook_impl.argnames]
if hook_impl.hookwrapper:
return _wrapped_call(hook_impl.function(*args), self.execute)
> res = hook_impl.function(*args)
c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:596:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
collector = <Module 'tests/test_send_self_env.py'>
def pytest_make_collect_report(collector):
> call = CallInfo(collector._memocollect, "memocollect")
c:\python35\lib\site-packages\_pytest\runner.py:288:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <[AttributeError("'CallInfo' object has no attribute 'result'") raised in repr()] CallInfo object at 0x373ff60>
func = <bound method Collector._memocollect of <Module 'tests/test_send_self_env.py'>>
when = 'memocollect'
def __init__(self, func, when):
#: context of invocation: one of "setup", "call",
#: "teardown", "memocollect"
self.when = when
self.start = time()
try:
> self.result = func()
c:\python35\lib\site-packages\_pytest\runner.py:150:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Module 'tests/test_send_self_env.py'>
def _memocollect(self):
""" internal helper method to cache results of calling collect(). """
> return self._memoizedcall('_collected', lambda: list(self.collect()))
c:\python35\lib\site-packages\_pytest\main.py:435:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Module 'tests/test_send_self_env.py'>, attrname = '_collected'
function = <function Collector._memocollect.<locals>.<lambda> at 0x00000000036A62F0>
def _memoizedcall(self, attrname, function):
exattrname = "_ex_" + attrname
failure = getattr(self, exattrname, None)
if failure is not None:
py.builtin._reraise(failure[0], failure[1], failure[2])
if hasattr(self, attrname):
return getattr(self, attrname)
try:
> res = function()
c:\python35\lib\site-packages\_pytest\main.py:315:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> return self._memoizedcall('_collected', lambda: list(self.collect()))
c:\python35\lib\site-packages\_pytest\main.py:435:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Module 'tests/test_send_self_env.py'>
def collect(self):
self.session._fixturemanager.parsefactories(self)
> return super(Module, self).collect()
c:\python35\lib\site-packages\_pytest\python.py:605:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Module 'tests/test_send_self_env.py'>
def collect(self):
if not getattr(self.obj, "__test__", True):
return []
# NB. we avoid random getattrs and peek in the __dict__ instead
# (XXX originally introduced from a PyPy need, still true?)
dicts = [getattr(self.obj, '__dict__', {})]
for basecls in inspect.getmro(self.obj.__class__):
dicts.append(basecls.__dict__)
seen = {}
l = []
for dic in dicts:
for name, obj in list(dic.items()):
if name in seen:
continue
seen[name] = True
> res = self.makeitem(name, obj)
c:\python35\lib\site-packages\_pytest\python.py:459:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Module 'tests/test_send_self_env.py'>, name = '__reduce__'
obj = <method '__reduce__' of 'object' objects>
def makeitem(self, name, obj):
#assert self.ihook.fspath == self.fspath, self
> return self.ihook.pytest_pycollect_makeitem(
collector=self, name=name, obj=obj)
c:\python35\lib\site-packages\_pytest\python.py:470:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Module 'tests/test_send_self_env.py'>
@property
def ihook(self):
""" fspath sensitive hook proxy used to call pytest hooks"""
> return self.session.gethookproxy(self.fspath)
E KeyboardInterrupt
c:\python35\lib\site-packages\_pytest\main.py:250: KeyboardInterrupt
======================== no tests ran in 0.56 seconds =========================
Change detected: tests\__init__.py
Change detected: tests\test_deferring_methods.py
Change detected: resumeback\__init__.py
Change detected: tests\test_deferring_methods_py3.py
Change detected: tests\test_garbage_collection.py
Change detected: tests\test_send_self_env.py
Running: py.test --fulltrace
^C
X:\Dropbox\Code\Python\resumeback>
Fascinating.
These files keep on emitting FileModifiedEvent
events from Watchdog:
Change detected: tests\__init__.py
Change detected: tests\test_deferring_methods.py
Change detected: resumeback\__init__.py
Change detected: tests\test_deferring_methods_py3.py
Change detected: tests\test_garbage_collection.py
And sometimes:
Change detected: tests\test_send_self_env.py
Maybe Boxcryptor really is touching these files when Python imports them from disk. I think I found a related issue on the forums.
Can you try these?
Polling
> ptw --poll
This does a manual check for differences instead of using OS events. If Boxcryptor is opening the files in a way that causes the OS to generate a modified
event, but doesn't actually change anything on the file, this might work.
Spooling
> ptw --spool 5000
This will wait 5 seconds before re-running when changes are detected. If Boxcryptor takes time to sync files before it updates the mod time, and accessing the file during this time invalidates the syncing, this might work.
Thanks for continuing to try things!
> ptw --poll
X:\Dropbox\Code\Python\resumeback>ptw --poll
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collected 52 items
test.txt s
tests\test_deferring_methods.py ..........Unhandled exception in thread started by <bound method Thread._bootstrap of <T
hread(Thread-10, started daemon 8332)>>
Traceback (most recent call last):
File "c:\python35\lib\threading.py", line 923, in _bootstrap_inner
self.run()
File "c:\python35\lib\threading.py", line 871, in run
self._target(*self._args, **self._kwargs)
File "X:\Dropbox\Code\Python\resumeback\resumeback\__init__.py", line 133, in _next_wait
return self._wait(generator, self._next, timeout)
File "X:\Dropbox\Code\Python\resumeback\resumeback\__init__.py", line 102, in _wait
raise RuntimeError("%s has already terminated" % generator)
RuntimeError: <generator object func at 0x00000000040111A8> has already terminated
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "c:\python35\lib\threading.py", line 891, in _bootstrap
self._bootstrap_inner()
File "c:\python35\lib\threading.py", line 933, in _bootstrap_inner
(self.name, _format_exc()), file=self._stderr)
File "c:\python35\lib\site-packages\_pytest\capture.py", line 232, in write
self.buffer.write(obj)
ValueError: I/O operation on closed file
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
X:\Dropbox\Code\Python\resumeback\tests\test_deferring_methods.py:202: KeyboardInterrupt
==================== 10 passed, 1 skipped in 1.32 seconds =====================
Wrapper is being deleted <resumeback.WeakGeneratorWrapper object at 0x000000000371C550>
Wrapper is being deleted <resumeback.StrongGeneratorWrapper object at 0x000000000371C8D0>
Deletion detected: tests\test_subgenerators_py3.py
Deletion detected: tests\test_deferring_methods.py
Deletion detected: tests\test_send_self_env_py3.py
Deletion detected: tests\test_deferring_methods_py3.py
Deletion detected: tests\__init__.py
Deletion detected: tests\test_send_self_env.py
Deletion detected: tests\test_garbage_collection.py
Deletion detected: tests\test_wrappers.py
Running: py.test
Traceback (most recent call last):
File "c:\python35\lib\runpy.py", line 170, in _run_module_as_main
"__main__", mod_spec)
File "c:\python35\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Python35\Scripts\py.test.exe\__main__.py", line 9, in <module>
File "c:\python35\lib\site-packages\_pytest\config.py", line 39, in main
config = _prepareconfig(args, plugins)
File "c:\python35\lib\site-packages\_pytest\config.py", line 118, in _prepareconfig
pluginmanager=pluginmanager, args=args)
File "c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 724, in __call__
return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
File "c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 338, in _hookexec
return self._inner_hookexec(hook, methods, kwargs)
File "c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 333, in <lambda>
_MultiCall(methods, kwargs, hook.spec_opts).execute()
File "c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 595, in execute
return _wrapped_call(hook_impl.function(*args), self.execute)
File "c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 249, in _wrapped_call
wrap_controller.send(call_outcome)
File "c:\python35\lib\site-packages\_pytest\helpconfig.py", line 28, in pytest_cmdline_parse
config = outcome.get_result()
File "c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 278, in get_result
raise ex[1].with_traceback(ex[2])
File "c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 264, in __init__
self.result = func()
File "c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 596, in execute
res = hook_impl.function(*args)
File "c:\python35\lib\site-packages\_pytest\config.py", line 861, in pytest_cmdline_parse
self.parse(args)
File "c:\python35\lib\site-packages\_pytest\config.py", line 966, in parse
self._preparse(args, addopts=addopts)
File "c:\python35\lib\site-packages\_pytest\config.py", line 927, in _preparse
self.pluginmanager.load_setuptools_entrypoints("pytest11")
File "c:\python35\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 495, in load_setuptools_entrypoints
from pkg_resources import iter_entry_points, DistributionNotFound
File "c:\python35\lib\site-packages\pkg_resources\__init__.py", line 37, in <module>
import email.parser
File "<frozen importlib._bootstrap>", line 969, in _find_and_load
File "<frozen importlib._bootstrap>", line 954, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 896, in _find_spec
File "<frozen importlib._bootstrap_external>", line 1136, in find_spec
File "<frozen importlib._bootstrap_external>", line 1110, in _get_spec
File "<frozen importlib._bootstrap_external>", line 1218, in find_spec
File "<frozen importlib._bootstrap_external>", line 75, in _path_stat
KeyboardInterrupt
Deletion detected: resumeback\__init__.py
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collected 52 items
test.txt s
tests\test_deferring_methods.py ........
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
X:\Dropbox\Code\Python\resumeback\resumeback\__init__.py:97: KeyboardInterrupt
===================== 8 passed, 1 skipped in 0.92 seconds =====================
Deletion detected: tests\test_subgenerators_py3.py
Deletion detected: tests\test_deferring_methods.py
Deletion detected: tests\test_send_self_env_py3.py
Deletion detected: tests\test_deferring_methods_py3.py
Deletion detected: tests\__init__.py
Deletion detected: tests\test_send_self_env.py
Deletion detected: tests\test_garbage_collection.py
Deletion detected: tests\test_wrappers.py
Running: py.test
Traceback (most recent call last):
File "c:\python35\lib\runpy.py", line 170, in _run_module_as_main
"__main__", mod_spec)
File "c:\python35\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Python35\Scripts\py.test.exe\__main__.py", line 5, in <module>
File "c:\python35\lib\site-packages\pytest.py", line 27, in <module>
_preloadplugins() # to populate pytest.* namespace so help(pytest) works
File "c:\python35\lib\site-packages\_pytest\config.py", line 76, in _preloadplugins
_preinit.append(get_config())
File "c:\python35\lib\site-packages\_pytest\config.py", line 85, in get_config
pluginmanager.import_plugin(spec)
File "c:\python35\lib\site-packages\_pytest\config.py", line 385, in import_plugin
__import__(importspec)
File "c:\python35\lib\site-packages\_pytest\pdb.py", line 3, in <module>
import pdb
File "c:\python35\lib\pdb.py", line 76, in <module>
import glob
File "c:\python35\lib\glob.py", line 125, in <module>
magic_check = re.compile('([*?[])')
File "c:\python35\lib\re.py", line 224, in compile
return _compile(pattern, flags)
File "c:\python35\lib\re.py", line 293, in _compile
p = sre_compile.compile(pattern, flags)
File "c:\python35\lib\sre_compile.py", line 540, in compile
code = _code(p, flags)
File "c:\python35\lib\sre_compile.py", line 525, in _code
_compile(code, p.data, flags)
File "c:\python35\lib\sre_compile.py", line 144, in _compile
_compile(code, av[1], flags)
File "c:\python35\lib\sre_compile.py", line 107, in _compile
_compile_charset(av, flags, code, fixup, fixes)
File "c:\python35\lib\sre_compile.py", line 224, in _compile_charset
for op, av in _optimize_charset(charset, fixup, fixes):
File "c:\python35\lib\sre_compile.py", line 327, in _optimize_charset
data = _mk_bitmap(charmap)
File "c:\python35\lib\sre_compile.py", line 377, in _mk_bitmap
for i in range(len(s), 0, -_CODEBITS)]
File "c:\python35\lib\sre_compile.py", line 377, in <listcomp>
for i in range(len(s), 0, -_CODEBITS)]
KeyboardInterrupt
Deletion detected: resumeback\__init__.py
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collecting 43 items
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
c:\python35\lib\site-packages\py\_path\local.py:353: KeyboardInterrupt
======================== no tests ran in 0.98 seconds =========================
X:\Dropbox\Code\Python\resumeback>
> ptw-spool 5000
X:\Dropbox\Code\Python\resumeback>ptw --spool 5000
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collecting 1 items
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
c:\python35\lib\tokenize.py:454: KeyboardInterrupt
======================== no tests ran in 0.67 seconds =========================
Change detected: tests\__init__.py
Change detected: tests\test_deferring_methods.py
Change detected: resumeback\__init__.py
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collecting 1 items
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
c:\python35\lib\site-packages\_pytest\_code\source.py:231: KeyboardInterrupt
======================== no tests ran in 0.76 seconds =========================
Change detected: tests\__init__.py
Change detected: tests\test_deferring_methods.py
Change detected: resumeback\__init__.py
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collecting 1 items
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
<frozen importlib._bootstrap_external>:815: KeyboardInterrupt
======================== no tests ran in 0.94 seconds =========================
Change detected: tests\__init__.py
Change detected: tests\test_deferring_methods.py
Running: py.test
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: X:\Dropbox\Code\Python\resumeback, inifile:
plugins: cov-2.2.1
collecting 1 items
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
to show a full traceback on KeyboardInterrupt use --fulltrace
c:\python35\lib\site-packages\py\_path\local.py:353: KeyboardInterrupt
======================== no tests ran in 0.91 seconds =========================
X:\Dropbox\Code\Python\resumeback>
Had to cancel both because they were looping. It appears that in the first command there is an error in pytest while in both commands misterious KeyboardInterrupt
exceptions occur that just outright stop the tests from actually running.
I should note that ptw
works fine in a non-Boxcryptor folder.
Edit: Btw, I don't need to change a file anymore to trigger this behavior. Previously I needed to change one file in order to make the test runner loop, but now it does so right from the start.
Previously I needed to change one file in order to make the test runner loop, but now it does so right from the start.
That's probably because pytest-watch now runs a "collect" iteration to look for the config file. This is so both pytest and pytest-watch use the same config file lookup logic.
So looks like this is definitely a Boxcryptor issue.
Thanks for humoring me while looking for a workaround.
I just tried this on my project and it looks good initially. However, once I update any file (i.e. re-save), pytest-watch just performs test after test after test ... until I ctrl-c.
It should definitely not do that.
There is either a loop in the tool itself or it detects changes to files that are generated during the build process and thus always attempts to rebuild.
The latter is unlikely however since it does not start looping until the very first change is detected. Furthermore, I checked which files had changed in the directory since the "original" run of pytest-watch and it was only the file I actually did change and its corresponding
__pycache__/*.pyc
file. And that file is very likely not regenerated if the source file didn't change either.It would be nice if the changed file was displayed in the console before the command is rerun.
Environment: Windows7, Python 3.5.0 (64-bit), pytest 2.8.3, py 1.4.31, pytest-watch 3.8.0, watchdog 0.8.3