Pytest run a 'setup' method based on pytest command line argument - python

My issue is, how can I execute a setup method, that is based on a pytest argument when I run pytest? Basically I want this 'setup method' to run first before running any tests.
For simplicity lets say I have a file 'text_something.py'
import somemodule
def test_some(usefakemodule):
...
the 'somemodule' is either installed in the environment or not. If its installed already, then it will work no problem. If not, I need to add the path of the fake module by running a method that basically does sys.path.append(XXX).
In short, I want to run 'pytest -v --usefakemodule' if I want to use the fake module dir, or just 'pytest -v' to just use that library installed locally (assuming its installed there).
I tried adding a fixture (scope=session) in conftest.py, but it doesnt seem to run/execute it first before it executes 'test_something.py', which will then state no module named 'somemodule'
I can run a regular method in conftest, but I dont know how it can depend on the pytest command line argument 'usefakemodule'.

In your conftest.py you use pytest_addoption combined with pytest_cmdline_main,
pleas refer to the documentation for details.
import pytest
def pytest_addoption(parser):
parser.addoption(
"--usefakemodule", action="store_true", default=False, help="Use fake module "
)
def pytest_cmdline_main(config):
usefakemodule = config.getoption("--usefakemodule")
print(usefakemodule)
if usefakemodule:
print("OK fake module ")
else:
print("no fakes")

I don't know whether/how you can have pytest accept extra arguments, but here are a couple other ideas for accomplishing this:
Just try to import the real module, and update the load path if you get an ImportError:
try:
import somemodule
except ImportError:
sys.path.append(XXX)
import somemodule
Or, use an environment var, and run with USE_FAKE_MODULE=true pytest -v:
import os
if os.environ.get('USE_FAKE_MODULE'):
sys.path.append(XXX)

Related

Running a module workaround python "Scalene"

I am trying to debug a memory leak in a module using Scalene.
Unfortunately, it appears that I can only run scalene script.py while I need to be able to specify the module to correctly run the application with python -m mymodule, which I can't seem to do with scalene.
Is there a way to overcome this? Thank you in advance
cf Scalene's documentation :
scalene your_prog.py # full profile (prints to console)
python3 -m scalene your_prog.py # equivalent alternative
You can use the second form with Scalene.
You can use runpy.run_module() to create a wrapper around your module, which you can then profile!
wrapper.py might contain:
from runpy import run_module
run_module('your_module_name', run_name='__main__')
and then you can run scalene wrapper.py!
The run_name argument is needed in order to "trick" the if __name__ == '__main__' clause into executing, if you have one.

How do I create terminal commands in my python script?

I want to create terminal commands in my python script.
for example,
$ cd my_project_folder
$ --help (I use a command in this python folder)
outputs
$ this is the help command. You've activated it using --help. This is only possible because you cd'd to the folder and inputted this command.
I am looking for user defined commands ( ones that I've already defined in my python function.)
I am not looking for commands like 'ls' and 'pwd'.
You can use os.system, as below:
import os
os.system('your command')
Use os module if you wanna execute command that is specific to bash or shell that you use
import os
os.system("string command")
As Leemosh sugested you can use click module to make your own commands that are related to scripts
And you can also use sys module to read args that you put affter your script
example
$ python3 name_of_script.py arg_n
import sys
if sys.argv[1] == "commnd":
do something
What you are looking for is creating a setup.py file and defining some entry points. I'd recommend watching https://www.youtube.com/watch?v=GIF3LaRqgXo&ab_channel=CodingTech or https://www.youtube.com/watch?v=4fzAMdLKC5ks&ab_channel=NextDayVideo to better understand how to deal with setup.py.
from setuptools import setup
setup(
name="Name_of_your_app",
version="0.0.1",
desciption="some description",
py_modules=["app"], # I think you don't need that
package_dir={"": "src"}, # and probably you don't need this as well
entry_points={"console_scripts": {"THIS_IS_THE_DEFINED_COMMAND=app:main"}},
)
app is name of the py file, main is function you wanna call.
app.py
def main():
print("hello")

executing standalone fabric script by calling it by its name, without the .py extension

I have a fabric script called fwp.py that I run without calling it throug fab by using:
if __name__ == '__main__':
# imports for standalone mode only
import sys
import fabric.main
fabric.main.main(fabfile_locations=[__file__])
The thing is then have to call the script by calling fwp.py. I'd like to rename it as fwp to be able to call it as fwp. But doing that would result in
Fatal error: Couldn't find any fabfiles!
Is there a way to make Python/Fabric import this file, despite the lack of a ".py" extension?
To reiterate and clarify:
I'm not using the "fab" utility (e.g. as fab task task:parameter); just calling my script as fwp.py task task:parameter, and would like to be able to call it as fwp task task:parameter.
Update
It's not a duplicate of this question. The question is not "How to run a stand-alone fabric script?", but "How to do so, while having a script without a .py" extension.
EDIT: Original answer corrected
The fabric.main.main() function automatically adds .py to the end of supplied fabfile locations (see https://github.com/fabric/fabric/blob/master/fabric/main.py#L93). Unfortunately that function also uses Python's import machinery to load the file so it has to look like a module or package. Without reimplementing much of the fabric.main module I don't think it will be possible. You could try monkey-patching both fabric.main.find_fabfiles and fabric.main.load_fabfiles to make it work.
Origininal answer (wrong)
I can get this to work unaltered on a freshly installed fabric package. The following will execute with a filename fwp and executable permission on version 1.10.1, Python2.7. I would just try upgrading fabric.
#!/usr/bin/env python
from fabric.api import *
import fabric.main
def do():
local('echo "Hello World"')
if __name__ == '__main__':
fabric.main.main(fabfile_locations=[__file__])
Output:
$ ./fwp do
Hello World
Done

How can I check for which command is run in setup.py?

I would like to know how to make some code in setup.py conditional on which command (e.g. install or upload) was run.
Specifically, I'd like to have:
An easy way to add "hacks" such as ignoring a particular file in install, but no other commands.
A recommended/canonical way to add hooks such as running tests before installing.
I have tried reading the distutils documentation, but it's pretty sparse on details – the distutils.command[.foo] modules are completely undocumented.
For the first point I can check sys.argv like mentioned in this question, but that doesn't work when multiple commands are run, like:
python setup.py sdist bdist upload
so it isn't applicable in general.
You can override the command instead:
from distutils.command.install import install
from distutils.core import setup
def run_file(path):
with open(path, 'r') as f:
exec(f.read())
class myinstall(install): # subclass distutils's install command
def finalize_options(self): # called after option parsing
# call base class function
install.finalize_options(self)
# super won't work because distutils under Python 2 uses old-style classes
# ignore a module
self.distribution.py_modules.remove('mymodule')
def run(self): # called to run a command
# run tests first
run_file('path/to/test.py')
# ^ remember to make sure the module is in sys.path
# run the real commands
install.run(self)
setup(
name='abc',
py_modules=['mymodule'],
cmdclass={'install': myinstall}
# ^ override the install command
)

How to check if all modules imported by a Python script are installed without running the script?

I would like to check if all modules imported by a script are installed before I actually run the script, because the script is quite complex and is usually running for many hours. Also, it may import different modules depending on the options passed to it, so just running it once may not check everything. So, I wouldn't like to run this script on a new system for few hours only to see it failing before completion because of a missing module.
Apparently, pyflakes and pychecker are not helpful here, correct me if I'm wrong. I can do something like this:
$ python -c "$(cat *.py|grep import|sed 's/^\s\+//g'|tr '\n' ';')"
but it's not very robust, it will break if the word 'import' appears in a string, for example.
So, how can I do this task properly?
You could use ModuleFinder from the standard lib modulefinder
Using the example from the docs
from modulefinder import ModuleFinder
finder = ModuleFinder()
finder.run_script('bacon.py')
print 'Loaded modules:'
for name, mod in finder.modules.iteritems():
print '%s: ' % name,
print ','.join(mod.globalnames.keys()[:3])
print '-'*50
print 'Modules not imported:'
print '\n'.join(finder.badmodules.iterkeys())
You could write a test.py that just contains all the possible imports for example:
import these
import are
import some
import modules
Run it and if there are any problems python will let you know

Categories

Resources