Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pytest 3.0.0+ and python-ldap #1869

Closed
aoodham opened this issue Aug 25, 2016 · 6 comments
Closed

pytest 3.0.0+ and python-ldap #1869

aoodham opened this issue Aug 25, 2016 · 6 comments

Comments

@aoodham
Copy link

aoodham commented Aug 25, 2016

Hi,

We've noticed an issue when using py.test on modules which have a dependency on python-ldap.
The stack trace is:

09:45:24 /usr/lib/python2.7/site-packages/py/_path/common.py:332: in visit
09:45:24     for x in Visitor(fil, rec, ignore, bf, sort).gen(self):
09:45:24 /usr/lib/python2.7/site-packages/py/_path/common.py:368: in gen
09:45:24     if p.check(dir=1) and (rec is None or rec(p))])
09:45:24 /usr/lib/python2.7/site-packages/_pytest/main.py:672: in _recurse
09:45:24     ihook = self.gethookproxy(path)
09:45:24 /usr/lib/python2.7/site-packages/_pytest/main.py:575: in gethookproxy
09:45:24     my_conftestmodules = pm._getconftestmodules(fspath)
09:45:24 /usr/lib/python2.7/site-packages/_pytest/config.py:315: in _getconftestmodules
09:45:24     mod = self._importconftest(conftestpath)
09:45:24 /usr/lib/python2.7/site-packages/_pytest/config.py:340: in _importconftest
09:45:24     raise ConftestImportFailure(conftestpath, sys.exc_info())
09:45:24 E   ConftestImportFailure: SyntaxError('invalid syntax', ('<string>', 1, 1, '@py_builtins'))
09:45:24 E     File "/usr/lib/python2.7/site-packages/_pytest/assertion/rewrite.py", line 207, in load_module
09:45:24 E       py.builtin.exec_(co, mod.__dict__)
09:45:24 E     File "/usr/lib/python2.7/site-packages/py/_builtin.py", line 221, in exec_
09:45:24 E       exec2(obj, globals, locals)
09:45:24 E     File "<string>", line 7, in exec2
09:45:24 E     File "/home/jenkins/workspace/cloud-explorer/software/nexus/cloud_explorer/python/sl/test_explorer/explorer_unit_test/conftest.py", line 6, in <module>
09:45:24 E       from sl.explorer import upgrade
09:45:24 E     File "/usr/lib/python2.7/site-packages/_pytest/assertion/rewrite.py", line 207, in load_module
09:45:24 E       py.builtin.exec_(co, mod.__dict__)
09:45:24 E     File "/usr/lib/python2.7/site-packages/py/_builtin.py", line 221, in exec_
09:45:24 E       exec2(obj, globals, locals)
09:45:24 E     File "<string>", line 7, in exec2
09:45:24 E     File "/home/jenkins/workspace/cloud-explorer/software/nexus/cloud_explorer/python/sl/explorer/upgrade.py", line 9, in <module>
09:45:24 E       import ldap
09:45:24 E     File "/usr/lib64/python2.7/site-packages/ldap/__init__.py", line 85, in <module>
09:45:24 E       from functions import open,initialize,init,get_option,set_option,escape_str
09:45:24 E     File "/usr/lib/python2.7/site-packages/_pytest/assertion/rewrite.py", line 207, in load_module
09:45:24 E       py.builtin.exec_(co, mod.__dict__)
09:45:24 E     File "/usr/lib/python2.7/site-packages/py/_builtin.py", line 221, in exec_
09:45:24 E       exec2(obj, globals, locals)
09:45:24 E     File "<string>", line 7, in exec2
09:45:24 E     File "/usr/lib64/python2.7/site-packages/ldap/functions.py", line 36, in <module>
09:45:24 E       from ldap.ldapobject import LDAPObject
09:45:24 E     File "/usr/lib/python2.7/site-packages/_pytest/assertion/rewrite.py", line 207, in load_module
09:45:24 E       py.builtin.exec_(co, mod.__dict__)
09:45:24 E     File "/usr/lib/python2.7/site-packages/py/_builtin.py", line 221, in exec_
09:45:24 E       exec2(obj, globals, locals)
09:45:24 E     File "<string>", line 7, in exec2
09:45:24 E     File "/usr/lib64/python2.7/site-packages/ldap/ldapobject.py", line 37, in <module>
09:45:24 E       from ldap.schema import SCHEMA_ATTRS
09:45:24 E     File "/usr/lib64/python2.7/site-packages/ldap/schema/__init__.py", line 11, in <module>
09:45:24 E       from ldap.schema.subentry import SubSchema,SCHEMA_ATTRS,SCHEMA_CLASS_MAPPING,SCHEMA_ATTR_MAPPING,urlfetch
09:45:24 E     File "/usr/lib/python2.7/site-packages/_pytest/assertion/rewrite.py", line 207, in load_module
09:45:24 E       py.builtin.exec_(co, mod.__dict__)
09:45:24 E     File "/usr/lib/python2.7/site-packages/py/_builtin.py", line 221, in exec_
09:45:24 E       exec2(obj, globals, locals)
09:45:24 E     File "<string>", line 7, in exec2
09:45:24 E     File "/usr/lib64/python2.7/site-packages/ldap/schema/subentry.py", line 19, in <module>
09:45:24 E       o = eval(_name)

This is running on a Fedora 20 machine with py.test 3.0.1 and python-ldap version 2.4.17. Although I can repeat the same on a fedora 23 machine running py.test 3.0.1/ 3.0.0 and python ldap 2.4.17/27
I can't seem to recreate this with a simple minimal example. Just having a test which references a conftest which imports ldap doesn't seem to work - so something strange must be happening, but I don't know what else to try.


(edited by @The-Compiler to add code symbols around the stacktrace)

@The-Compiler
Copy link
Member

I'm guessing this is somehow caused by #1619, because assertion rewriting wasn't done in conftest.py before - cc @flub @nicoddemus @sober7

Any chance you can share the full conftest.py where this happens?

@aoodham
Copy link
Author

aoodham commented Aug 26, 2016

Sure, the conftest file contains:

from flask_mako import render_template
from mock import Mock
import pytest

from sl.explorer import upgrade

from sl.explorer.models import Task, PbxPatch

@pytest.fixture()
def single_patch_db(app):

    db = app.extensions['sqlalchemy'].db
    with app.app_context():
        Task.query.delete(synchronize_session=False)
        PbxPatch.schedule(session=db.session,
                          patchFile='Test_patch_file',
                          patchVersion='1.8.2rc7',
                          endStep='Live',
                          )
        db.session.commit()

    return db


@pytest.fixture()
def single_archive_patch_db(app):

    db = app.extensions['sqlalchemy'].db
    with app.app_context():
        Task.query.delete(False)
        PbxPatch.schedule(session=db.session,
                          patchFile='Test_patch_file',
                          patchVersion='1.8.3d6',
                          endStep='Live',
                          active=False
        )
        db.session.commit()

    return db

@pytest.fixture
def render_template_spy(monkeypatch):
    render_template_spy = Mock(wraps=render_template)
    monkeypatch.setattr(upgrade, 'render_template', render_template_spy)
    return render_template_spy

This is the one which has the import which references ldap. There is another conftest file higher up the tree, which in turn uses the pytest_plugins keyword to pull in an additional file.

I can share those as well, if the above isn't of much help

@The-Compiler
Copy link
Member

So from what I see from that stacktrace, there are two relevant things happening here:

18  for _name in dir():
19    o = eval(_name)
20    if hasattr(o,'schema_attribute'):
21      SCHEMA_CLASS_MAPPING[o.schema_attribute] = o
22      SCHEMA_ATTR_MAPPING[o] = o.schema_attribute
  • pytest seems to insert its @py_builtins global into that module, which causes that eval to fail.

I wonder, why is 2) happening? Do you use pytest.register_assert_rewrite somewhere?

@nicoddemus
Copy link
Member

A bug was fixed just yesterday related to pytest_plugins defined as a string (as opposed to a list[str]) marking a lot of modules for assertion rewriting when they shouldn't be rewritten.

@aoodham Is it possible to test using the latest master and see if it has fixed this issue as well?

@aoodham
Copy link
Author

aoodham commented Aug 31, 2016

@nicoddemus:

Just tried running the test suite with latest master - it all looks good:

============================================================================================================ test session starts =============================================================================================================
platform linux2 -- Python 2.7.11, pytest-3.0.2.dev, py-1.4.31, pluggy-0.3.1 -- /bin/python
cachedir: .cache
rootdir: /home/apw/software, inifile: 
collected 132 items 
<all tests pass, not going to print it here, mostly boring>
=========================================================================================================== pytest-warning summary ===========================================================================================================
WP1 None Modules are already imported so can not be re-written: sl.nexustest.db_plugin
============================================================================================================ 39 tests deselected =============================================================================================================
======================================================================================== 93 passed, 39 deselected, 1 pytest-warnings in 20.65 seconds ========================================================================================

So aside from the warning - which I'm guessing didn't stop anything from happening, it all looks fine

@nicoddemus
Copy link
Member

Great! 😁

That warning only means that sl.nexustest.db_plugin was already imported by the time pytest start rewriting assertion in test modules. If you have plain asserts in that module, I suggest you call pytest.register_assertion_rewrite at some point before it gets imported (possibly right before/after the pytest_plugins declaration).

I'm closing this for now then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants