Search code examples
pythonclassoopmethodspython-class

How to group methods in Python class?


Just started learning OOP using python so I apologise if this question comes as too simplistic and welcome any improvements to my code. I am trying to write a wrapper for an API using the requests library and SurveyMonkey's API. This is what I have so far:

class SurveyMonkey:

    def __init__(self, access_token, base_url = "https://api.surveymonkey.com"):
        self.access_token = access_token
        self.base_url = base_url
        self.headers = {
            "Authorization": f"Bearer {self.access_token}",
            "Content-Type": "application/json"
        }
        self.survey_id = str()
        self.params = dict()
    
    def get_json(self):
        return requests.get(self.url, headers=self.headers, params=self.params).json()

    def list_surveys(self):
        self.url = f"{self.base_url}/v3/surveys"
        return self.get_json()

    def get_survey(self, survey_id):
        self.survey_id = survey_id
        self.url = f"{self.base_url}/v3/surveys/{self.survey_id}"
        return self.get_json()
    
    def get_survey_details(self, survey_id):
        self.survey_id = survey_id
        self.url = f"{self.base_url}/v3/surveys/{self.survey_id}/details"
        return self.get_json()
    
    def get_survey_responses_page(self, survey_id, params=dict()):
        self.survey_id = survey_id
        self.params = params
        self.url = f"{self.base_url}/v3/surveys/{self.survey_id}/responses"
        return self.get_json()
    
    def get_survey_responses_bulk_page(self, survey_id, params=dict()):
        self.survey_id = survey_id
        self.params = params
        self.url = f"{self.base_url}/v3/surveys/{self.survey_id}/responses/bulk"
        return self.get_json()
sm = SurveyMonkey(access_token)

I have used libraries where I've noticed the methods were somehow grouped. There are a few survey API's in SurveyMonkey and was wondering if I can somehow group the last 4 methods so I could call them using something like

sm.survey.get.details(id)
sm.survey.get.response.page(id)
sm.survey.get.response.bulk(id)

I couldn't really figure out how to do this

UPDATE (Thanks Tom):

I've restructured the code as per Tom's specifications and it looks like this:

class SurveyMonkey:
    
    def __init__(self, access_token, base_url = "https://api.surveymonkey.com"):
        self.surveys = surveys(self)
        self.survey_responses = survey_responses(self)
        
        self.access_token = access_token
        self.base_url = base_url
        self.headers = {
            "Authorization": f"Bearer {self.access_token}",
            "Content-Type": "application/json"
        }
        self.survey_id = str()
        self.params = dict()
        
    def get_json(self):
        return requests.get(self.url, headers=self.headers, params=self.params).json()
        
class surveys:

    def __init__(self, parent: SurveyMonkey):
        self.parent = parent

    def list_surveys(self):
        self.parent.url = f"{self.parent.base_url}/v3/surveys"
        return self.parent.get_json()
    
    def get_survey(self, survey_id):
        self.survey_id = survey_id
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}"
        return self.parent.get_json()
    
    def get_survey_details(self, survey_id):
        self.survey_id = survey_id
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/details"
        return self.parent.get_json()
    
class survey_responses:
    
    def __init__(self, parent:SurveyMonkey):
        self.parent = parent
        
    def list_responses(self, survey_id, params=dict()):
        self.survey_id = survey_id
        self.parent.params = params
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/responses"
        return self.parent.get_json()
    
    def get_response(self, survey_id, response_id, params=dict()):
        self.survey_id = survey_id
        self.response_id = response_id
        self.parent.params = params
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/responses/{response_id}"
        return self.parent.get_json()
    
    def get_response_details(self, survey_id, response_id, params=dict()):
        self.survey_id = survey_id
        self.response_id = response_id
        self.parent.params = params
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/responses/{response_id}/details"
        return self.parent.get_json()
    
    def get_response_bulk(self, survey_id, params=dict()):
        self.survey_id = survey_id
        self.parent.params = params
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/responses/bulk"
        return self.parent.get_json()

Solution

  • You can do something like this:

    class SurveyMonkey:
    
        def __init__(self):
            self.survey = Survey(self)
    
    
    class Survey:
    
        def __init__(self, parent: SurveyMonkey):
            self.parent = parent
            self.get = Get(self)
    
    
    class Get:
    
        def __init__(self, parent: Survey):
            self.parent = parent
            self.response = Response(self)
    
        def details(self, id):
            print(id)
    
    
    class Response:
    
        def __init__(self, parent: Get):
            self.parent = parent
    
        def page(self, id):
            print(id)
    
        def bulk(self, id):
            print(id)
    
    
    sm = SurveyMonkey()
    sm.survey.get.response.page(1)
    

    Then you have to be clever about your building your request function calls, traversing the class hierarchy and building the info you need to make the request.