Defining many HTTP request methods in a class using partialmethods I am using an object that expects a keyword argument for every call, but I never intend to change it. In this case a timeout of 10. What is the best way to add a partialmethods for each attributes.

In my example I want to set a timeout for my session requests http methods.

I could monkeypatch Session.request with a partialmethod. This works fairly well because all of the session methods go through request. Session().post is actually going through Session.request('post', &lt;inputs&gt;).

from requests import Session

Session.request = partialmethod(Session.request, timeout=10)


However, what about use cases where there isn't a single method I can fix or I simply don't want to do something potentially dangerous like monkeypatching.

I have a session helper object that configures the auth and the adapter (omitted here) for the client, but I want different default timeouts for different methods. I can't even monkeypatch the method in that case.

I could do it after standard definition of the class in a loop.

from functools import partialmethod
from requests import Session

class SeshTester:
    def __init__(self):
        self.s = Session()

    def request(self, method, *args, **kwargs):
        return self.s.request(method, *args, **kwargs)


for r_method in ['delete', 'get', 'head', 'options']:
    setattr(SeshTester, r_method, partialmethod(SeshTester.request, r_method, timeout=7))

for r_method in ['connect', 'put', 'push']:
    setattr(SeshTester, r_method, partialmethod(SeshTester.request, r_method, timeout=13))

# this call is equivalent to self.s.request('get', 'http://google.com', timeout=7
print(SeshTester().get('http://google.com'))


I don't think this is very legible, but am unaware how to do this inside of standard class definition. SeshTester object obviously isn't reference-able before it is made, but I don't want to repeat myself by doing post = partialmethod(request, 'post', timeout=13) for every possible http method.

I would like to perform this loop in the class, but don't know how to reference the object before it's fully defined.
It is certainly possible to do what was outlined that lies outside the class definition within the class definition itself through the usage of locals, and with that the intent of what is to be done can be expressed more clearly with less verbose code and lookup using setattr.

class SeshTester:
    def __init__(self):
        self.s = Session()

    def request(self, method, *args, **kwargs):
        return self.s.request(method, *args, **kwargs)

    for r_method in ['delete', 'get', 'head', 'options']:
        locals()[r_method] = partialmethod(request, r_method, timeout=7)

    for r_method in ['connect', 'put', 'push']:
        locals()[r_method] = partialmethod(request, r_method, timeout=13)


Seeing this working as intended from the shell:

&gt;&gt;&gt; SeshTester().get
functools.partial(&lt;bound method SeshTester.request of &lt;__main__.SeshTester object at 0x7fde00176ef0&gt;&gt;, 'get', timeout=7)
&gt;&gt;&gt; SeshTester().put
functools.partial(&lt;bound method SeshTester.request of &lt;__main__.SeshTester object at 0x7fddf8da0668&gt;&gt;, 'put', timeout=13)


One more thing: the documentation linked above does not actually describe what is implemented, at least for CPython; other implementations may have locals() behave differently within the class scope, however there is now an effort to properly standardize this underspecified behavior to the CPython implementation in PEP-558, such that the above code example will work as intended according to the standard (if the PEP gets ratified into Python 3.7).



However, as mentioned in the question, if the API provides a standardized helper method that provides a specific Session instance, certainly it can provide a subclassed Session instance with the specific features/methods that require overriding be applied where needed.  Consider the following:

class SessionExtras(Session):

    def request(self, method, url, *a, **kw):
        default_timeout = 7 
        timeouts = {
            'CONNECT': 13,
            'PUT': 13,
            'PUSH': 13,
        } 
        if kw.get('timeout') is None:
            kw['timeout'] = timeouts.get(method, default_timeout)
        return super().request(method, url, *a, **kw)


Perhaps this way the intent of what is to be done is expressed in a much more clear way, and allow the API users to make use of a real Session instance rather than some surrogate.  For this example, the default_timeout and timeouts is defined within the function definition, however they could conceivably be moved to the class or even module level, depending on the intended usage and how it is to be customized for the specific API that is being written.