# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER

"""Astroid hooks for understanding boto3.ServiceRequest()"""
import astroid
from astroid import MANAGER, extract_node

BOTO_SERVICE_FACTORY_QUALIFIED_NAME = "boto3.resources.base.ServiceResource"


def service_request_transform(node):
    """Transform ServiceResource to look like dynamic classes"""
    code = """
    def __getattr__(self, attr):
        return 0
    """
    func_getattr = extract_node(code)
    node.locals["__getattr__"] = [func_getattr]
    return node


def _looks_like_boto3_service_request(node):
    return node.qname() == BOTO_SERVICE_FACTORY_QUALIFIED_NAME


MANAGER.register_transform(
    astroid.ClassDef, service_request_transform, _looks_like_boto3_service_request
)

Transform boto3.ServiceRequest to look like dynamic class
Transform boto3.ServiceRequest to look like dynamic class

`boto3.resource` creates resources dynamically via a resource factory.
Unfortunately that completely breaks static analysis leading to spurious
false positives since pylint cannot determine sanely that attributes
exist or not.

Here's an example of accessing the Topic class out of the `sns` resource.
As you can see, the class is created dynamically rather than existing
in the codebase itself:

```
In [2]: boto3.resource
Out[2]: <function boto3.resource(*args, **kwargs)>

In [3]: boto3.resource('sns')
Out[3]: sns.ServiceResource()

In [4]: boto3.resource('sns').Topic
Out[4]: <bound method ResourceFactory._create_class_partial.<locals>.create_resource of sns.ServiceResource()>
```

This patch adds a fake `__getattr__` method to `ServiceRequest`.
This will prevent `pylint` from emitting `no-member` at all for `ServiceRequest`
instances, but that is a good solution for now until we can load typeshed-like
annotation packages.

Close PyCQA/pylint#3134
