Skip to content

Running a test module as a script. #20

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

Closed
pytestbot opened this issue Jan 27, 2011 · 6 comments
Closed

Running a test module as a script. #20

pytestbot opened this issue Jan 27, 2011 · 6 comments
Labels
type: enhancement new feature or API change, should be merged into features branch

Comments

@pytestbot
Copy link
Contributor

Originally reported by: Jurko Gospodnetić (BitBucket: jurko, GitHub: jurko)


I am trying to make my test modules runnable directly as scripts (e.g. python xxx.py) or as a python module (python -m xxx). Everything being done with Python 3.2.rc1 on Windows XP.

The closest I got so far is to add something like this to my test scripts:

    if __name__ == "__main__":
        import pytest
        pytest.main([__file__])

However, this does not work in all the cases.

Imagine the following scenario (I have attached files modeling this exact scenario so it can be more easily reproduced):

  • package module ppp
  • test module xxx.py contained inside package ppp

In it I can do the following:

  • 'python xxx.py' from the ppp folder
  • 'python -m xxx' from the ppp folder
  • 'python ppp\xxx.py' from the ppp's parent folder

but trying this:

  • 'python -m ppp.xxx' from the ppp's parent folder

causes the following error:

import file mismatch:
imported module 'ppp.xxx' has this __file__ attribute:
  ppp\xxx.py
which is not the same as the test file we want to collect:
  C:\Workplace\ppp\xxx.py
HINT: use a unique basename for your test file modules

Is there a better way to do get this functionality or is it something that is not supposed to be supported or is it something that needs fixing?

The error itself is reported from deep inside the py.py library and so far I have not been able to find a quick-fix for it.

Many thanks and best regards,
Jurko Gospodnetić


@pytestbot
Copy link
Contributor Author

Original comment by holger krekel (BitBucket: hpk42, GitHub: hpk42):


(couldn't open your your attachment)

This seems to be a problem in comparing absolute path with relative path. I think i could fix it ... could you try to invokve:

{{{
easy_install -i http://pypi.testrun.org -U py
}}}

and report back if the problem goes away?
(couldn't open your example archive btw)

@pytestbot
Copy link
Contributor Author

Original comment by Jurko Gospodnetić (BitBucket: jurko, GitHub: jurko):


I'll try the easy_install now and let you know the results...

Here's the same attachment afain in .zip format. It should contain the following:

  • folder 'ppp' (container package)
  • file 'ppp__init__.py' (empty)
  • file 'ppp\xxx.py' (see content below)

Best regards,
Jurko Gospodnetić

--- 'ppp\xxx.py' -----------
{{{
def test_pass():
assert 1 == 1

def test_fail():
assert 1 == 0

if name == "main":
import pytest
pytest.main([file])
}}}

@pytestbot
Copy link
Contributor Author

Original comment by Jurko Gospodnetić (BitBucket: jurko, GitHub: jurko):


Yup, it seems the latest development version fixes the problem. My guess is that the fix is the additional os.path.abspath() call in:

  • py/_path/local.py/LocalPath.samepath()

So I guess the problem will 'resolve itself' in time as new releases get pushed out and I can safely ignore it for now. :-)

And the whole idiom for calling the test script as a 'standalone script' using pytest.main([file]) - is there a better way or is this supposed to be ok?

Best regards,
Jurko Gospodnetić

@pytestbot
Copy link
Contributor Author

Original comment by holger krekel (BitBucket: hpk42, GitHub: hpk42):


pytest.main([file]) is ok i guess - however, "file" might have a ".pyc" or ".pyo" ending and thus might break. At least that's true on Python2.

We can think about introducing a safer shortcut. Unfortunately pytest.main() is used already to mean pytest.main(sys.argv[1:]), see http://pytest.org/usage.html#calling-pytest-from-python-code

Hum, you could actually do safely, even with the current release:

{{{
#!python
if name == 'main':
pytest.main(['--pyargs', name])

}}}

Maybe pytest.thismod() or something could be a shortcut. What do you think?

@pytestbot
Copy link
Contributor Author

Original comment by Jurko Gospodnetić (BitBucket: jurko, GitHub: jurko):


As for a pytest.thismod() shortcut (or any other name you find suitable) - if implemented 'correctly' that would be a 'black box' solving all my problems - so that's just fine by me. :-))

And as to how to implement this shortcut - here are some more thoughts:

  • You are correct in that file can contain the .pyc/.pyo extension. I just tested this with Python 3.2.rc1.

  • When I try your solution with the ['--pyargs', name] py.test arguments - it works ok when loading a .py module but reports a load of 'INTERNALERROR> ...' messages when used from a .pyc module. It seems like something internally assumes that the module uses the .py extension and then can not find it. Also, it seems some internal path to string conversion in _pytest\session.py is missing an explicit str() call.

    Here is a copy/paste of the results of such a run:

{{{
C:\Workplace>python bbb.pyc
============================================================= test session starts ==============================================================
platform win32 -- Python 3.2.0 -- pytest-2.0.0
INTERNALERROR> config = <_pytest.config.Config object at 0x00EF3270>
INTERNALERROR>
INTERNALERROR> def pytest_cmdline_main(config):
INTERNALERROR> """ default command line protocol for initialization, session,
INTERNALERROR> running tests and reporting. """
INTERNALERROR> session = Session(config)
INTERNALERROR> session.exitstatus = EXIT_OK
INTERNALERROR> try:
INTERNALERROR> config.pluginmanager.do_configure(config)
INTERNALERROR> config.hook.pytest_sessionstart(session=session)
INTERNALERROR> > config.hook.pytest_collection(session=session)
INTERNALERROR>
INTERNALERROR> config = <_pytest.config.Config object at 0x00EF3270>
INTERNALERROR> session = <Session 'pysj'>
INTERNALERROR>
INTERNALERROR> C:\Program Files\Python\Python32\lib\site-packages\pytest-2.0.0-py3.2.egg_pytest\session.py:64:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <HookCaller 'pytest_collection'>
INTERNALERROR>
INTERNALERROR> def call(self, **kwargs):
INTERNALERROR> methods = self.hookrelay._pm.listattr(self.name)
INTERNALERROR> > return self._docall(methods, kwargs)
INTERNALERROR>
INTERNALERROR> kwargs = {'session': <Session 'pysj'>}
INTERNALERROR> methods = [<function pytest_collection at 0x00D97C48>, <bound method TerminalReporter.pytest_collection of <_pytest.terminal.Te
rminalReporter object at 0x00FABBB0>>]
INTERNALERROR> self = <HookCaller 'pytest_collection'>
INTERNALERROR>
INTERNALERROR> C:\Program Files\Python\Python32\lib\site-packages\pytest-2.0.0-py3.2.egg_pytest\core.py:406:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <HookCaller 'pytest_collection'>
INTERNALERROR> methods = [<function pytest_collection at 0x00D97C48>, <bound method TerminalReporter.pytest_collection of <_pytest.terminal.Termi
nalReporter object at 0x00FABBB0>>]
INTERNALERROR> kwargs = {'session': <Session 'pysj'>}
INTERNALERROR>
INTERNALERROR> def _docall(self, methods, kwargs):
INTERNALERROR> self.trace(self.name, kwargs)
INTERNALERROR> self.trace.root.indent += 1
INTERNALERROR> mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
INTERNALERROR> try:
INTERNALERROR> > res = mc.execute()
INTERNALERROR>
INTERNALERROR> kwargs = {'session': <Session 'pysj'>}
INTERNALERROR> mc = <MultiCall 0 results, 0 meths, kwargs={'session': <Session 'pysj'>}>
INTERNALERROR> methods = [<function pytest_collection at 0x00D97C48>, <bound method TerminalReporter.pytest_collection of <_pytest.terminal.TerminalReporter object at 0x00FABBB0>>]
INTERNALERROR> self = <HookCaller 'pytest_collection'>
INTERNALERROR>
INTERNALERROR> C:\Program Files\Python\Python32\lib\site-packages\pytest-2.0.0-py3.2.egg_pytest\core.py:417:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <MultiCall 0 results, 0 meths, kwargs={'session': <Session 'pysj'>}>
INTERNALERROR>
INTERNALERROR> def execute(self):
INTERNALERROR> while self.methods:
INTERNALERROR> method = self.methods.pop()
INTERNALERROR> kwargs = self.getkwargs(method)
INTERNALERROR> > res = method(**kwargs)
INTERNALERROR>
INTERNALERROR> kwargs = {'session': <Session 'pysj'>}
INTERNALERROR> method = <function pytest_collection at 0x00D97C48>
INTERNALERROR> res = None
INTERNALERROR> self = <MultiCall 0 results, 0 meths, kwargs={'session': <Session 'pysj'>}>
INTERNALERROR>
INTERNALERROR> C:\Program Files\Python\Python32\lib\site-packages\pytest-2.0.0-py3.2.egg_pytest\core.py:338:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> session = <Session 'pysj'>
INTERNALERROR>
INTERNALERROR> def pytest_collection(session):
INTERNALERROR> > session.perform_collect()
INTERNALERROR>
INTERNALERROR> session = <Session 'pysj'>
INTERNALERROR>
INTERNALERROR> C:\Program Files\Python\Python32\lib\site-packages\pytest-2.0.0-py3.2.egg_pytest\session.py:86:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <Session 'pysj'>, args = ['main'], genitems = True
INTERNALERROR>
INTERNALERROR> def perform_collect(self, args=None, genitems=True):
INTERNALERROR> if args is None:
INTERNALERROR> args = self.config.args
INTERNALERROR> self.trace("perform_collect", self, args)
INTERNALERROR> self.trace.root.indent += 1
INTERNALERROR> self._notfound = []
INTERNALERROR> self._initialpaths = set()
INTERNALERROR> self._initialparts = []
INTERNALERROR> for arg in args:
INTERNALERROR> > parts = self._parsearg(arg)
INTERNALERROR>
INTERNALERROR> arg = 'main'
INTERNALERROR> args = ['main']
INTERNALERROR> genitems = True
INTERNALERROR> self = <Session 'pysj'>
INTERNALERROR>
INTERNALERROR> C:\Program Files\Python\Python32\lib\site-packages\pytest-2.0.0-py3.2.egg_pytest\session.py:373:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <Session 'pysj'>, arg = local('C:\Workplace\bbb.py')
INTERNALERROR>
INTERNALERROR> def _parsearg(self, arg):
INTERNALERROR> """ return (fspath, names) tuple after checking the file exists. """
INTERNALERROR> arg = str(arg)
INTERNALERROR> if self.config.option.pyargs:
INTERNALERROR> arg = self._tryconvertpyarg(arg)
INTERNALERROR> parts = str(arg).split("::")
INTERNALERROR> relpath = parts[0].replace("/", os.sep)
INTERNALERROR> path = self.fspath.join(relpath, abs=True)
INTERNALERROR> if not path.check():
INTERNALERROR> if self.config.option.pyargs:
INTERNALERROR> msg = "file or package not found: "
INTERNALERROR> else:
INTERNALERROR> msg = "file not found: "
INTERNALERROR> > raise pytest.UsageError(msg + arg)
INTERNALERROR> E TypeError: Can't convert 'LocalPath' object to str implicitly
INTERNALERROR>
INTERNALERROR> arg = local('C:\Workplace\bbb.py')
INTERNALERROR> msg = 'file or package not found: '
INTERNALERROR> parts = ['C:\Workplace\bbb.py']
INTERNALERROR> path = local('C:\Workplace\bbb.py')
INTERNALERROR> relpath = 'C:\Workplace\bbb.py'
INTERNALERROR> self = <Session 'pysj'>
INTERNALERROR>
INTERNALERROR> C:\Program Files\Python\Python32\lib\site-packages\pytest-2.0.0-py3.2.egg_pytest\session.py:466: TypeError

=============================================================== in 0.06 seconds ===============================================================
}}}

Here I used a bbb.pyc file with no available bbb.py file.

Hope this helps.

Best regards,
Jurko Gospodnetić

@pytestbot
Copy link
Contributor Author

Original comment by Jurko Gospodnetić (BitBucket: jurko, GitHub: jurko):


The ['--pyargs', name] error-reporting bug seems to have been fixed in changeset <>.

As for the ['--pyargs', name] solution not working without the source .py test script being available - I opened a separate issue <<issue 22>>.

@pytestbot pytestbot added the type: enhancement new feature or API change, should be merged into features branch label Jun 15, 2015
fkohlgrueber pushed a commit to fkohlgrueber/pytest that referenced this issue Oct 27, 2018
mgorny pushed a commit to mgorny/pytest that referenced this issue May 27, 2023
Adding SELENIUM_URI to allow host, port and path to be set at once.
mgorny pushed a commit to mgorny/pytest that referenced this issue May 27, 2023
fix __multicall__ for pytest-profiling plugin
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement new feature or API change, should be merged into features branch
Projects
None yet
Development

No branches or pull requests

1 participant