Pytest Command Line: passing in string to use as host - python

So what I am trying to do is write a pytest script that allows me to pass in a string as an argument. I can't for the life of me figure out how to get the argument to pass in as a whole string instead of having it be treated as separate characters. I have tried a bunch of options but this is the closest I have gotten. I feel like I'm just missing some small logic that will make this actually work.
conftest.py
def pytest_addoption(parser):
parser.addoption("--host", dest="host", type="string",
action="store", default="john", help="Enter an
endpoint for TransactionDS")
def pytest_generate_tests(metafunc):
if 'host' in metafunc.fixturenames:
metafunc.parametrize("host", metafunc.config.getoption('host'))
test_args.py
def test_host(host):
global endpoint
endpoint = host
if (endpoint == '90.90.90.90'):
print(endpoint)
else:
print(endpoint)
command line
pytest -q --host "Chris" test_args.py -s --html=report.html
output
IP Address from Hello World 1 -
C
.h
.r
.i
.s
.

Fixture value supposed to be a list of values to iterate through.
So if you use string it will treat each char as a value and run the test the len(host) number of time
So just use
def pytest_generate_tests(metafunc):
if 'host' in metafunc.fixturenames:
metafunc.parametrize("host", [metafunc.config.getoption('host')])
py.test -q --host "Chris" test_args.py -s
Chris
.
1 passed in 0.00 seconds
I removed from your command line parameter html that is not described in your conftest.py

Related

pytest customize sys.argv parsing

I'm trying to customize pytest command line option parsing behavior to accept two groups of paramaters separated by --.
parameters that come before the separator as passed to pytest as is.
The parameters after the separator are to be stored in fixture for later use
For example in the following invocation,
pytest -s mytest.py -- --myarg 10
-s option is passed to pytest and the string --myarg 10 is stored as test_args fixture in mytest.py.
I have tried to customize pytest_load_initial_conftests to modify args.
% ls
args_plugin.py test_my_arg.py
% cat args_plugin.py
import pytest
from typing import List
_test_args: List[str] = []
def _setup_args(args: List[str]):
sep = "--"
if sep in args:
idx = args.index("--")
global _test_args
_test_args = args[idx + 1 :]
args = args[:idx]
return args
#pytest.hookimpl(hookwrapper=True)
def pytest_load_initial_conftests(early_config, parser, args: List[str]):
args = _setup_args(args)
print(_test_args, args)
outcome = yield
#pytest.fixture
def cli_args() -> List[str]:
return _test_args
% cat test_my_args.py
import pytest
def test_cli_args(cli_args):
print(cli_args)
Running it, I get following error
% PYTHONPATH=. pytest -p args_plugin -s . -- --myarg 10
['--myarg', '10'] ['-p', 'args_plugin', '-s', '.']
======= test session starts =======
collected 0 items
======= no tests ran in 0.00s =======
ERROR: file or directory not found: --myarg
Any alternative approaches to the problem are also welcome.
If I understand your code right, I believe all you need is to add [:] to your args = expression in hook function.
Like this:
#pytest.hookimpl(hookwrapper=True)
def pytest_load_initial_conftests(early_config, parser, args: List[str]):
args[:] = _setup_args(args)
print(_test_args, args)
outcome = yield
It will overwrite args variable instead of defining new one (in local function scope)

Python argparse cut half of argument

I'm trying to enter sha512 hash as an argument but argparse just cut off half of it for no reason. When I enter Unix hash( MiqkFWCm1fNJI ) it works as it supposed. I tried to search for something like this but didn't find anything.
My code for command line arguments looks like this :
def check_args():
parse = argparse.ArgumentParser()
parse.add_argument('-p', '--password', type=str, action='store', help='enter your hashed password: -p your_hash')
parse.add_argument('-w', '--wordlist', help='add your wordlist: -w wordlist')
parse.add_argument('-f', '--file', help='file with hashes: -f your_hashes')
args_list = parse.parse_args()
return args_list
Part of code where it's used:
c_arg = check_args()
psw = c_arg.password
wordlist = c_arg.wordlist
file = c_arg.file
print(psw)
so when I run script
python crack.py -p $6$krVh8s..$ttQmt30au3s9wHywp/KGdFKGe1WoEK4xpFJupMA.I06/tdv1//4x7e1gSU2e2Qu/1kQ0rfqXRxghfBX0Io1BJ.
I get this output:
../KGdFKGe1WoEK4xpFJupMA.I06/tdv1//4x7e1gSU2e2Qu/1kQ0rfqXRxghfBX0Io1BJ.
which should be:
$6$krVh8s..$ttQmt30au3s9wHywp/KGdFKGe1WoEK4xpFJupMA.I06/tdv1//4x7e1gSU2e2Qu/1kQ0rfqXRxghfBX0Io1BJ.
if I run same script with argument like this it works as supposed:
python crack.py -p MiqkFWCm1fNJI
Output:
MiqkFWCm1fNJI
What can be wrong about this and how can I make argparse read this kind of strings?
Your problem has nothing to do with argparse or Python.
$6 and the like are references to [non-existent] environment variables in Unix/Linux. Their values are '' (empty strings). Enclose your entire hash in single quotation marks to protect the data from being interpreted by the shell: '$6$krVh8s..$ttQmt30au3s9wHywp/...'.

argparse function arguments

I am trying to use argparse to create my script with parameters but I am not being able to.
The name of my script is pipeline and it has some options arguments like -b, -c, -i and -r.
If you call the script ./pipeline -b should give an error asking for a git repository path but I am not being able to do this.
from git import Repo
import os
import sys
import subprocess
import argparse
class Ci:
def build(self,args):
cloned_repo = Repo.clone_from(args)
print("clonning repository " + args)
cloned_repo
dir = git.split('/')(-1)
if os.path.isdir(dir):
print("repository cloned successfully")
else:
print("error to clone repository")
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-b','-build',action='store_true', help='execute mvn clean install')
parser.add_argument('-c','-compress',action='store_true',help='zip a directory recursively')
parser.add_argument('-i','-integration',action='store_true',help='execute mvn verify')
parser.add_argument('-r','-release',action='store_true',help='execute build,integration and compress respectively')
args = parser.parse_args()
if args.b:
a = Ci()
a.build()
if len(sys.argv) < 2:
parser.print_help()
sys.exit(1)
I can't make this sub-parameter work and I can't find a way to pass this parameter to my build function.
e.g:
./pipeline -b
Output: error missins git path
./pipeline -b https://git/repo
Output: clonning repo
and the string "https://git/repo" has to be passed as the argument to my build function:
How can I make it work?
first a note about convention: usually the longer option name is preceded by two hyphens like this '--build'
second, 'store_true' is the action you perform with '-b', which means argparse doesnt expect an argument after it, it just sets the args.build variable to True (and if the argument wasn't there it would set it to False)
try removing the action='store_true' and then it will default to storing the next value it finds in the argument list into args.build
Reducing your code to:
import argparse
class Ci:
def build(self,args):
print("clonning repository " + args)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-b','-build',action='store_true', help='execute mvn clean install')
parser.add_argument('-c','-compress',action='store_true',help='zip a directory recursively')
parser.add_argument('-i','-integration',action='store_true',help='execute mvn verify')
parser.add_argument('-r','-release',action='store_true',help='execute build,integration and compress respectively')
args = parser.parse_args()
print(args)
if args.b:
a = Ci()
a.build()
I get:
1313:~/mypy$ python3 stack49408644.py -b
Namespace(b=True, c=False, i=False, r=False)
Traceback (most recent call last):
File "stack49408644.py", line 22, in <module>
a.build()
TypeError: build() missing 1 required positional argument: 'args'
The parser runs fine, seeing args.b to True. But the call to build is wrong. It does not match the method's definition.
Providing a 'directory' doesn't help either, because -b is True/False
1313:~/mypy$ python3 stack49408644.py -b foo
usage: stack49408644.py [-h] [-b] [-c] [-i] [-r]
stack49408644.py: error: unrecognized arguments: foo
You need to either change -b to take an value, or add another argument that takes a value.
#AntiMatterDynamite showed how to change -b. Instead let's add:
parser.add_argument('adir', help='a directory for build')
and change the build call
a.build(args.adir)
Now the value is passed on to the method:
1322:~/mypy$ python3 stack49408644.py -b
usage: stack49408644.py [-h] [-b] [-c] [-i] [-r] adir
stack49408644.py: error: the following arguments are required: adir
1322:~/mypy$ python3 stack49408644.py -b foo
Namespace(adir='foo', b=True, c=False, i=False, r=False)
clonning repository foo
Instead redefining -b:
parser.add_argument('-b','-build', help='execute mvn clean install')
if args.b is not None:
a = Ci()
a.build(args.b)
test runs:
1322:~/mypy$ python3 stack49408644.py -b
usage: stack49408644.py [-h] [-b B] [-c] [-i] [-r]
stack49408644.py: error: argument -b/-build: expected one argument
1324:~/mypy$ python3 stack49408644.py -b foo
Namespace(b='foo', c=False, i=False, r=False)
clonning repository foo
So your parser needs to accept a value. And you need to pass that value on to your code. You seem to have read enough of the argparse docs to get things like print_help and store_true, but missed the simpler use of store (default) or positional. Were you trying to do something more sophisticated?
I agree with #hpaulj (why isn't an accepted answer?). I guess you found your problem, i.e., store_true does not take argument, then follow hpaulj indications.
In addition, I opened the question because of its title, I was expecting something different such as the following. I wanted to find a way to pass the argparse arguments to a function and possibly modify them with the function arguments. Here is the solution I wrote in case others come looking for this. It may need to be adjusted to account for positional arguments, I also highlight the possible use of vars(args) to get a dictionary from the argparse arguments to compare dict-to-dict with the args_dict:
def get_options(args_dict: dict):
""" get options from command-line,
update with function args_dict if needed """
args = get_cmd() # this is the function taking cmd-line arguments
for key, val in args_dict.items():
if not hasattr(args, key):
raise AttributeError('unrecognized option: ', key)
else:
setattr(args, key, val)
return(args)

Run a method only if a tag or keyword is given using Python

I'm writing Selenium tests in Python and want to be able to tag certain sections of the script so that I can skip those sections if I specify it from the cmd line. What I'm hoping for is something like this:
#run
def somemethod():
print "this method should not run if the #run tag is False"
what I'd like to do from there is something like:
python script_name.py #run=False
or whatever format this should be in. This should make it skip that method.
This is something that can obviously be done with an if statement, like so:
if not run:
somemethod()
or put the if statement inside of the method. However, I want to be able to write a tag from the command line, rather than having a ton of if-statements everywhere. Does something like this exist, or is it functionality that I'd have to try to create?
What I'm using:
Python 2.7.9
Selenium 2.44
Windows 7 and Linux
You could create a custom decorator and use the argparse module to check for the existance of a command line switch. Something like this:
import argparse
from functools import wraps
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--dont-run-test', dest='dont_run_test', action='store_true', default=False)
arguments = parser.parse_args()
def run(f):
#wraps(f)
def wrapper(*args, **kwargs):
if not arguments.dont_run_test:
return f(*args, **kwargs)
else: # To demonstrate it works
print 'Skipping test %s' % f.__name__
return wrapper
#run
def my_test():
print 'This should run only if the -d command line flag is not specified'
my_test()
Example output:
>python2 annotate.py
This should run only if the -d command line flag is not specified
>python2 annotate.py -d
Skipping test my_test

How do I add cli arguments to py.test?

Im trying to have interchangeable config files and I'm using py.test to send the testing suite to the cloud.
The following works when I run them locally using python main.py --site site1 in the terminal.
I'm trying to figure out how I can add cli arguments so that it will work with py.test
I have 3 files. main, config, and site1_config
main.py
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='CLI tests for an environment')
parser.add_argument('--site', nargs='?', help='the site to use for the config')
parser.add_argument('unittest_args', nargs='*')
#Get our property
args = parser.parse_args()
if args.site:
config.localizeConfig(args.site)
sys.argv[1:] = args.unittest_args
unittest.main(verbosity = 2)
config.py
def localizeConfig(site):
localizedConfig = __import__(site+'_config');
# localizedConfig = __import__(site);
#print dir(localizedConfig)
props = filter(lambda a: not a.startswith('__'), dir(localizedConfig))
#Iterate over each property and set it on the config
for prop in props:
if prop != 'os' and prop != 'sys' and prop != 'webdriver':
globals()[prop] = getattr(localizedConfig, prop)
host_url = www.google.com
site1_config.py
host_url = www.yahoo.com
Im trying to set a flag so that when py.test -n6 --boxed main.py site1
is run, the site1_config.py will copy over its contents into config.py
I'm not sure how I can get this to work with py.test
usage: py.test [options] [file_or_dir] [file_or_dir] [...]
py.test: error: unrecognized arguments:
I don't really get what you are trying to do, but in order to add CLI arguments to py.test check:
http://pytest.org/latest/example/simple.html:
# content of conftest.py
import pytest
def pytest_addoption(parser):
parser.addoption("--cmdopt", action="store", default="type1",
help="my option: type1 or type2")
The equivalent of your unittest.main(verbosity = 2) is pytest.main(['-v'])
Things to note:
In pytest, I'm not sure verbosity level is selectable
Some of the references on pytest.main(input) don't specify that the input has to be a list, but as of today it must be.
https://docs.pytest.org/en/latest/usage.html

Categories

Resources