Mailjet REST API - is it even functional? - python

I'm using the mailjet Python API, and I'm a little confused.
https://www.mailjet.com/docs/api/lists/contacts
It doesn't even appear possible to use this API class to call mailjets GET methods.
Can anyone confirm this is the case?
api.lists.Contacts(id='foo') # causes POST, thus 405
Here's their API classes. I don't even see ApiMethodFunction passing options to the connection class.
class ApiMethod(object):
def __init__(self, api, method):
self.api = api
self.method = method
def __getattr__(self, function):
return ApiMethodFunction(self, function)
def __unicode__(self):
return self.method
class ApiMethodFunction(object):
def __init__(self, method, function):
self.method = method
self.function = function
def __call__(self, **kwargs):
response = self.method.api.connection.open(
self.method,
self.function,
postdata=kwargs,
)
return json.load(response)
def __unicode__(self):
return self.function
It seems like a critical feature so I'm inclined to think I'm just using it incorrectly, but could it be?
How are you supposed to list Contacts if it needs id in the GET parameters?

the python library is now fixed. According to its author, you can now pass a parameter to specify if the request is going to be a POST or a GET
https://github.com/WoLpH/mailjet

Related

Python decorator class with members

I want to write a class that will have member variables and member functions that will be used as decorators.
class decorator_class:
def __init__(self, baseurl, username,password):
self._baseurl = baseurl
self._username = _username
self._password = _password
def decorator_get(self,arguments):
def inner_function(function):
#wraps(function)
def wrapper(*args, **kwargs):
url = self._url + argument
if len(kwargs) > 0:
url+="?"
argseperator=""
for k,v in kwargs.items():
url+="{}{}={}".format(argseperator,k,v)
argseperator="&"
r = requests.get(url, auth=(self._username, self._password))
if r.status_code != 200:
raise Exception('Failed to GET URL: {}'.format(url))
return function(args[0],json = r.json())
return wrapper
return inner_function
class usedecorator:
def __init__(baseurl, self,user,password):
self.dec = decorator_class(baseurl, self,user,password)
#dec.decorator_get('/path/to/resource1')
def process_output_resource1(self, json):
do_something_with_json
The problem is that __init__ is being called after the class is loaded and at that time dec is undefined.
if I define the decorator_class globally it works, but then there is no way to pass the url, user and password to it at runtime.
Any suggestions?
Your decorator_get > innder_function > wrapper has the userdecorator's self.
Weird sentence but eh.
You have some weird namings, IDK why did you use self as a second argument for instance but, I tried to follow your naming.
def decorator_get(arguments):
def inner_function(function):
#wraps(function)
def wrapper(self, *args, **kwargs):
url = self._base_url + arguments
if len(kwargs) > 0:
url+="?"
argseperator=""
for k,v in kwargs.items():
url+="{}{}={}".format(argseperator,k,v)
argseperator="&"
r = requests.get(url, auth=(self._username, self._password))
if r.status_code != 200:
raise Exception('Failed to GET URL: {}'.format(url))
return function(self, json = r.json())
return wrapper
return inner_function
class usedecorator:
def __init__(self, baseurl,user,password):
self._base_url = baseurl
self._username = user
self._password= password
#decorator_get('/path/to/resource1')
def process_output_resource1(self, json):
do_something_with_json
Indeed -to have a decorator for methods in a class, it must already be defined (i.e. ready to be used) when the method to be decorated is declared: which means it have to be declared either at top-level or inside the class body.
Code inside methods, including __init__, however will only run when an instance is created - and that is the point where the class will get your connection parameters.
If this decorator is being used always in this model, you can turn it into a descriptor: an object which is a class attribute, but which has code (in a method named __get__) that is executed after the instance is created.
This descriptor could then fetch the connection parameters in the instance itself, after it has been created, and prepare way for calling the underlying method.
That will require some reorganization on your code: the object returned by __get__ has to be a callable which will ultimately run your function, but it would not be nice if simply retrieving the method name would trigger the network request - one will expect it to be triggered when the process_output... method is actually called. The __get__ method then should return your inner "wrapper" function, which will have all the needed data for the request from the "instance" attribute Python passes automatically, but for the payload which it gets via kwargs.
class decorator_class:
def __init__(self, path=None):
self.path = None
self.func = None
def __get__(self, instance, owner):
if instance is None:
return self
def bound_to_request(**kwargs):
# retrieves the baseurl, user and password from the host instance:
# build query part of the target URL - instead of your convoluted
# code to build the query string (which will break ont he first special character,
# just pass kwargs as the "params" argument)
response = requests.get(instance._base_url, auth=(
instance.user, instance.password), params=kwargs)
# error treatment code
#...
return self.func(response.json())
return bound_to_request
def __call__(self, arg):
# create a new instance of this class on each stage:
# first anotate the API path, on the second call annotate the actual method
new_inst = type(self)()
if not self.path:
if not isinstance(arg, str):
raise TypeError("Expecting an API path for this method")
new_inst.path = arg
else:
if not callable(arg):
raise TypeError("Expecting a target method to be decorated")
new_inst.func = wraps(arg)
return new_inst
def __repr__(self):
return f"{self.func.__name__!r} method bound to retrieve data from {self.path!r}"
class use_decorator:
dec = decorator_class()
def __init__(self=, baseurl, user, password):
# the decorator assumes these to be set as instance attributes
self.baseurl = baseurl
self.user = user
self.password = password
# <- the call passing the path returns an instance of
# the decorator with the path set. it is use as an
# decorator is called again, and on this second call, the decorated method is set.
#dec.decorator_get('/path/to/resource1')
def process_output_resource1(self, json):
# do_something_with_json
...
In time, re-reading your opening paragraph, I see you intended to have more than one decorator inside your original class, probably others intended for "POST" and other HTTP requests: most important thing, the __get__ name here has nothing to do with HTTP: it is a fixed method name in the Python spec which is called automatically by the language when one will retrieve your method from an instance of use_decorator. That is, when there is code: my_instance.process_output_resource1(...), the __get__ method of the descriptor is called. Whatever it returned is then called.
For enabling the same decorator to use POST and other HTTP methods, I suggest you to have as a first parameter when annotating the path for each method, and then simply call the appropriate requests method by checking self.method inside the bound_to_request function.
I think you're going too far with the decorator approach. Let's break this down into a single question: What is the actual shared state here that you need a class for? To me, it looks like just the baseurl, user, and password. So let's just use those directly without a decorator:
from requests import Session
from requests.auth import HTTPBasicAuth
class UseDecorator: # this isn't a good name, but we will keep it temporarily
def __init__(self, baseurl, user, password):
self.baseurl = baseurl
self.session = Session()
# we've now bound the authentication to the session
self.session.auth = HTTPBasicAuth(user, password)
# now let's just bind a uri argument to a function to simply
# send a request
def send_request(self, uri, *args, **kwargs):
url = self.baseurl + uri
# you don't need to manually inject parameters, just use
# the params kwarg
r = self.session.get(url, params=kwargs)
# this will check the response code for you and even handle
# a redirect, which your 200 check will fail on
r.raise_for_status()
return r.json()
# then just handle each individual path
def path_1(self, *args, **kwargs):
data = self.send_request('/path/1', *args, **kwargs)
# process data
def path_2(self, *args, **kwargs):
data = self.send_request('/path/2', *args, **kwargs)
# process data
Because we're leveraging the machinery offered to us by requests, most of your decorator is simplified, and we can boil it down to a simple function call for each path

Python: run staticmethod of class in init?

The following is making me suspect whether what I want is a class or a module.
Basically I'm building a parser of sorts, an API library.
The external service which my code connects to needs a token for every time a request is made.
I'm successfully generating this token. However, I'm not sure how I can "give" this token to class instances if it's not in the __init__ of the class.
My code so far:
class MBParser(object):
pass
class SomeServiceParser(MBParser):
'''instantiate and use me'''
def __init__(self):
self.token = _get_token()
#staticmethod
def _get_token():
# code to get the token
You could wrap each function that requires a new token in a decorator like the following:
def new_token(func):
def wrapper(self, *args, **kwargs):
self.token = SomeParser._get_token()
r = func(self, *args, **kwargs)
return wrapper
I explicitly added a self argument in the wrapper method since the methods in the class will need this anyway. And this way, I can access the self.token attribute and set it to a new value
Could use the decorator as follows:
#new_token
def makeHTTPRequest(self, name):
# ... make request and use self.token here

Perform additional operations for each call to an external API

I have an external API that I cannot modify. For each call to this API, I need to be able to perform an operation before and after. This API is used like this:
def get_api():
"""
Return an initiated ClassAPI object
"""
token = Token.objects.last()
api = ClassAPI(
settings.CLASS_API_ID,
settings.CLASS_API_SECRET,
last_token)
return api
get_api() is called everywhere in the code and the result is then used to perform request (like: api.book_store.get(id=book_id)).
My goal is to return a virtual object that will perform the same operations than the ClassAPI adding print "Before" and print "After".
The ClassAPI looks like this:
class ClassAPI
class BookStore
def get(...)
def list(...)
class PenStore
def get(...)
def list(...)
I tried to create a class inheriting from (ClassApi, object) [as ClassAPI doesn't inherit from object] and add to this class a metaclass that decorates all the methods, but I cannot impact the methods from BookStore (get and list)
Any idea about how to perform this modifying only get_api() and adding additional classes? I try to avoid copying the whole structure of the API to add my operations.
I am using python 2.7.
You could do this with a Proxy:
class Proxy:
def __init__(self, other):
self.other = other
self.calls = []
def __getattr__(self, name):
self.calls.append(name)
return self
def __call__(self, *args, **kwargs):
self.before()
ret = self.call_proxied(*args, **kwargs)
self.after()
return ret
def call_proxied(self, *args, **kwargs):
other = self.other
calls = self.calls
self.calls = []
for item in calls:
other = getattr(other, item)
return other(*args, **kwargs)
This class intercepts unknown members in the __getattr__() method, saving the names that are used and returning itself.
When a method is called (eg. api.book_store.get(id=book_id) ), it calls a before() and after() method on itself and in between it fetches the members of other and forwards the arguments in a call.
You use this class like this:
def get_api():
...
return Proxy(api)
Update: corrected the call to self.call_proxied(*args, **kwargs). Also allow any return value to be returned.

Implementing Django style API, chaining dots, inheritance

I'm trying to implement client for JSON API. I've worked with Django and i found the way it handles queries pretty interesting.
For example:
>>> from django.contrib.auth.models import User
>>> user = User.objects.get(username='johndoe')
>>> user
<User: johndoe>
>>> user.objects.get(username='johndoe')
AttributeError: Manager isn't accessible via User instances
I'm interested what Manager exactly is and if there is a simple way to implement it. I tried to do something similar, but failed miserably. Here is my first attempt:
class Api(object):
def __init__(self, api_key):
self.api_key = key
#property
def player(self):
return Player(api=self)
class Player(object):
def __init__(self, api):
self.api = api
def get(self, id_):
'''
gets json and turns it into dictionary
'''
self.name = data['name']
self.id_ = id_
return self
So the usage would look like this:
>>> api = Api('api_key_here')
>>> player = api.player.get('player_id_here')
However to me it feels sketchy and simply wrong to do it this way(which is certainly true). Problems here are:
I have to send whole Api object to Player object
Player object will still have get() method
I don't know if using #property this way is acceptable
Here is how i would like to use my Api class:
api = Api('api_key_here')
player = api.player.get('player_id') #getting player object
item = api.item.get('item_id') #getting item object
recent_games = api.recent_games.filter(player=player, how_many=10) #getting list of game objects
I recommend you look at https://github.com/samgiles/slumber which implements exactly what you may be doing (a Rest API Client). But even if you are doing something else, slumber is implemented doing what you are trying to do. Something like:
class RestResource(object):
def __init__(self, *args, **kwargs):
self._store = kwargs
def __call__(self, id=None, action=None):
"""
Returns a new instance of self modified by one or more of the available
parameters. These allows us to do things like override format for a
specific request, and enables the api.resource(ID).get() syntax to get
a specific resource by it's ID.
"""
kwargs = {
'foo': self._store['name1'],
'bar': self._store['name2']
}
return self.__class__(**kwargs)
class Api(object):
resource_class = RestResource
def __getattr__(self, item):
kwargs = {
'name1': 'val1',
'name2': 'val2'
}
return self.resource_class(**kwargs)
and you can use like this
api = Api()
api.player.get()

Python decorators and class inheritance

I'm trying to use decorators in order to manage the way users may or may not access resources within a web application (running on Google App Engine). Please note that I'm not allowing users to log in with their Google accounts, so setting specific access rights to specific routes within app.yaml is not an option.
I used the following resources :
- Bruce Eckel's guide to decorators
- SO : get-class-in-python-decorator2
- SO : python-decorators-and-inheritance
- SO : get-class-in-python-decorator
However I'm still a bit confused...
Here's my code ! In the following example, current_user is a #property method which belong to the RequestHandler class. It returns a User(db.model) object stored in the datastore, with a level IntProperty().
class FoobarController(RequestHandler):
# Access decorator
def requiredLevel(required_level):
def wrap(func):
def f(self, *args):
if self.current_user.level >= required_level:
func(self, *args)
else:
raise Exception('Insufficient level to access this resource')
return f
return wrap
#requiredLevel(100)
def get(self, someparameters):
#do stuff here...
#requiredLevel(200)
def post(self):
#do something else here...
However, my application uses different controllers for different kind of resources. In order to use the #requiredLevel decorator within all subclasses, I need to move it to the parent class (RequestHandler) :
class RequestHandler(webapp.RequestHandler):
#Access decorator
def requiredLevel(required_level):
#See code above
My idea is to access the decorator in all controller subclasses using the following code :
class FoobarController(RequestHandler):
#RequestHandler.requiredLevel(100)
def get(self):
#do stuff here...
I think I just reached the limit of my knowledge about decorators and class inheritance :). Any thoughts ?
Your original code, with two small tweaks, should also work. A class-based approach seems rather heavy-weight for such a simple decorator:
class RequestHandler(webapp.RequestHandler):
# The decorator is now a class method.
#classmethod # Note the 'klass' argument, similar to 'self' on an instance method
def requiredLevel(klass, required_level):
def wrap(func):
def f(self, *args):
if self.current_user.level >= required_level:
func(self, *args)
else:
raise Exception('Insufficient level to access this resource')
return f
return wrap
class FoobarController(RequestHandler):
#RequestHandler.requiredLevel(100)
def get(self, someparameters):
#do stuff here...
#RequestHandler.requiredLevel(200)
def post(self):
#do something else here...
Alternately, you could use a #staticmethod instead:
class RequestHandler(webapp.RequestHandler):
# The decorator is now a static method.
#staticmethod # No default argument required...
def requiredLevel(required_level):
The reason the original code didn't work is that requiredLevel was assumed to be an instance method, which isn't going to be available at class-declaration time (when you were decorating the other methods), nor will it be available from the class object (putting the decorator on your RequestHandler base class is an excellent idea, and the resulting decorator call is nicely self-documenting).
You might be interested to read the documentation about #classmethod and #staticmethod.
Also, a little bit of boilerplate I like to put in my decorators:
#staticmethod
def requiredLevel(required_level):
def wrap(func):
def f(self, *args):
if self.current_user.level >= required_level:
func(self, *args)
else:
raise Exception('Insufficient level to access this resource')
# This will maintain the function name and documentation of the wrapped function.
# Very helpful when debugging or checking the docs from the python shell:
wrap.__doc__ = f.__doc__
wrap.__name__ = f.__name__
return f
return wrap
After digging through StackOverflow, and carefully reading Bruce Eckel's guide to decorators, I think I found a possible solution.
It involves implementing the decorator as a class in the Parent class :
class RequestHandler(webapp.RequestHandler):
# Decorator class :
class requiredLevel(object):
def __init__(self, required_level):
self.required_level = required_level
def __call__(self, f):
def wrapped_f(*f_args):
if f_args[0].current_user.level >= self.required_level:
return f(*f_args)
else:
raise Exception('User has insufficient level to access this resource')
return wrapped_f
This does the work ! Using f_args[0] seems a bit dirty to me, I'll edit this answer if I find something prettier.
Then you can decorate methods in subclasses the following way :
FooController(RequestHandler):
#RequestHandler.requiredLevel(100)
def get(self, id):
# Do something here
#RequestHandler.requiredLevel(250)
def post(self)
# Do some stuff here
BarController(RequestHandler):
#RequestHandler.requiredLevel(500)
def get(self, id):
# Do something here
Feel free to comment or propose an enhancement.

Categories

Resources