Working in Python 3.8.
I prefer to have one return per function as it makes debugging easier.
Current code which I can live with:
if foo:
return redirect(url_for('what.what'))
else:
return render_template('who.who', form=my_form)
Desired code though:
if foo:
ret_func = redirect
ref_func_args = url_for("what.what")
else:
ret_func = render_template
ret_func_args = ('who.html', form=my_form) # syntax help needed here
return ret_func(ret_func_args) # and probably some syntax help here also
Python understandably doesn't like the ret_func_args = ('who.html', form=my_form) and in particular form=my_form.
render_template is expecting a keyword argument named 'form'.
What is the proper syntax for ret_func_args = ('who.html', form=my_form) and perhaps the ret_func(ret_func_args) line? The ret_func(ret_func_args) does work if foo is true but can not figure out how to pass named parameters when foo is false in this case.
Related
#app.get("/drogaraia")
def scraperaia(urlbase="https://www.drogaraia.com.br/medicamentos",maximodepaginas=10):
listaprincipal= []
pagina=2
contador=1
while pagina<maximodepaginas:
testeurl= ((urlbase)+".html?p="+str(pagina))
page = requests.get(testeurl)
results= BeautifulSoup(page.content,"html.parser")
remedios = results.find_all("div",class_="container")
for remedio in remedios:
try:
link=(remedio.find("a", class_="show-hover"))['href']
preco=remedio.find(class_="price").getText().strip()
titulo=(remedio.find("a", class_="show-hover")).getText()
categoria=urlbase.rsplit('/',1)[-1]
listaremedio=[{'link':link,'preco':preco,'titulo':titulo,'categoria':categoria}]
listaprincipal.extend(listaremedio)
except:
pass
contador=contador+1
pagina=pagina+1
return(listaprincipal)
#app.get("/drogaraia/medicamentos/monitores-e-testes/teste-de-controle-glicemicos")
scraperaia(urlbase="https://www.drogaraia.com.br/medicamentos/monitores-e-testes/teste-de-controle-glicemicos",maximodepaginas=10)
Error message here:
scraperaia(urlbase="https://www.drogaraia.com.br/medicamentos/monitores-e-testes/teste-de-controle-glicemicos",maximodepaginas=10)
^^^^^^^^^^
SyntaxError: invalid syntax
I don't see how it can be wrong syntax. I have tried not assigning the variables inside the scraperaia() function, like so:
urlbase="https://www.drogaraia.com.br/medicamentos/monitores-e-testes/teste-de-controle-glicemicos"
maximodepaginas=10
scraperaia(urlbase,maximodepaginas)
and it still doesnt work.
The last two lines of your provided code are wrong. You need to use def to define a function.
You can define multiple routes bound to the same function. If you would like to know which route was used, you can use the Request object to get the request URL path (see documentation here and here). Working example below:
from fastapi import FastAPI, Request
app = FastAPI()
#app.get("/store")
#app.get("/store/monitors-and-tests")
def main(request: Request, baseurl: str = "https://someurl", maxpages: int = 10):
return {"Called from": request.url.path}
I'm getting missing 1 required positional argument on the code below. I tried different stuffs but no luck. I believe it is a small detail that I'm missing but since I'm a beginner on Python and I'm not being able to fix it myself.
import requests
from flask import Flask, jsonify, request, render_template
import os
app = Flask(__name__)
#app.route('/outages')
def map_status(data):
url = "https://my-api.local.com/data"
response = requests.get(url)
result_data = json.loads(response.text)
if(data['install_status']=='1'):
data['install_status']='Installed'
elif(data['install_status']=='3'):
data['install_status']='Maintenance'
return data
result_data['result']=map(map_status,result_data['result'])
return(list(result_data['result']))
This is the error I'm getting:
[ERR] TypeError: map_status() missing 1 required positional argument: 'data'
If I change the return for print, it works, but on this case I need to use return to get the data.
When you call a function that has arguments, you must specify the value of them.
The correct code would be:
result_data['result'] = map(map_status(insert_data), result_data['result'])
where (insert_data) is the place where you would insert the value of whatever needs to be put there.
If you don't want the argument to be required all the time you can specify an optional argument like so:
def map_status(data=None)
This makes the initial value of data a NoneType. When you want to call the function with the data argument, just do so like you would a normal argument, but with an equal sign, like so:
map_status(data="hello")
You can also just make the optional argument an empty literal:
def map_status(data="")
Parametrized tests in Pytest have the following id format:
<function name>[<param identifier>].
I would like to be able to totally control the name of the Test Case when these are parametrized.
For example, I currently have the following code:
import pytest
list_args = ["a", "b", "c"]
#pytest.fixture(params=list_args)
def prog_arg(request):
yield request.param
def test_001():
# This should not be changed
pass
def test_002(prog_arg):
# This should be test_002_01, test_002_02, ...
print(prog_arg)
ids = [f"test_003_{i+1:02d}" for i in range(len(list_args))]
#pytest.mark.parametrize("arg", list_args, ids=ids)
def test_003(arg):
# This should be test_003_01, test_003_02, ...
print(prog_arg)
When I run (pytest 5.1.3), I have:
test_rename_id.py::test_TC_001 PASSED
test_rename_id.py::test_TC_002[a] PASSED
test_rename_id.py::test_TC_002[b] PASSED
test_rename_id.py::test_TC_002[c] PASSED
test_rename_id.py::test_TC_003[test_003_01] PASSED
test_rename_id.py::test_TC_003[test_003_02] PASSED
test_rename_id.py::test_TC_003[test_003_03] PASSED
What I would like is to have:
test_rename_id.py::test_TC_001 PASSED
test_rename_id.py::test_TC_002_01 PASSED
test_rename_id.py::test_TC_002_02 PASSED
test_rename_id.py::test_TC_002_03 PASSED
test_rename_id.py::test_TC_003_01 PASSED
test_rename_id.py::test_TC_003_02 PASSED
test_rename_id.py::test_TC_003_03 PASSED
Is it possible without too much hacking of the request object (or other modifications that might got broken in future updates of pytest?
Thanks
This is surely possible by rewriting the nodeids of the collected items. In the example below, I rewrite nodeids in a custom impl of the pytest_collection_modifyitems hook. Place the following code into your conftest.py:
# conftest.py
import itertools as it
import re
def grouper(item):
return item.nodeid[:item.nodeid.rfind('[')]
def pytest_collection_modifyitems(items):
for _, group in it.groupby(items, grouper):
for i, item in enumerate(group):
item._nodeid = re.sub(r'\[.*\]', '_{:02d}'.format(i + 1), item.nodeid)
Running your test module from the question now yields:
test_spam.py::test_001 PASSED
test_spam.py::test_002_01 PASSED
test_spam.py::test_002_02 PASSED
test_spam.py::test_002_03 PASSED
test_spam.py::test_003_01 PASSED
test_spam.py::test_003_02 PASSED
test_spam.py::test_003_03 PASSED
As per the docs available in the pytest, I would like to apprise you that the way ids work in the pytest.mark.paramterize is just like the output you mentioned in your question.
The format is:-
filename-testname-idsvalue.
Reference:- https://hackebrot.github.io/pytest-tricks/param_id_func/
In my code release_bundler.py file
class MavenDependenciesPathsBuilderStrategy(PathsBuilderStrategy):
def build_bundler_copy_paths(self, mapping_values):
source = join(getcwd(),'target','dependency',mapping_values[0])
destination = join(getcwd(),'target','generated-resources',mapping_values[1],mapping_values[0])
return [source, destination]
class NestedModulePathsFilterStrategy(FilterStrategy):
def filter_changeset_paths(self, changeset_paths, bundling_map, paths_builder_strategy):
for mapping_key in bundling_map.keys():
if(mapping_key in changeset_paths):
mapping_values = bundling_map.get(mapping_key).values()
copy_paths = paths_builder_strategy.build_bundler_copy_paths(mapping_values)
return copy_paths
If I want to test the filter_changeset_paths method, I'll have to mock both getcwd method inside the build_bundler_copy_paths method or mocking only the latter will do?
I tried mocking the method in my tests release_bundler_test.py, importing classed like this:
from release_bundler import NestedModulePathsFilterStrategy, MavenDependenciesPathsBuilderStrategy
then patch the MavenDependenciesPathsBuilderStrategy class
def mock_build_bundler_copy_paths(self, mapping_values):
return ['/cwd/foo','/cwd/bar']
#mock.patch('release_bundler.MavenDependenciesPathsBuilderStrategy', 'build_bundler_copy_paths', mock_build_bundler_copy_paths)
def test_nested_module_filter_changeset_paths(self):
pc_maps = {'ProcessingComponents/ProcessContainer':['ProcessContainerInstaller-bin.zip','SERVICES/Installer'],'ProcessingComponents/DataGrid':['ProcessContainerInstaller-bin.zip','SERVICES/Installer']}
changed_paths = ['ProcessingComponents/ProcessContainer/ProcessContainerRuntime/main/java/com/suntecgroup/tbms/container/ContainerException.java']
filter_test = NestedModulePathsFilterStrategy()
result = filter_test.filter_changeset_paths(changed_paths,pc_maps, MavenDependenciesPathsBuilderStrategy())
self.assertIsNotNone(result)
self.assertEquals(result[0], '/cwd/foo')
self.assertEquals(result[0], '/cwd/bar')
but I don't think this mock works because self.assertIsNotNone(result) fails
So the questions are:
Am I mocking the right way? can't get my head over it
will mocking on the MavenDependenciesPathsBuilderStrategy method do or I have to mock the os.getcwd inside it's method also?
My bad, my newbie python brains took a while to get a hang of things:
this is how it works well
#mock.patch('release_bundler.MavenDependenciesPathsBuilderStrategy.build_bundler_copy_paths')
def test_filters_pc_from_changeset_paths(self, mock_build_bundler_copy_paths):
pc_maps = {'ProcessingComponents/ProcessContainer':['ProcessContainerInstaller-bin.zip','SERVICES/Installer']}
changed_paths = ['ProcessingComponents/ProcessContainer/ProcessContainerRuntime/main/java/com/suntecgroup/tbms/container/ContainerException.java']
with mock.patch('release_bundler.NestedModulePathsFilterStrategy.do_copy') as mock_do_copy:
mock_do_copy.return_value = ''
filter_test = NestedModulePathsFilterStrategy()
filter_test.filter_changeset_paths(changed_paths,pc_maps, MavenDependenciesPathsBuilderStrategy())
mock_build_bundler_copy_paths.assert_called_with(['ProcessContainerInstaller-bin.zip','SERVICES/Installer'])
mock_do_copy.assert_called()
I might be wrong but I think we cant apply multiple decorators to a method?
I am attempting to build unit tests and have been using mock, However upon using two patch statements, I was not able to set the proper return values.
#patch('pulleffect.lib.google.gcal_helper.validate_and_refresh_creds')
#patch('pulleffect.lib.google.gcal_helper.get_google_creds')
def test_get_calendar_list_for_gcalhelper_without_credentials(self,
mock_get_google_creds,
mock_validate_and_refresh_creds):
mock_validate_and_refresh_creds = "redirect"
mock_get_google_creds = "credentials"
credentials = pulleffect.lib.google.gcal_helper.get_calendar_list("name","widget")
assert b'redirect' in credentials
however the assert fails and instead of the expected string redirect I instead get
<MagicMock name = "validate_and_refresh_creds() id = 14054613955344>
I was wondering what is necessary to have redirect returned instead. I have not encountered this issue when only patching a single method.
I was able to fix the issue of
<MagicMock name = "foo()" id = number>
incorrectly appearing by replacing my earlier code with:
from mock import MagicMock
def test_get_calendar_list_for_gcalhelper_without_credentials(self):
rtn = { "redirect": "/gcal/authenticate"}
pulleffect.lib.google.gcal_helper.validate_and_refresh_creds = MagicMock(name = "sup", return_value = rtn)
pulleffect.lib.google.gcal_helper.get_google_creds = MagicMock(name = "sup2", return_value = "redirect")
credentials = pulleffect.lib.google.gcal_helper.get_calendar_list("name","widget")
assert b'redirect' in credentials
this allowed the return values to be properly set.
mock_get_google_creds and mock_validate_and_refresh_creds created with patch decorator are ordinary mock objects (Mock or MagicMock). Direct assignment is not the correct way to set return values. Use return_value attribute:
mock_validate_and_refresh_creds.return_value = "redirect"
Also you can set it during patching:
patch takes arbitrary keyword arguments. These will be passed to the
Mock (or new_callable) on construction.
#patch('pulleffect.lib.google.gcal_helper.get_google_creds', return_value="redirect")
I recommend you to use this solution. You should move your functions to helper class and instead static methods user class methods, because it's possible to mock class in this way.
class GCallHelper(object):
#classmethond
def validate_and_refresh(cls):
...
return result
def test_get_calendar_list_for_gcalhelper_without_credentials(self):
with patch('pulleffect.lib.google.gcal_helper') as mocked_gcal:
mocked_gcal.return_value.validate_and_refresh_creds.return_value = 'redirect'
mocked_gcal.return_value.get_google_creds.return_value = 'credentials'
credentials = pulleffect.lib.google.gcal_helper.get_calendar_list("name","widget")
assert b'redirect' in credentials
p.s. And you forgot 'return_value' in your example.