For the details on `method`, `url`, `params`, and `data`, refer to the Requests documentation on the constructor of `requests.Request`.
For details on `timeout`, see `requests.adapters.HTTPAdapter.send`.
`headers` can be used to specify any HTTP headers. Note that this is case-sensitive. To override the user agent, include a value for the `User-Agent` key here.
`responseOkCallback` can be used to control whether a response is considered acceptable or not. By default, all HTTP responses are considered fine. If specified, this callable must produce a boolean marking whether the response is successful and an error message string. The string is used for logging purposes when the success flag is `False`; it should be `None` if the first return value is `True`.
'''
mergedHeaders = {'User-Agent': self._userAgent}
mergedHeaders = {'User-Agent': self._userAgent}
if headers:
if headers:
mergedHeaders.update(headers)
mergedHeaders.update(headers)
@@ -120,14 +152,18 @@ class HttpClient:
raise RuntimeError('Reached unreachable code')
raise RuntimeError('Reached unreachable code')
def get(self, *args, **kwargs):
def get(self, *args, **kwargs):
'''Make a GET request. This is equivalent to calling `.request('GET', ...)`.'''
return self.request('GET', *args, **kwargs)
return self.request('GET', *args, **kwargs)
def post(self, *args, **kwargs):
def post(self, *args, **kwargs):
'''Make a POST request. This is equivalent to calling `.request('POST', ...)`.'''
return self.request('POST', *args, **kwargs)
return self.request('POST', *args, **kwargs)
class ModuleMeta(type):
class ModuleMeta(type):
__modulesByName = {} # name -> Module class
'''Metaclass of modules. This is used to keep track of which modules exist and selecting them. It also enforces module name restrictions and prevents name collisions.'''
for name in list(cls.__modulesByName): # create a copy of the names list so the dict can be modified in the loop
for name in list(cls.__modulesByName): # create a copy of the names list so the dict can be modified in the loop
if cls.__modulesByName[name]() is None:
if cls.__modulesByName[name]() is None:
@@ -168,7 +208,13 @@ class ModuleMeta(type):
yield class_
yield class_
@classmethod
@classmethod
def drop(cls, module):
def drop(cls, module: 'Module'):
'''
Remove a module from the list of known modules
If a Module subclass is destroyed after `del MyModule`, it is also eventually removed from the list. However, as that relies on garbage collection, it should not be depended on and modules should be dropped with this method explicitly.
'''
if module.name is not None and module.name in cls.__modulesByName:
if module.name is not None and module.name in cls.__modulesByName:
del cls.__modulesByName[module.name]
del cls.__modulesByName[module.name]
logger.info(f'Module {module.name!r} dropped')
logger.info(f'Module {module.name!r} dropped')
@@ -191,7 +237,7 @@ class Module(metaclass = ModuleMeta):
'''Whether or not this module is for handling `inputUrl`.'''
'''Whether or not this module is for handling `inputUrl`.'''