Minio minio.error.SignatureDoesNotMatch thrown with try-except - python

I am using the python package for the minio server. I have the following piece of code that is used for a login:
from minio.error import [...], SignatureDoesNotMatch, [...]
def login(self):
try:
self.user = Minio(MINIO_CONFIG['MINIO_ENDPOINT'],
access_key=self.username,
secret_key=self.password,
secure=MINIO_CONFIG['MINIO_SECURE'])
return {"msg":"User is now logged in", "status": "OK"}
except SignatureDoesNotMatch as err:
return {"msg": err.message, "status":"F"}
except ResponseError as err:
return {'msg': err.message, 'status': "F"}
except InvalidAccessKeyId as err:
return {"msg": err.message, "status":"F"}
except InvalidArgument as err:
return {"msg": err.message, "status":"F"}
except InvalidArgumentError as err:
return {"msg": err.message, "status":"F"}
The issue I am facing is that even though I do have in the try-except the SignatureDoesNotMatch in case the credentials are not correct, it does not return me the msg it should but it throws an minio.error.SignatureDoesNotMatch instead. Why does that happen?
The error I get:
minio.error.SignatureDoesNotMatch: SignatureDoesNotMatch: message: The request signature we calculated does not match the signature you provided.

This seems fine, looking at the code, this will never run into an error on it's own, regardless of the credentials provided. It will only run into an error when it makes an API call, or when you invoke methods like list_buckets, list_objects etc using this self.user instance, from outside this block.
I think what you're trying to do is-- invoking methods like list_buckets etc from outside this encapsulation-- somewhere else not this part of the code, and then they produce this error and propagate them to the console. You cannot encapsulate the MinIO instance within try-catch and catch errors while you make use of stuff like self.user.list_buckets() from outside this try-catch block.

Related

How to change Prometheus error message if token is invalid?

I have a python file called main.py and I am trying to make a Prometheus connection with a specific token. However, if the token is expired, instead of the error message printing out prometheus_api_client.exceptions.PrometheusApiClientException, how can I get the error message to print our like status_code: 500, reason: Invalid token using a try and except block.
Code:
#token="V0aksn-as9ckcnblqc6bi3ans9cj1nsk" #example, expired token
token ="c0ams7bnskd9dk1ndk7aKNYTVOVRBajs" #example, valid token
pc = PrometheusConnect(url = url, headers={"Authorization": "bearer {}".format(token)}, disable_ssl=True)
try:
#Not entirely sure what to put here and the except block
except:
I've tested out a couple code in the try and except blocks and could not get rid of the long error from Prometheus. Any suggestions?
How about putting your pc variable in try and PrometheusApiClientException for the exception. If that doesn't work, go to the source file and use whatever exception developers used while making authorization.
This is how you catch that exception in a try/except block
try:
# Interact with prometheus here
pass
except prometheus_api_client.exceptions.PrometheusApiClientException as e:
print('status_code: 500, reason: Invalid token')

How does python function return statement work?

I am new to python but I have experience with other languages like nodejs, java etc. I have a function in python defined like:
from flask import abort
def delete_contact(contact_id, api_key=None): # noqa: E501
print('delete contact ', contact_id)
session = Session()
try:
query = session.query(DBContact).filter(DBContact.id == contact_id)
print('delete count:', query.count())
if query.count() == 0:
print('return 404')
return abort(404, 'Not find record')
contact = query.one()
session.delete(contact)
session.commit()
return 'success'
except Exception as error:
print(error)
finally:
session.close()
print('xxxxx')
return abort(400, 'failed to delete contact ' + contact_id)
When execution this code I can see the output includes both return 404 and xxxxx. I don't understand why xxxxx get printed if the function returns in return abort(404, 'Not find record') already. In other language like java, javascript, if a function returns a value, the rest code should not execute except finally block. But the print('xxxxx') is outside finally block. Why is it executed?
abort(404, 'Not find record') raises a HTTPException, which is caught by your except block.
Therefore the return part of the return abort(404, 'Not find record') statement is never reached and instead of returning python will execute the except block followed by the finally block and then the statements after the try-except-finally statement.
The function then doesn't return either, because the line
return abort(400, 'failed to delete contact ' + contact_id)
raises another HTTPException, which will be propagated through the call stack.
The returns don't do anything.
If you want to propagate the HTTPException, but not other exceptions, you could do something like:
try:
...
except HTTPException:
raise
except Exception as error:
print(error)
finally:
...
...
This will raise the HTTPExceptions thrown by abort, but handle all other exceptions in the second except block, continuing the function afterwards.

RESTful api design: handle exceptions through nested functions (python, flask)

I would like to improve my coding style with a more robust grasp of try, except and raise in designing API, and less verbose code.
I have nested functions, and when one catches an execption, I am passing the exception to the other one and so on.
But like this, I could propagate multiple checks of a same error.
I am referring to:
[Using try vs if in python
for considering cost of try operation.
How would you handle an error only once across nested functions ?
E.g.
I have a function f(key) doing some operations on key; result is
passed to other functions g(), h()
if result comply with
expected data structure, g() .. h() will manipulate and return
updated result
a decorator will return final result or return the
first error that was met, that is pointing out in which method it was raised (f(),g() or h()).
I am doing something like this:
def f(key):
try:
#do something
return {'data' : 'data_structure'}
except:
return {'error': 'there is an error'}
#application.route('/')
def api_f(key):
data = f(k)
try:
# do something on data
return jsonify(data)
except:
return jsonify({'error':'error in key'})
IMO try/except is the best way to go for this use case. Whenever you want to handle an exceptional case, put in a try/except. If you can’t (or don’t want to) handle the exception in some sane way, let it bubble up to be handled further up the stack. Of course there are various reasons to take different approaches (e.g. you don’t really care about an error and can return something else without disrupting normal operation; you expect “exceptional” cases to happen more often than not; etc.), but here try/except seems to make the most sense:
In your example, it’d be best to leave the try/except out of f() unless you want to…
raise a different error (be careful with this, as this will reset your stack trace):
try:
### Do some stuff
except:
raise CustomError('Bad things')
do some error handling (e.g. logging; cleanup; etc.):
try:
### Do some stuff
except:
logger.exception('Bad things')
cleanup()
### Re-raise the same error
raise
Otherwise, just let the error bubble up.
Subsequent functions (e.g. g(); h()) would operate the same way. In your case, you’d probably want to have some jsonify helper function that jsonifies when possible but also handles non-json data:
def handle_json(data):
try:
return json.dumps(data)
except TypeError, e:
logger.exception('Could not decode json from %s: %s', data, e)
# Could also re-raise the same error
raise CustomJSONError('Bad things')
Then, you would have handler(s) further up the stack to handle either the original error or the custom error, ending with a global handler that can handle any error. In my Flask application, I created custom error classes that my global handler is able to parse and do something with. Of course, the global handler is configured to handle unexpected errors as well.
For instance, I might have a base class for all http errors…
### Not to be raised directly; raise sub-class instances instead
class BaseHTTPError(Exception):
def __init__(self, message=None, payload=None):
Exception.__init__(self)
if message is not None:
self.message = message
else:
self.message = self.default_message
self.payload = payload
def to_dict(self):
"""
Call this in the the error handler to serialize the
error for the json-encoded http response body.
"""
payload = dict(self.payload or ())
payload['message'] = self.message
payload['code'] = self.code
return payload
…which is extended for various http errors:
class NotFoundError(BaseHTTPError):
code = 404
default_message = 'Resource not found'
class BadRequestError(BaseHTTPError):
code = 400
default_message = 'Bad Request'
class NotFoundError(BaseHTTPError):
code = 500
default_message = 'Internal Server Error'
### Whatever other http errors you want
And my global handler looks like this (I am using flask_restful, so this gets defined as a method on my extended flask_restful.Api class):
class RestAPI(flask_restful.Api):
def handle_error(self, e):
code = getattr(e, 'code', 500)
message = getattr(e, 'message', 'Internal Server Error')
to_dict = getattr(e, 'to_dict', None)
if code == 500:
logger.exception(e)
if to_dict:
data = to_dict()
else:
data = {'code': code, 'message': message}
return self.make_response(data, code)
With flask_restful, you may also just define your error classes and pass them as a dictionary to the flask_restful.Api constructor, but I prefer the flexibility of defining my own handler that can add payload data dynamically. flask_restful automatically passes any unhandled errors to handle_error. As such, this is the only place I’ve needed to convert the error to json data because that is what flask_restful needs in order to return an https status and payload to the client. Notice that even if the error type is unknown (e.g. to_dict not defined), I can return a sane http status and payload to the client without having had to convert errors lower down the stack.
Again, there are reasons to convert errors to some useful return value at other places in your app, but for the above, try/except works well.

Python class methods, when to return self?

I'm confused as to when to return self inside a class and when to return a value which may or may not possibly be used to check the method ran correctly.
def api_request(self, data):
#api web request code
return response.text
def connect(self):
#login to api, set some vars defined in __init__
return self
def send_message(self, message):
#send msg code
return self
So above theres a few examples. api_request I know having the text response is a must. But with send_message what should I return?
which is then converted to a dict to check a key exists, else raise error).
Should it return True, the response->dict, or self?
Thanks in advance
Since errors tend to be delivered as exceptions and hence success/fail return values are rarely useful, a lot of object-modifier functions wind up with no return value at all—or more precisely, return None, since you can't return nothing-at-all. (Consider some of Python's built-in objects, like list, where append and extend return None, and dict, where dict.update returns None.)
Still, returning self is convenient for chaining method calls, even if some Pythonistas don't like it. See kindall's answer in Should internal class methods returnvalues or just modify instance variables in python? for example.
Edit to add some examples based on comment:
What you "should" return—or raise an exception, in which case, "what exception"—depends on the problem. Do you want send_message() to wait for a response, validate that response, and verify that it was good? If so, do you want it to raise an error if there is no response, the validation fails, or the response was valid but says "message rejected"? If so, do you want different errors for each failure, etc? One reasonable (for some value of reasonable) method is to capture all failures with a "base" exception, and make each "type" of failure a derivative of that:
class ZorgError(Exception): # catch-all "can't talk via the Zorg-brand XML API"
pass
class ZorgRemoteDown(ZorgError): # connect or send failed, or no response/timeout
pass
class ZorgNuts(ZorgError): # remote response incomprehensible
pass
class ZorgDenied(ZorgError): # remote says "permission denied"
pass
# add more if needed
Now some of your functions might look something like this (note, none of this is tested):
def connect(self):
"""connect to server, log in"""
... # do some prep work
addr = self._addr
try:
self._sock.connect(addr)
except socket.error as err:
if err.errno == errno.ECONNREFUSED: # server is down
raise ZorgRemoteDown(addr) # translate that to our Zorg error
# add more special translation here if needed
raise # some other problem, propagate it
... # do other stuff now that we're connected, including trying to log in
response = self._get_response()
if response == 'login denied' # or whatever that looks like
raise ZorgDenied() # maybe say what exactly was denied, maybe not
# all went well, return None by not returning anything
def send_message(self, msg):
"""encode the message in the way the remote likes, send it, and wait for
a response from the remote."""
response = self._send_and_wait(self._encode(msg))
if response == 'ok':
return
if response == 'permission denied':
raise ZorgDenied()
# don't understand what we got back, so say the remote is crazy
raise ZorgNuts(response)
Then you need some "internal" functions like these:
def _send_and_wait(self, raw_xml):
"""send raw XML to server"""
try:
self._sock.sendall(raw_xml)
except socket.error as err:
if err.errno in (errno.EHOSTDOWN, errno.ENETDOWN) # add more if needed
raise ZorgRemoteDown(self._addr)
raise
return self._get_response()
def _get_response(self):
"""wait for a response, which is supposedly XML-encoded"""
... some code here ...
if we_got_a_timeout_while_waiting:
raise ZorgRemoteDown(self._addr)
try:
return some_xml_decoding_stuff(raw_xml)
except SomeXMLDecodeError:
raise ZorgNuts(raw_xml) # or something else suitable for debug
You might choose not to translate socket.errors at all, and not have all your own errors; perhaps you can squeeze your errors into ValueError and KeyError and so on, for instance.
These choices are what programming is all about!
Generally, objects in python are mutable. You therefore do not return self, as the modifications you make in a method are reflected in the object itself.
To use your example:
api = API() # initialise the API
if api.connect(): # perhaps return a bool, indicating that the connection succeeded
api.send_message() # you now know that this API instance is connected, and can send messages

Python: Getting the error message of an exception

In python 2.6.6, how can I capture the error message of an exception.
IE:
response_dict = {} # contains info to response under a django view.
try:
plan.save()
response_dict.update({'plan_id': plan.id})
except IntegrityError, e: #contains my own custom exception raising with custom messages.
response_dict.update({'error': e})
return HttpResponse(json.dumps(response_dict), mimetype="application/json")
This doesnt seem to work. I get:
IntegrityError('Conflicts are not allowed.',) is not JSON serializable
Pass it through str() first.
response_dict.update({'error': str(e)})
Also note that certain exception classes may have specific attributes that give the exact error.
Everything about str is correct, yet another answer: an Exception instance has message attribute, and you may want to use it (if your customized IntegrityError doesn't do something special):
except IntegrityError, e: #contains my own custom exception raising with custom messages.
response_dict.update({'error': e.message})
You should use unicode instead of string if you are going to translate your application.
BTW, Im case you're using json because of an Ajax request, I suggest you to send errors back with HttpResponseServerError rather than HttpResponse:
from django.http import HttpResponse, HttpResponseServerError
response_dict = {} # contains info to response under a django view.
try:
plan.save()
response_dict.update({'plan_id': plan.id})
except IntegrityError, e: #contains my own custom exception raising with custom messages.
return HttpResponseServerError(unicode(e))
return HttpResponse(json.dumps(response_dict), mimetype="application/json")
and then manage errors in your Ajax procedure.
If you wish I can post some sample code.
Suppose you raise error like this
raise someError("some error message")
and 'e' is catched error instance
str(e) returns:
[ErrorDetail(string='some error message', code='invalid')]
but if you want "some error message" only
e.detail
will gives you that (actually gives you a list of str which includes "some error message")
This works for me:
def getExceptionMessageFromResponse( oResponse ):
#
'''
exception message is burried in the response object,
here is my struggle to get it out
'''
#
l = oResponse.__dict__['context']
#
oLast = l[-1]
#
dLast = oLast.dicts[-1]
#
return dLast.get( 'exception' )

Categories