Repository: getmoto/moto

Issue:
Cognito-idp does not implement AttributesToGet or Filter in list_users
The only `list_users` parameter currently implemented is `UserPoolId`. We should implement `AttributesToGet` and `Filter` for completeness.


Discussion:
Thanks; setting as a feature request.

Resolving patch:
diff --git a/moto/cognitoidp/models.py b/moto/cognitoidp/models.py
--- a/moto/cognitoidp/models.py
+++ b/moto/cognitoidp/models.py
@@ -646,7 +646,9 @@ def _base_json(self):
         }
 
     # list_users brings back "Attributes" while admin_get_user brings back "UserAttributes".
-    def to_json(self, extended=False, attributes_key="Attributes"):
+    def to_json(
+        self, extended=False, attributes_key="Attributes", attributes_to_get=None
+    ):
         user_mfa_setting_list = []
         if self.software_token_mfa_enabled:
             user_mfa_setting_list.append("SOFTWARE_TOKEN_MFA")
@@ -654,10 +656,15 @@ def to_json(self, extended=False, attributes_key="Attributes"):
             user_mfa_setting_list.append("SMS_MFA")
         user_json = self._base_json()
         if extended:
+            attrs = [
+                attr
+                for attr in self.attributes
+                if not attributes_to_get or attr["Name"] in attributes_to_get
+            ]
             user_json.update(
                 {
                     "Enabled": self.enabled,
-                    attributes_key: self.attributes,
+                    attributes_key: attrs,
                     "MFAOptions": [],
                     "UserMFASettingList": user_mfa_setting_list,
                 }
diff --git a/moto/cognitoidp/responses.py b/moto/cognitoidp/responses.py
--- a/moto/cognitoidp/responses.py
+++ b/moto/cognitoidp/responses.py
@@ -341,6 +341,7 @@ def list_users(self):
         limit = self._get_param("Limit")
         token = self._get_param("PaginationToken")
         filt = self._get_param("Filter")
+        attributes_to_get = self._get_param("AttributesToGet")
         users, token = cognitoidp_backends[self.region].list_users(
             user_pool_id, limit=limit, pagination_token=token
         )
@@ -385,7 +386,12 @@ def list_users(self):
                     and compare(inherent_attributes[name](user), value)
                 )
             ]
-        response = {"Users": [user.to_json(extended=True) for user in users]}
+        response = {
+            "Users": [
+                user.to_json(extended=True, attributes_to_get=attributes_to_get)
+                for user in users
+            ]
+        }
         if token:
             response["PaginationToken"] = str(token)
         return json.dumps(response)


Test patch:
diff --git a/tests/test_cognitoidp/test_cognitoidp.py b/tests/test_cognitoidp/test_cognitoidp.py
--- a/tests/test_cognitoidp/test_cognitoidp.py
+++ b/tests/test_cognitoidp/test_cognitoidp.py
@@ -2210,6 +2210,33 @@ def test_list_users_when_limit_more_than_total_items():
     result.shouldnt.have.key("PaginationToken")
 
 
+@mock_cognitoidp
+def test_list_users_with_attributes_to_get():
+    conn = boto3.client("cognito-idp", "us-west-2")
+    user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
+
+    for _ in range(5):
+        conn.admin_create_user(
+            UserPoolId=user_pool_id,
+            Username=str(uuid.uuid4()),
+            UserAttributes=[
+                {"Name": "family_name", "Value": "Doe"},
+                {"Name": "given_name", "Value": "Jane"},
+                {"Name": "custom:foo", "Value": "bar"},
+            ],
+        )
+
+    result = conn.list_users(
+        UserPoolId=user_pool_id, AttributesToGet=["given_name", "custom:foo", "unknown"]
+    )
+    users = result["Users"]
+    users.should.have.length_of(5)
+    for user in users:
+        user["Attributes"].should.have.length_of(2)
+        user["Attributes"].should.contain({"Name": "given_name", "Value": "Jane"})
+        user["Attributes"].should.contain({"Name": "custom:foo", "Value": "bar"})
+
+
 @mock_cognitoidp
 def test_admin_disable_user():
     conn = boto3.client("cognito-idp", "us-west-2")