How to raise Suds.WebFault from python code? - python

I am trying to raise a Suds.WebFault from python code. The __init__ method\constructor takes three arguments __init__(self, fault, document). The fault has fault.faultcode and fault.detail members\attributes\properties. I could not find out what class fault belongs to no matte what I tried. How do I raise Suds.WebFault type exception from python code?
Thanks in advance.

Not sure what exactly you are asking but you can throw a web fault using:
import suds
try:
client.service.Method(parameter)
except suds.WebFault, e:
print e

WebFault is defined in suds.__init__.py as:
class WebFault(Exception):
def __init__(self, fault, document):
if hasattr(fault, 'faultstring'):
Exception.__init__(self, u"Server raised fault: '%s'" %
fault.faultstring)
self.fault = fault
self.document = document
Therefore to raise a WebFault with a meaningful message you will need to pass an object as the first param with the message. Document can simply be None unless required.
import suds
class Fault(object):
faultstring = 'my error message'
raise suds.WebFault(Fault(), document=None)

WebFault is only meant to be actually raised when a <Fault> element is returned by the web server. So it's probably a bad idea to raise that yourself.
If you still would like to, I would start looking at the code where the framework raises it: https://github.com/unomena/suds/blob/4e90361e13fb3d74915eafc1f3a481400c798e0e/suds/bindings/binding.py#L182 - and work backwards from there.

Related

CherryPy: what is the difference between `error_page.default` vs. `error_page.404` config settings?

Let's say I want to display my own 404 & 500 pages, I've found 2 possibilities so far:
1: Using cherrypy.config.update
def error_page_404(status, message, traceback, version):
return ('Error 404 Page not found')
def error_page_500(status, message, traceback, version):
return ('Error:')
cherrypy.config.update({'error_page.404': error_page_404, 'error_page.500': error_page_500})
Using _cp_config:
from cherrypy import _cperror
def handle_error():
cherrypy.response.status = 500
cherrypy.log("handle_error() called. Alarm!", "WEBAPP")
cherrypy.response.body = ['Sorry, an error occured. The admin has been notified']
error = _cperror.format_exc()
def error_page(status, message, traceback, version):
cherrypy.log("error_page() called. Probably not very important.", "WEBAPP")
return "Sorry, an error occured."
class Root:
_cp_config = {
'error_page.default': error_page,
'request.error_response': handle_error
}
but is there a difference or a suggestion which is preferable to use?
request.error_response allows you to set a handler for processing of some unexpected errors, like your own exceptions raised from HTTP handlers.
The callable that you'll set for this option will receive no arguments at all and you'll have to inspect sys.exc_info() for the details, to find out what happened.
You'll also have to set cherrypy.response.status and cherrypy.response.body by yourself, explicitly in your error handler.
If you want to modify the error response for HTTP error codes (when instances of cherrypy.HTTPError are raised, like raise cherrypy.NotFound), you can use error_page.default (catch-all) or error_page.404 (error-specific) for handling those errors.
error_page options support both file path and callable values. In case of using a file path, the HTML template file can use the following substitution patterns: %(status)s, %(message)s, %(traceback)s, and %(version)s.
If you opt-in to using a function, it'll receive those as arguments (callback(status, message, traceback, version)). The return value of this callable is then used HTTP response payload.
As you can see, these approaches have different implications and different levels of flexibility and usability. Choose whatever works for you. Internally, the default request.error_response uses error_page settings to figure out what to return. So if you redefine request.error_response, it'll not use error_page.* settings unless you explicitly make it do so.
See the docstring with some explanation here.

AdWords RateExceededError

I'm building a helper library to call the AdWords (Google Ads) Keyword Planner API and having trouble catching RateExceededError errors when they come up.
The specific error message that I'm getting is below.
GoogleAdsServerFault: RateExceededError <rateName=RATE_LIMIT, rateKey=null, rateScope=ACCOUNT, retryAfterSeconds=30, errorDetails="Quota check failed: QuotaInfo{quotaGroupId=v2-kwi-webapi-global, userId=global}"> Original AdsAPI trace for debugging [
com.google.ads.api.services.common.error.ApiException: RateExceededError <rateName=RATE_LIMIT, rateKey=null, rateScope=ACCOUNT, retryAfterSeconds=30, errorDetails="Quota check failed: QuotaInfo{quotaGroupId=v2-kwi-webapi-global, userId=global}">
Underlying ApiErrors are:
RateExceededError <rateName=RATE_LIMIT, rateKey=null, rateScope=ACCOUNT, retryAfterSeconds=30>
I'm currently working with the below setup to call the API and catch errors, however exceptions are still being raised occasionally. Is there a better way I should catch these errors and just log the exceptions as warnings?
class AdwordsAPIException(Exception):
pass
def call_adwords_api_client(self, selector):
try:
return _adwords_client.get(selector)
except AdwordsAPIException:
return None
Many thanks in advance!
Well, you have made a custom Exception class which is never raised, to skip all exceptions try this
def call_adwords_api_client(self, selector):
try:
return _adwords_client.get(selector)
except:
return None
Also, api suggests to wait for 30 seconds before trying again. good luck.

Identify a specific exception in python

I have a problem with identifying an exception.
Im writing a scraper that scrapes a lot of different websites, and some errors I want to handle and some I only want to ignore.
I except my exceptions like this:
except Exception as e:
most of the exceptions I can identify like this:
type(e).__name__ == "IOError"
But I have one exception "[Errno 10054] An existing connection was forcibly closed by the remote host"
that has the name "error" which is too vague and Im guessing other errors also have that name. Im guessing I can somehow get the errno number from my exception and thus identify it. But I don't know how.
First, you should not rely on the exception's class name, but on the class itself - two classes from two different modules can have the same value for the __name__ attribute while being different exceptions. So what you want is:
try:
something_that_may_raise()
except IOError as e:
handle_io_error(e)
except SomeOtherError as e:
handle_some_other_error(e)
etc...
Then you have two kind of exceptions: the one that you can actually handle one way or another, and the other ones. If the program is only for your personal use, the best way to handle "the other ones" is usually to not handle them at all - the Python runtime will catch them, display a nice traceback with all relevant informations (so you know what happened and where and can eventually add some handling for this case).
If it's a "public" program and/or if you do have some things to clean up before the program crash, you can add a last "catch all" except clause at the program's top level that will log the error and traceback somewhere so it isn't lost (logging.exception is your friend), clean what has to be cleaned and terminate with a more friendly error message.
There are very few cases where one would really want to just ignore an exception (I mean pretending nothing wrong or unexpected happened and happily continue). At the very least you will want to notify the user one of the actions failed and why - in your case that might be a top-level loop iterating over a set of sites to scrap, with an inner try/except block catching "expected" error cases, ie:
# config:
config = [
# ('url', {params})
('some.site.tld', {"param1" : value1, "param2" : value2}),
('some.other.tld', {"param1" : value1, "answer" : 42}),
# etc
]
def run():
for url, params in config:
try:
results = scrap(url, **params)
except (SomeKnownError, SomeOtherExceptedException) as e:
# things that are to be expected and mostly harmless
#
# you configured your logger so that warnings only
# go to stderr
logger.warning("failed to scrap %s : %s - skipping", url, e)
except (MoreSeriousError, SomethingIWannaKnowAbout) as e:
# things that are more annoying and you want to know
# about but that shouldn't prevent from continuing
# with the remaining sites
#
# you configured your logger so that exceptions goes
# to both stderr and your email.
logger.exception("failed to scrap %s : %s - skipping", url, e)
else:
do_something_with(results)
Then have a top-level handler around the call to run() that takes care of unexpected errors :
def main(argv):
parse_args()
try:
set_up_everything()
run()
return 0
except Exception as e:
logger.exception("oops, something unexpected happened : %s", e)
return 1
finally:
do_some_cleanup()
if __name__ == "__main__":
sys.exit(main(sys.argv))
Note that the logging module has an SMTPHandler - but since mail can easily fail too you'd better still have a reliable log (stderr and tee to a file ?) locally. The logging module takes some time to learn but it really pays off in the long run.

Django model.DoesNotExist exception somehow replaced with an AttributeError

I'm experiencing an odd exception on a Django 1.5 site:
"TypeError: 'exceptions.AttributeError' object is not callable"
Essentially it looks like the model.DoesNotExist exception has been replaced with an AttributeError.
The error is intermittent, but once it happens it seems to 'stick' until I restart the process, which makes me think it might be a case of the model class getting incorrectly set in the course of a particular request, and then persisting.
Bottom of traceback:
File "/opt/mysite/django/apps/profiles/models.py", line 353, in profile_from_cache
profile = self.get(user=user_id)
File "/opt/mysite/.virtualenvs/django/lib/python2.7/site-packages/django/db/models/manager.py", line 143, in get
return self.get_query_set().get(*args, **kwargs)
File "/opt/mysite/.virtualenvs/django/lib/python2.7/site-packages/django/db/models/query.py", line 404, in get
self.model._meta.object_name)
TypeError: 'exceptions.AttributeError' object is not callable
Line of code from django/db/models/query.py:
if not num:
raise self.model.DoesNotExist(
"%s matching query does not exist." %
self.model._meta.object_name)
So it looks as if it's trying to pass a message to the DoesNotExist exception on the model, but it's somehow been replaced by an AttributeError instead.
The issue only seems to happen from http requests - if I do the same action from the command line I just get a DoesNotExist exception (which is what should be happening).
I can't find any obvious reason this should be happening. Any ideas?
(PS this seems to be the same issue. The user's answer to it, I think, is wrong: https://groups.google.com/forum/#!topic/django-users/k9JMyXlUt3Q)
Possibly relevant code
Here is an outline of the model manager:
class CacheManager(models.Manager):
def profile_from_cache(self, user_id=None):
profile = cache.get("profile_%s" % user_id)
if profile is None:
try:
profile = self.get(user=user_id)
except Profile.DoesNotExist:
return None
cache.set("profile_%s" % user_id, profile, settings.CACHE_TIMEOUT)
return profile
...
class Profile(models.Model):
...
caches = CacheManager()
Here's the line of code that seems to be causing the error. In this case it's in some middleware, but there are a few different places, all causing the same thing.
Profile.caches.profile_from_cache(user_id=request.user.pk)
It was because of incorrect syntax elsewhere in the project, that caught multiple exceptions like this:
try:
do_something()
except AttributeError, Profile.DoesNotExist:
pass
When it should have been this:
try:
do_something()
except (AttributeError, Profile.DoesNotExist):
pass
What was happening was that when this happened, AttributeError got assigned to Profile.DoesNotExist in memory, so when it was raised later, it was the wrong exception.
Thanks to this post for helping.

What could be the reason for lxml.etree.relaxng to return DocumentInvalid without logging an error?

I have code as follows:
try:
schema = lxml.etree.RelaxNG(file=schema_file)
schema.assertValid(etree)
except lxml.etree.DocumentInvalid as exception:
print(schema.error_log)
print(exception.error_log)
raise exception
It consistently raises a DocumentInvalid error:
DocumentInvalid: Document does not comply with schema
yet prints no errors in either the schema error log or the global error log.
This only happens for some files, others validate correctly, or give a reason for failing to validate. (It's a very long schema, so I won't quote it here.)
I don't even know where to start looking. What could the cause possibly be?
That is how you can get an error message
try:
schema = lxml.etree.RelaxNG(file=schema_file)
schema.assertValid(etree)
except lxml.etree.DocumentInvalid as exception:
print(exception.error_log.filter_from_errors()[0])
raise exception

Categories