We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Schema factory only variable fail - can't pass list type
Looking at the [schema factory docs](https://webargs.readthedocs.io/en/latest/advanced.html#schema-factories), I'm interested in trying the
```
# Filter based on 'fields' query parameter
only = request.args.get("fields", None)
```
part.

However, when I try appending something like `?fields=some_field` to my HTTP request, I get the following error:
```
File "edited/marshmallow/schema.py", line 349, in __init__
    raise StringNotCollectionError('"only" should be a list of strings')
```

As far as I can see, webargs always passes the query string parameters as strings. I tried wrapping it in square brackets, but I think I'm barking up the wrong tree. Have I misunderstood something, or is this a bug?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `examples/schema_example.py`
Content:
```
1 """Example implementation of using a marshmallow Schema for both request input
2 and output with a `use_schema` decorator.
3 Run the app:
4 
5     $ python examples/schema_example.py
6 
7 Try the following with httpie (a cURL-like utility, http://httpie.org):
8 
9     $ pip install httpie
10     $ http GET :5001/users/
11     $ http GET :5001/users/42
12     $ http POST :5001/users/ usename=brian first_name=Brian last_name=May
13     $ http PATCH :5001/users/42 username=freddie
14     $ http GET :5001/users/ limit==1
15 """
16 import functools
17 from flask import Flask, request, jsonify
18 import random
19 
20 from marshmallow import Schema, fields, post_dump
21 from webargs.flaskparser import parser, use_kwargs
22 
23 app = Flask(__name__)
24 
25 ##### Fake database and models #####
26 
27 
28 class Model:
29     def __init__(self, **kwargs):
30         self.__dict__.update(kwargs)
31 
32     def update(self, **kwargs):
33         self.__dict__.update(kwargs)
34 
35     @classmethod
36     def insert(cls, db, **kwargs):
37         collection = db[cls.collection]
38         new_id = None
39         if "id" in kwargs:  # for setting up fixtures
40             new_id = kwargs.pop("id")
41         else:  # find a new id
42             found_id = False
43             while not found_id:
44                 new_id = random.randint(1, 9999)
45                 if new_id not in collection:
46                     found_id = True
47         new_record = cls(id=new_id, **kwargs)
48         collection[new_id] = new_record
49         return new_record
50 
51 
52 class User(Model):
53     collection = "users"
54 
55 
56 db = {"users": {}}
57 
58 
59 ##### use_schema #####
60 
61 
62 def use_schema(schema, list_view=False, locations=None):
63     """View decorator for using a marshmallow schema to
64         (1) parse a request's input and
65         (2) serializing the view's output to a JSON response.
66     """
67 
68     def decorator(func):
69         @functools.wraps(func)
70         def wrapped(*args, **kwargs):
71             use_args_wrapper = parser.use_args(schema, locations=locations)
72             # Function wrapped with use_args
73             func_with_args = use_args_wrapper(func)
74             ret = func_with_args(*args, **kwargs)
75             # Serialize and jsonify the return value
76             return jsonify(schema.dump(ret, many=list_view).data)
77 
78         return wrapped
79 
80     return decorator
81 
82 
83 ##### Schemas #####
84 
85 
86 class UserSchema(Schema):
87     id = fields.Int(dump_only=True)
88     username = fields.Str()
89     first_name = fields.Str()
90     last_name = fields.Str()
91 
92     class Meta:
93         strict = True
94 
95     @post_dump(pass_many=True)
96     def wrap_with_envelope(self, data, many, **kwargs):
97         return {"data": data}
98 
99 
100 ##### Routes #####
101 
102 
103 @app.route("/users/<int:user_id>", methods=["GET", "PATCH"])
104 @use_schema(UserSchema())
105 def user_detail(reqargs, user_id):
106     user = db["users"].get(user_id)
107     if not user:
108         return jsonify({"message": "User not found"}), 404
109     if request.method == "PATCH" and reqargs:
110         user.update(**reqargs)
111     return user
112 
113 
114 # You can add additional arguments with use_kwargs
115 @app.route("/users/", methods=["GET", "POST"])
116 @use_kwargs({"limit": fields.Int(missing=10, location="query")})
117 @use_schema(UserSchema(), list_view=True)
118 def user_list(reqargs, limit):
119     users = db["users"].values()
120     if request.method == "POST":
121         User.insert(db=db, **reqargs)
122     return list(users)[:limit]
123 
124 
125 # Return validation errors as JSON
126 @app.errorhandler(422)
127 @app.errorhandler(400)
128 def handle_validation_error(err):
129     exc = getattr(err, "exc", None)
130     if exc:
131         headers = err.data["headers"]
132         messages = exc.messages
133     else:
134         headers = None
135         messages = ["Invalid request."]
136     if headers:
137         return jsonify({"errors": messages}), err.code, headers
138     else:
139         return jsonify({"errors": messages}), err.code
140 
141 
142 if __name__ == "__main__":
143     User.insert(
144         db=db, id=42, username="fred", first_name="Freddie", last_name="Mercury"
145     )
146     app.run(port=5001, debug=True)
147
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/examples/schema_example.py b/examples/schema_example.py
--- a/examples/schema_example.py
+++ b/examples/schema_example.py
@@ -89,9 +89,6 @@
     first_name = fields.Str()
     last_name = fields.Str()
 
-    class Meta:
-        strict = True
-
     @post_dump(pass_many=True)
     def wrap_with_envelope(self, data, many, **kwargs):
         return {"data": data}

{"golden_diff": "diff --git a/examples/schema_example.py b/examples/schema_example.py\n--- a/examples/schema_example.py\n+++ b/examples/schema_example.py\n@@ -89,9 +89,6 @@\n     first_name = fields.Str()\n     last_name = fields.Str()\n \n-    class Meta:\n-        strict = True\n-\n     @post_dump(pass_many=True)\n     def wrap_with_envelope(self, data, many, **kwargs):\n         return {\"data\": data}\n", "issue": "Schema factory only variable fail - can't pass list type\nLooking at the [schema factory docs](https://webargs.readthedocs.io/en/latest/advanced.html#schema-factories), I'm interested in trying the\r\n```\r\n# Filter based on 'fields' query parameter\r\nonly = request.args.get(\"fields\", None)\r\n```\r\npart.\r\n\r\nHowever, when I try appending something like `?fields=some_field` to my HTTP request, I get the following error:\r\n```\r\nFile \"edited/marshmallow/schema.py\", line 349, in __init__\r\n    raise StringNotCollectionError('\"only\" should be a list of strings')\r\n```\r\n\r\nAs far as I can see, webargs always passes the query string parameters as strings. I tried wrapping it in square brackets, but I think I'm barking up the wrong tree. Have I misunderstood something, or is this a bug?\n", "before_files": [{"content": "\"\"\"Example implementation of using a marshmallow Schema for both request input\nand output with a `use_schema` decorator.\nRun the app:\n\n    $ python examples/schema_example.py\n\nTry the following with httpie (a cURL-like utility, http://httpie.org):\n\n    $ pip install httpie\n    $ http GET :5001/users/\n    $ http GET :5001/users/42\n    $ http POST :5001/users/ usename=brian first_name=Brian last_name=May\n    $ http PATCH :5001/users/42 username=freddie\n    $ http GET :5001/users/ limit==1\n\"\"\"\nimport functools\nfrom flask import Flask, request, jsonify\nimport random\n\nfrom marshmallow import Schema, fields, post_dump\nfrom webargs.flaskparser import parser, use_kwargs\n\napp = Flask(__name__)\n\n##### Fake database and models #####\n\n\nclass Model:\n    def __init__(self, **kwargs):\n        self.__dict__.update(kwargs)\n\n    def update(self, **kwargs):\n        self.__dict__.update(kwargs)\n\n    @classmethod\n    def insert(cls, db, **kwargs):\n        collection = db[cls.collection]\n        new_id = None\n        if \"id\" in kwargs:  # for setting up fixtures\n            new_id = kwargs.pop(\"id\")\n        else:  # find a new id\n            found_id = False\n            while not found_id:\n                new_id = random.randint(1, 9999)\n                if new_id not in collection:\n                    found_id = True\n        new_record = cls(id=new_id, **kwargs)\n        collection[new_id] = new_record\n        return new_record\n\n\nclass User(Model):\n    collection = \"users\"\n\n\ndb = {\"users\": {}}\n\n\n##### use_schema #####\n\n\ndef use_schema(schema, list_view=False, locations=None):\n    \"\"\"View decorator for using a marshmallow schema to\n        (1) parse a request's input and\n        (2) serializing the view's output to a JSON response.\n    \"\"\"\n\n    def decorator(func):\n        @functools.wraps(func)\n        def wrapped(*args, **kwargs):\n            use_args_wrapper = parser.use_args(schema, locations=locations)\n            # Function wrapped with use_args\n            func_with_args = use_args_wrapper(func)\n            ret = func_with_args(*args, **kwargs)\n            # Serialize and jsonify the return value\n            return jsonify(schema.dump(ret, many=list_view).data)\n\n        return wrapped\n\n    return decorator\n\n\n##### Schemas #####\n\n\nclass UserSchema(Schema):\n    id = fields.Int(dump_only=True)\n    username = fields.Str()\n    first_name = fields.Str()\n    last_name = fields.Str()\n\n    class Meta:\n        strict = True\n\n    @post_dump(pass_many=True)\n    def wrap_with_envelope(self, data, many, **kwargs):\n        return {\"data\": data}\n\n\n##### Routes #####\n\n\n@app.route(\"/users/<int:user_id>\", methods=[\"GET\", \"PATCH\"])\n@use_schema(UserSchema())\ndef user_detail(reqargs, user_id):\n    user = db[\"users\"].get(user_id)\n    if not user:\n        return jsonify({\"message\": \"User not found\"}), 404\n    if request.method == \"PATCH\" and reqargs:\n        user.update(**reqargs)\n    return user\n\n\n# You can add additional arguments with use_kwargs\n@app.route(\"/users/\", methods=[\"GET\", \"POST\"])\n@use_kwargs({\"limit\": fields.Int(missing=10, location=\"query\")})\n@use_schema(UserSchema(), list_view=True)\ndef user_list(reqargs, limit):\n    users = db[\"users\"].values()\n    if request.method == \"POST\":\n        User.insert(db=db, **reqargs)\n    return list(users)[:limit]\n\n\n# Return validation errors as JSON\n@app.errorhandler(422)\n@app.errorhandler(400)\ndef handle_validation_error(err):\n    exc = getattr(err, \"exc\", None)\n    if exc:\n        headers = err.data[\"headers\"]\n        messages = exc.messages\n    else:\n        headers = None\n        messages = [\"Invalid request.\"]\n    if headers:\n        return jsonify({\"errors\": messages}), err.code, headers\n    else:\n        return jsonify({\"errors\": messages}), err.code\n\n\nif __name__ == \"__main__\":\n    User.insert(\n        db=db, id=42, username=\"fred\", first_name=\"Freddie\", last_name=\"Mercury\"\n    )\n    app.run(port=5001, debug=True)\n", "path": "examples/schema_example.py"}], "after_files": [{"content": "\"\"\"Example implementation of using a marshmallow Schema for both request input\nand output with a `use_schema` decorator.\nRun the app:\n\n    $ python examples/schema_example.py\n\nTry the following with httpie (a cURL-like utility, http://httpie.org):\n\n    $ pip install httpie\n    $ http GET :5001/users/\n    $ http GET :5001/users/42\n    $ http POST :5001/users/ usename=brian first_name=Brian last_name=May\n    $ http PATCH :5001/users/42 username=freddie\n    $ http GET :5001/users/ limit==1\n\"\"\"\nimport functools\nfrom flask import Flask, request, jsonify\nimport random\n\nfrom marshmallow import Schema, fields, post_dump\nfrom webargs.flaskparser import parser, use_kwargs\n\napp = Flask(__name__)\n\n##### Fake database and models #####\n\n\nclass Model:\n    def __init__(self, **kwargs):\n        self.__dict__.update(kwargs)\n\n    def update(self, **kwargs):\n        self.__dict__.update(kwargs)\n\n    @classmethod\n    def insert(cls, db, **kwargs):\n        collection = db[cls.collection]\n        new_id = None\n        if \"id\" in kwargs:  # for setting up fixtures\n            new_id = kwargs.pop(\"id\")\n        else:  # find a new id\n            found_id = False\n            while not found_id:\n                new_id = random.randint(1, 9999)\n                if new_id not in collection:\n                    found_id = True\n        new_record = cls(id=new_id, **kwargs)\n        collection[new_id] = new_record\n        return new_record\n\n\nclass User(Model):\n    collection = \"users\"\n\n\ndb = {\"users\": {}}\n\n\n##### use_schema #####\n\n\ndef use_schema(schema, list_view=False, locations=None):\n    \"\"\"View decorator for using a marshmallow schema to\n        (1) parse a request's input and\n        (2) serializing the view's output to a JSON response.\n    \"\"\"\n\n    def decorator(func):\n        @functools.wraps(func)\n        def wrapped(*args, **kwargs):\n            use_args_wrapper = parser.use_args(schema, locations=locations)\n            # Function wrapped with use_args\n            func_with_args = use_args_wrapper(func)\n            ret = func_with_args(*args, **kwargs)\n            # Serialize and jsonify the return value\n            return jsonify(schema.dump(ret, many=list_view).data)\n\n        return wrapped\n\n    return decorator\n\n\n##### Schemas #####\n\n\nclass UserSchema(Schema):\n    id = fields.Int(dump_only=True)\n    username = fields.Str()\n    first_name = fields.Str()\n    last_name = fields.Str()\n\n    @post_dump(pass_many=True)\n    def wrap_with_envelope(self, data, many, **kwargs):\n        return {\"data\": data}\n\n\n##### Routes #####\n\n\n@app.route(\"/users/<int:user_id>\", methods=[\"GET\", \"PATCH\"])\n@use_schema(UserSchema())\ndef user_detail(reqargs, user_id):\n    user = db[\"users\"].get(user_id)\n    if not user:\n        return jsonify({\"message\": \"User not found\"}), 404\n    if request.method == \"PATCH\" and reqargs:\n        user.update(**reqargs)\n    return user\n\n\n# You can add additional arguments with use_kwargs\n@app.route(\"/users/\", methods=[\"GET\", \"POST\"])\n@use_kwargs({\"limit\": fields.Int(missing=10, location=\"query\")})\n@use_schema(UserSchema(), list_view=True)\ndef user_list(reqargs, limit):\n    users = db[\"users\"].values()\n    if request.method == \"POST\":\n        User.insert(db=db, **reqargs)\n    return list(users)[:limit]\n\n\n# Return validation errors as JSON\n@app.errorhandler(422)\n@app.errorhandler(400)\ndef handle_validation_error(err):\n    exc = getattr(err, \"exc\", None)\n    if exc:\n        headers = err.data[\"headers\"]\n        messages = exc.messages\n    else:\n        headers = None\n        messages = [\"Invalid request.\"]\n    if headers:\n        return jsonify({\"errors\": messages}), err.code, headers\n    else:\n        return jsonify({\"errors\": messages}), err.code\n\n\nif __name__ == \"__main__\":\n    User.insert(\n        db=db, id=42, username=\"fred\", first_name=\"Freddie\", last_name=\"Mercury\"\n    )\n    app.run(port=5001, debug=True)\n", "path": "examples/schema_example.py"}]}