python __init__() takes 1 positional argument but 2 were given newbie - python

I have an attribute error in a little spotify-api program i am trying to run
my run file contains the following
import os
from spotify_client import AddSongs
def run():
spotify_client = AddSongs('spotify_token')
random_tracks = spotify_client.get_random_tracks()
track_ids = [track['id'] for track in random_tracks]
was_added_to_queue = spotify_client.add_tracks_to_queue()
if was_added_to_queue:
for track in random_tracks:
print(f"Added {track['name']} to your library")
if __name__ == '__main__':
run()
then in spotify_client is the following class
class AddSongs(object):
def __init__(self,):
self.spotify_token = ""
self.uri = ""
def get_random_tracks(self):
wildcard = f'%{random.choice(string.ascii_lowercase)}%'
query = urllib.parse.quote(wildcard)
offset = random.randint(0, 2000)
url = f"https://api.spotify.com/v1/search?q={query}&offset={offset}&type=track&limit=1"
response = requests.get(
url,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {self.spotify_token}"
}
)
response_json = response.json()
print(response)
tracks = [
track for track in response_json['tracks']['items']
]
self.uri = response_json["tracks"]["items"][0]["uri"]
print(f'Found {len(tracks)} tracks to add to your queue')
return tracks
return self.uri
def add_tracks_to_queue(self,):
print('adding to queue...')
url =f"https://api.spotify.com/v1/me/player/queue?uri={self.uri}"
response = requests.post(
url,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {self.spotify_token}"
}
)
print(f"Added {track['name']} to your queue")
return response.ok
def callrefresh(self):
print("Refreshing token")
refreshCaller = Refresh()
self.spotify_token = refreshCaller.refresh()
self.get_random_tracks()
a = AddSongs()
a. callrefresh()
As you can see it runs the code fine up untill add_tracks_to_queue
this is giving me the following traceback
Refreshing token
<Response [200]>
Found 1 tracks to add to your queue
Traceback (most recent call last):
File "/Users/shakabediako/Documents/free_streams/run.py", line 18, in <module>
run()
File "/Users/shakabediako/Documents/free_streams/run.py", line 7, in run
spotify_client = AddSongs('spotify_token')
TypeError: __init__() takes 1 positional argument but 2 were given
>>>
I know there are multiple threads about this error but after reading most of them i haven't been able to understand the concept or find the answer.
I think it has something to do with me calling the function from another file but i do not understand why this creates another "positional argument"
I know this because if i just run the spotify_client file i get the following response
Refreshing token
<Response [200]>
Found 1 tracks to add to your queue
>>>
which are just my print values up until def add_tracks_to_queue (which i also don't understand why it is not running)
I really hope someone can help me with this
Thanks in advance

Your AddSongs class doesn't accept any variables as input (also there's a stray comma in the __init__ which doesn't seem to serve any purpose):
class AddSongs(object):
def __init__(self,):
Yet you're calling it as if it does accept a variable:
spotify_client = AddSongs('spotify_token')
The self parameter has to be in there, but if you want to accept any other variables, you need to actually define them. The solution could therefore be to add a token parameter:
class AddSongs(object):
def __init__(self, token=""): # defaults to an empty string if token is not passed in
self.spotify_token = token
That way, if you call AddSongs('spotify_token'), the class's self.spotify_token will get set to 'spotify_token'.

Related

Reuse methods from locust in different tests

I currently have this locust test:
import logging
from locust import HttpUser, TaskSet, task, constant
log = logging.getLogger("rest-api-performance-test")
def get_headers():
headers = {
"accept": "application/json",
"content-type": "application/json",
}
return headers
def headers_token(auth_token):
headers = {
"accept": "application/json",
"content-type": "application/json",
"auth-token": str(auth_token),
}
return headers
class LoginTasks(TaskSet):
def post_login(self):
headers = get_headers()
login_response = self.client.post("/api/auth",
json={"key": "cstrong#tconsumer.com", "secret": "cstrong"},
headers=headers, catch_response=False, name="Login")
login_data = login_response.json()
auth_token_value = login_data["results"][0]["auth-token"]
return auth_token_value
class UserTasks(UserTasks):
#task
def test_get_list_of_workers(self):
auth_token = self.post_login()
try:
with self.client.get("/api/client/workers",
headers=headers_token(auth_token), catch_response=True,
name="Get Worker Lists") as request_response:
if request_response.status_code == 200:
assert (
'"label": "Salena Mead S"' in request_response.text
)
request_response.success()
log.info("API call resulted in success.")
else:
request_response.failure(request_response.text)
log.error("API call resulted in failed.")
except Exception as e:
log.error(f"Exception occurred! details are {e}")
class WebsiteUser(HttpUser):
host = "https://test.com"
wait_time = constant(1)
tasks = [UserTasks]
the tests runs as expected but post_login is required by multiple tests since is the one who generates the authentication token used by most of the APIs that I'm testing, is there a way to avoid use inheritance from class LoginTasks and find a better solution? The reason I want to avoid it is post_login is not the only method that is going be used many times so I don't want to use multiple inheritance on my UserTasks class.
Any help is appreciated.
Move the function out of the class and pass in the client you want it to use.
def post_login(client):
headers = get_headers()
login_response = client.post("/api/auth",
…
You can then call it when you need it the same way you call get_headers().
auth_token = post_login(self.client)

Mocking variable and replacing it with object

I'd like to test this piece of code:
modify: UserModifyPort = _ports_.user_modify_port
#_app_.route(f"/user", methods=["POST"])
#headers_check({"Accept": "application/json", "Content-Type": "application/json"})
def create_user():
body_json = request.get_json()
body = UserCreateRequest(body_json["username"], body_json["password"])
cmd = UserCreateCmd(body.username, body.password)
# modify usage
user_id = modify.create_user(cmd)
response = UserCreateResponse(user_id)
return response.to_dict(), 201
In this test I need to mock a global variable modify and replace it with object. I've been trying to do this like that:
# TEST
#mock.patch("application.user.user_rest_adapter.modify")
def test_create_user_should_create(modify_mock, db_engine, client, user_config):
modify_mock.return_value = DatabaseUserModifyAdapter(db_engine, user_config)
response = client.post("/user", headers={"Accept": "application/json", "Content-Type": "application/json"},
json={"username": "GALJO", "password": "qwerty123"})
But it isn't executing modify.create_user() function, it just returns some weird object:
<MagicMock name='modify.create_user()' id='140375141136512'>
How can I make this function work?
I solved this issue with sort of workaround. Instead of mocking entire object I've mocked just function that I use. There is no need to use another function, because it is tested in other tests so I replaced it with constant value. I've only checked if given args are correct, everything else is other test task.
#mock.patch("application.user.user_rest_adapter.modify.create_user")
def test_create_user_should_create(create_user_mock, client):
# given
user_id = "a20d7a48-7235-489b-8552-5a081d069078"
create_user_mock.return_value = UUID(user_id)
# when
response = client.post("/user", headers={"Accept": "application/json", "Content-Type": "application/json"},
json={"username": "GALJO", "password": "qwerty123"})
# then
args = create_user_mock.call_args.args
assert args[0].username == "GALJO"
assert args[0].password == "qwerty123"
assert response.json["userID"] == user_id

Response generated while mocking is not correct in python tests

I am trying to unit test some of my functions using mocks in python. Few of them seems to be working as expected but I am trouble with the response of one the test case. Which it not returning the ideal response which it should.
###############motpenrichreceiverinfo.py##################
import requests
def getReceiverInfo(fundId):
print('Inside fetchReceiverInfo',fundId)
response = requests.get("REST URL FOR RECEIVER INFO")
if response.ok:
return response
else:
return None
def getMotpTrade(trade_id):
response = requests.get("REST URL")
if response.ok:
return response
else:
return None
def getMotpCanonical(trade_id):
response = requests.get("REST URL")
if response.ok:
return response
else:
return None
def EnrichTradeWithReceiverInfo(event, context):
#print('Lambda function started..')
trade_id = event['tradeId']
motpTrade = getMotpTrade(trade_id)
canonicalTrade = getMotpCanonical(trade_id)
fundId = motpTrade['Account']
#print(fundId)
data = getReceiverInfo(fundId)
print(data)
return data
##########################test_motptrade.py##############################
# Standard library imports
from unittest.mock import Mock, patch
# Third-party imports...
from nose.tools import assert_true
from nose.tools import assert_is_not_none, assert_list_equal, assert_dict_equal
# Local imports
from motpenrichreceiverinfo import getMotpTrade, getReceiverInfo, EnrichTradeWithReceiverInfo
#patch('motpenrichreceiverinfo.requests.get')
def test_motptraderequest_response(mock_get):
motpTrade = [{
"motpTrade":"motpTrade"
}]
# Configure the mock to return a response with an OK status code.
mock_get.return_value.ok = True
mock_get.return_value.json.return_value = motpTrade
# Send a request to the API server and store the response.
response = getMotpTrade('tradeId')
# If the request is sent successfully, then I expect a response to be returned.
assert_list_equal(response.json(), motpTrade)
#patch('motpenrichreceiverinfo.requests.get')
def test_getReceiverInfo_respose_ok(mock_get):
receiverInfo = [{
"reciever":"reciever"
}]
# Configure the mock to return a response with an OK status code.
mock_get.return_value.ok = True
mock_get.return_value.json.return_value = receiverInfo
# Send a request to the API server and store the response.
response = getReceiverInfo("1110")
# If the request is sent successfully, then I expect a response to be returned.
assert_list_equal(response.json(), receiverInfo)
#patch('motpenrichreceiverinfo.getMotpTrade')
#patch('motpenrichreceiverinfo.getMotpCanonical')
#patch('motpenrichreceiverinfo.getReceiverInfo')
def test_EnrichTradeWithReceiverInfo_ok(mock_get,mock_canonical,mock_receiverinfo):
motpTrade = [{
"motpTrade":"motpTrade"
}]
receiverInfo = [{
"reciever":"reciever"
}]
event = {"tradeId":"123456"}
# Configure the mock to return a response with an OK status code.
mock_get.return_value = Mock(ok=True)
mock_get.return_value.json.return_value = motpTrade
mock_canonical.return_value.ok = True
mock_canonical.return_value.json.return_value = [{}]
mock_receiverinfo.return_value.ok = True
mock_receiverinfo.return_value.json.return_value = receiverInfo
data = EnrichTradeWithReceiverInfo(event,"")
assert_true(mock_get.called)
assert_true(mock_receiverinfo.called)
assert_list_equal(data.json(),receiverInfo)
Here my first two cases are working as expected. But my last test case(test_EnrichTradeWithReceiverInfo_ok) is somehow not working. Ideally it should have response equal to receiverInfo object.But when I run it gives below error. It would be really helpful someone can help me understand what I am doing wrong here.
(venv) C:\Development\motplambdas>nosetests -v test_motptrade.py
test_motptrade.test_EnrichTradeWithReceiverInfo_ok ... FAIL
test_motptrade.test_getReceiverInfo_respose_ok ... ok
test_motptrade.test_motptraderequest_response ... ok
======================================================================
FAIL: test_motptrade.test_EnrichTradeWithReceiverInfo_ok
----------------------------------------------------------------------
Traceback (most recent call last):
File "c:\development\motplambdas\venv\lib\site-packages\nose\case.py", line 198, in runTest
self.test(*self.arg)
File "c:\program files\python38\lib\unittest\mock.py", line 1325, in patched
return func(*newargs, **newkeywargs)
File "C:\Development\motplambdas\test_motptrade.py", line 69, in test_EnrichTradeWithReceiverInfo_ok
assert_list_equal(data.json(),receiverInfo)
AssertionError: Lists differ: [{'motpTrade': 'motpTrade'}] != [{'reciever': 'reciever'}]
First differing element 0:
{'motpTrade': 'motpTrade'}
{'reciever': 'reciever'}
- [{'motpTrade': 'motpTrade'}]
+ [{'reciever': 'reciever'}]
----------------------------------------------------------------------
Ran 3 tests in 0.011s
FAILED (failures=1)
The issue is the order of which you are passing your Mock objects into the function call.
#patch('motpenrichreceiverinfo.getMotpTrade')
#patch('motpenrichreceiverinfo.getMotpCanonical')
#patch('motpenrichreceiverinfo.getReceiverInfo')
def test_EnrichTradeWithReceiverInfo_ok(mock_get,mock_canonical,mock_receiverinfo)
Mock objects are passed from the bottom up, meaning #patch('motpenrichreceiverinfo.getReceiverInfo') is the first Mock passed in to the function call, not the last as you have it listed. Due to this you end up setting getReceiverInfo to return the wrong value. The solution is to switch the function call to look like this:
def test_EnrichTradeWithReceiverInfo_ok(mock_receiverinfo, mock_canonical, mock_get)
You can read more about this here where it explains how nesting decorators works.
Note that the decorators are applied from the bottom upwards. This is the standard way that Python applies decorators. The order of the created mocks passed into your test function matches this order.

Weird Python error

This error: cancel_agreement() missing 1 required positional argument: 'agreement_id'
appeared while executing this method:
def force_cancel(self):
api = model_from_ref(self.processor.api)
api.cancel_agreement(self.subscription_reference)
# transaction.cancel_subscription() # runs in the callback
Here is cancel_agreement() method:
def cancel_agreement(self, agreement_id, is_upgrade=False):
note = _("Upgrading billing plan") if is_upgrade else _("Canceling a service")
r = self.session.post(self.server + '/v1/payments/billing-agreements/%s/cancel' % agreement_id,
data='{"note": "%s"}' % note,
headers={'content-type': 'application/json'})
if r.status_code != requests.codes.ok:
raise RuntimeError(_("Cannot cancel a billing agreement at PayPal. Please contact support."))
I don't understand why the error happens: It is calling a two-argument function (api and self.subscription_reference) and its definition is also two required arguments (self and agreement_id).
Sadly I can't show the entire code, because my business partner is against releasing it open source.
It should be:
def force_cancel(self):
klass = model_from_ref(self.processor.api)
api = klass()
api.cancel_agreement(self.subscription_reference)

Unexpected type-error python

I am trying to create a client used to mainly test out the responses of a server asynchronously. I have created a function that basically waits for the next response from the server, if a requestId is provided when this function is called it will look for the next response with the requestId provided. Here is the function:
def getNextResponse(self, requestId = None):
logger = logging.getLogger(__name__)
self.acknowledge += 1
logger.info("requestId ack for this response: {}".format(requestId))
while(not self.response):
pass
self.acknowledge -= 1
logger.info("requestId unset for this response: {}".format(requestId))
message = json.loads(self.messagesList[len(self.messagesList)-1])
if(requestId != None):
while(requestId != message['body']['requestId']):
self.acknowledge += 1
while(not self.response):
pass
self.acknowledge -= 1
message = self.messagesList[len(self.messagesList)-1]
self.startMonitor -= 1
return message['body']
I also have helper functions for each command which can be sent to the engine below is one of said helper function for a ping command:
def ping(self, sessionId = None, requestId = None, version="1.0"):
result = {
"method": "Ping"
}
if(None != version):
result['version'] = version
if(None != sessionId):
result['sessionId'] = sessionId
if(None != requestId):
result['requestId'] = requestId
logger = logging.getLogger(__name__)
logger.info("Message Sent: " + json.dumps(result, indent=4))
self.startMonitor += 1
self.ws.send(json.dumps(result))
message = self.getNextResponse(requestId = requestId)
return message
It basically sets up a json object which contains all the parameters that the server expects and then sends the entire json message to the server. After it has been sent i call getNextResponse to await a response from the server. The requestId is set to None by default, so if no requestId is provided, it will just look for the very next response returned by the server. Since this can be quite inconsistent because of other asynchronous commands, one can provided a unique requestId for the command so that the response from the server will also contain this requestId thus making each response unique.
In my test case I am generating a random requestId by using:
def genRequestId(self):
x = random.randint(10000000, 99999999)
print x
reqId = str(x)+"-97a2-11e6-9346-fde5d2234523"
return reqId
The problem that I encountered is that sometimes (seems to be random), when I call ping in one of my test cases, i get this error:
message = self.getNextResponse(requestId = requestId)
TypeError: string indices must be integers, not str
I am quite confused by this error, requestId that I am generating inside ping is supposed to be a string and I am not referencing inside it in any way. I have tried removing the reference to the parameter like so:
message = self.getNextResponse(requestId)
But I am still getting this error. The error doesn't go any deeper inside the getNextResponse function which leads me to believe that it is coming from inside the ping function when I try to call it. Any help would be greatly appreciated!
EDIT: Here is the error
Traceback (most recent call last):
File "ctetest./RegressionTest/WebsocketTest\test_18_RecTimer.py", line 385, in test009_recTimer_Start_withAudio
response = client.endSession(sessionId = sessionId, requestId = requestId_2)
File "ctetest./RegressionTest/WebsocketTest../.././CTESetupClass\WebsocketCl
ient.py", line 528, in endSession
message = self.getNextResponse(requestId)
File "ctetest./RegressionTest/WebsocketTest../.././CTESetupClass\WebsocketCl
ient.py", line 49, in wrapper
raise ret
TypeError: string indices must be integers, not str
you have two statements in your code that look very similar:
message = json.loads(self.messagesList[len(self.messagesList)-1])
and then further down:
message = self.messagesList[len(self.messagesList)-1]
The first will set message to a json object (probably dict) where the second one assigns message to a string, I'm assuming this is not intended and the cause for your error.

Categories