Reputation: 148
I'm trying to create a syntax friendly library that doesn't require the user to constantly pass in credentials or type redundant or excessive statements. My strategy is to focus on how I intend the library syntax to look, and then design the library to function in that way. I know I can implement the following:
api = Api(user="admin", pswd="blahblah")
new_order = api.Order()
new_order.status = "pending"
api.create(new_order)
api.order_assign_user(new_order, user)
existing_order = api.get_order(orderId=12345)
existing_order.status = "shipped"
api.update(existing_order)
using something like the following:
class Api(object):
def __init__(self, user=None, pswd=None):
self.user = user
self.pswd = pswd
class Order(api):
def __init__ (self, status=None):
self.status = status
def create(self, x):
auth = Auth(self.user, self.pswd)
# use authorization credentials to create data remotely
return x
def update(self, x):
auth = Auth(self.user, self.pswd)
# use authorization credentials to update data from remote
return x
def get_order(self, orderId=None):
auth = Auth(self.user, self.pswd)
# use authorization credentials to update data from remote
return order
But I'd like to be able to use the following statements:
new_order.create() # instead of api.create(new_order)
new_order.assign_user(user) # instead of api.order_assign_user(new_order, user)
existing_order = api.Order.get(orderId=12345) # returns retrieved Order Instance
How would I get the Order()
instance to access attributes of the Api()
instance that created it? Without access to these, any attributes like 'user' and 'pswd' would be inaccessible (they're needed for requests.get() calls)
I've tried variations of functions and classes to accomplish this, but could never solve this problem. This is the closest I've been able to achieve:
class Api(object):
def __init__(self, user=None, pswd=None):
self.user = user
self.pswd = pswd
class Order(api):
def __init__ (self, status=None):
self.status = status
@classmethod
def get(cls, value):
return cls(status=value)
def create(self):
auth = Auth(self.user, self.pswd)
# these credentials need to come from the Api() instance?, not self
return x
def update(self):
auth = Auth(self.user, self.pswd)
# these credentials need to come from the Api() instance?, not self
return x
Is this possible? Or am I going about this the wrong way? I've considered making this into a module but that didn't seem to be a valid option either.
Upvotes: 0
Views: 62
Reputation: 2033
This demonstrates a basic implementation of what I think you want to do, I found this better than the __get__
, __set__
hackery that I had in mind when I commented your question
import requests
class Order:
def __init__(self, user:str, passwd: str):
self.session = requests.Session()
self.session.auth = (user, passwd)
self.status = None
# This is only to make the class callable, since the class is
# already instantiated in Api init calling it again would raise an exception
def __call__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
return self
def get(self):
response = self.session.get('https://httpbin.org/basic-auth/my_user/my_pass')
print(response.text)
def post(self):
response = self.session.post('https://httpbin.org/post', data={'status': self.status})
print(response.text)
class Api:
def __init__(self, user: str, passwd: str):
self.Order = Order(user, passwd)
Upvotes: 1
Reputation: 5012
Inner classes in Python are just separate classes, and their instances are not in any way automatically associated with an instance of an outer class.
I would suggest a solution in which the constructor of Order
would take an Api
instance as an argument and work with that instance:
class Api(object):
def __init__(self, user=None, pswd=None):
self.user = user
self.pswd = pswd
class Order(object):
def __init__(self, api, status=None):
self.api = api
self.status = status
@classmethod
def get(cls, api, value):
return cls(api, status=value)
def create(self):
auth = Auth(self.api.user, self.api.pswd)
return x
def update(self):
auth = Auth(self.api.user, self.api.pswd)
return x
Upvotes: 1