We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
CI: jupyter-server build fails since late september
The `test_singleuser_auth` step fails with the following error ([example failure](https://travis-ci.org/github/jupyterhub/jupyterhub/jobs/729518444))

```
404 Client Error: Not Found for url: http://127.0.0.1:59471/@/space%20word/user/nandy/api/spec.yaml?redirects=2
```

Has something change with regards to `@` symbols or spaces in words like `space word`? Yes it has, in `jupyter-server` it seems, because there have been releases in this time span.

![image](https://user-images.githubusercontent.com/3837114/94790428-9275a400-03d6-11eb-807f-1a174e1b3721.png)

## References
- [jupyter-server changelog](https://github.com/jupyter/jupyter_server/blob/master/CHANGELOG.md)
- [The only PR that I saw in the changelog with clear potential to cause our CI error](https://github.com/jupyter/jupyter_server/pull/304)
- [A seemingly related PR by, @minrk](https://github.com/jupyterhub/jupyterhub/pull/3168)
- [Another seemingly related PR, by @danlester](https://github.com/jupyterhub/jupyterhub/pull/3167)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `jupyterhub/traitlets.py`
Content:
```
1 """
2 Traitlets that are used in JupyterHub
3 """
4 # Copyright (c) Jupyter Development Team.
5 # Distributed under the terms of the Modified BSD License.
6 import entrypoints
7 from traitlets import Integer
8 from traitlets import List
9 from traitlets import TraitError
10 from traitlets import TraitType
11 from traitlets import Type
12 from traitlets import Unicode
13 
14 
15 class URLPrefix(Unicode):
16     def validate(self, obj, value):
17         u = super().validate(obj, value)
18         if not u.startswith('/'):
19             u = '/' + u
20         if not u.endswith('/'):
21             u = u + '/'
22         return u
23 
24 
25 class Command(List):
26     """Traitlet for a command that should be a list of strings,
27     but allows it to be specified as a single string.
28     """
29 
30     def __init__(self, default_value=None, **kwargs):
31         kwargs.setdefault('minlen', 1)
32         if isinstance(default_value, str):
33             default_value = [default_value]
34         super().__init__(Unicode(), default_value, **kwargs)
35 
36     def validate(self, obj, value):
37         if isinstance(value, str):
38             value = [value]
39         return super().validate(obj, value)
40 
41 
42 class ByteSpecification(Integer):
43     """
44     Allow easily specifying bytes in units of 1024 with suffixes
45 
46     Suffixes allowed are:
47       - K -> Kilobyte
48       - M -> Megabyte
49       - G -> Gigabyte
50       - T -> Terabyte
51     """
52 
53     UNIT_SUFFIXES = {
54         'K': 1024,
55         'M': 1024 * 1024,
56         'G': 1024 * 1024 * 1024,
57         'T': 1024 * 1024 * 1024 * 1024,
58     }
59 
60     # Default to allowing None as a value
61     allow_none = True
62 
63     def validate(self, obj, value):
64         """
65         Validate that the passed in value is a valid memory specification
66 
67         It could either be a pure int, when it is taken as a byte value.
68         If it has one of the suffixes, it is converted into the appropriate
69         pure byte value.
70         """
71         if isinstance(value, (int, float)):
72             return int(value)
73 
74         try:
75             num = float(value[:-1])
76         except ValueError:
77             raise TraitError(
78                 '{val} is not a valid memory specification. Must be an int or a string with suffix K, M, G, T'.format(
79                     val=value
80                 )
81             )
82         suffix = value[-1]
83         if suffix not in self.UNIT_SUFFIXES:
84             raise TraitError(
85                 '{val} is not a valid memory specification. Must be an int or a string with suffix K, M, G, T'.format(
86                     val=value
87                 )
88             )
89         else:
90             return int(float(num) * self.UNIT_SUFFIXES[suffix])
91 
92 
93 class Callable(TraitType):
94     """
95     A trait which is callable.
96 
97     Classes are callable, as are instances
98     with a __call__() method.
99     """
100 
101     info_text = 'a callable'
102 
103     def validate(self, obj, value):
104         if callable(value):
105             return value
106         else:
107             self.error(obj, value)
108 
109 
110 class EntryPointType(Type):
111     """Entry point-extended Type
112 
113     classes can be registered via entry points
114     in addition to standard 'mypackage.MyClass' strings
115     """
116 
117     _original_help = ''
118 
119     def __init__(self, *args, entry_point_group, **kwargs):
120         self.entry_point_group = entry_point_group
121         super().__init__(*args, **kwargs)
122 
123     @property
124     def help(self):
125         """Extend help by listing currently installed choices"""
126         chunks = [self._original_help]
127         chunks.append("Currently installed: ")
128         for key, entry_point in self.load_entry_points().items():
129             chunks.append(
130                 "  - {}: {}.{}".format(
131                     key, entry_point.module_name, entry_point.object_name
132                 )
133             )
134         return '\n'.join(chunks)
135 
136     @help.setter
137     def help(self, value):
138         self._original_help = value
139 
140     def load_entry_points(self):
141         """Load my entry point group"""
142         # load the group
143         group = entrypoints.get_group_named(self.entry_point_group)
144         # make it case-insensitive
145         return {key.lower(): value for key, value in group.items()}
146 
147     def validate(self, obj, value):
148         if isinstance(value, str):
149             # first, look up in entry point registry
150             registry = self.load_entry_points()
151             key = value.lower()
152             if key in registry:
153                 value = registry[key].load()
154         return super().validate(obj, value)
155
```
--- 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/jupyterhub/traitlets.py b/jupyterhub/traitlets.py
--- a/jupyterhub/traitlets.py
+++ b/jupyterhub/traitlets.py
@@ -9,6 +9,7 @@
 from traitlets import TraitError
 from traitlets import TraitType
 from traitlets import Type
+from traitlets import Undefined
 from traitlets import Unicode
 
 
@@ -27,11 +28,15 @@
     but allows it to be specified as a single string.
     """
 
-    def __init__(self, default_value=None, **kwargs):
+    def __init__(self, default_value=Undefined, **kwargs):
         kwargs.setdefault('minlen', 1)
         if isinstance(default_value, str):
             default_value = [default_value]
-        super().__init__(Unicode(), default_value, **kwargs)
+        if default_value is not Undefined and (
+            not (default_value is None and not kwargs.get("allow_none", False))
+        ):
+            kwargs["default_value"] = default_value
+        super().__init__(Unicode(), **kwargs)
 
     def validate(self, obj, value):
         if isinstance(value, str):

{"golden_diff": "diff --git a/jupyterhub/traitlets.py b/jupyterhub/traitlets.py\n--- a/jupyterhub/traitlets.py\n+++ b/jupyterhub/traitlets.py\n@@ -9,6 +9,7 @@\n from traitlets import TraitError\n from traitlets import TraitType\n from traitlets import Type\n+from traitlets import Undefined\n from traitlets import Unicode\n \n \n@@ -27,11 +28,15 @@\n     but allows it to be specified as a single string.\n     \"\"\"\n \n-    def __init__(self, default_value=None, **kwargs):\n+    def __init__(self, default_value=Undefined, **kwargs):\n         kwargs.setdefault('minlen', 1)\n         if isinstance(default_value, str):\n             default_value = [default_value]\n-        super().__init__(Unicode(), default_value, **kwargs)\n+        if default_value is not Undefined and (\n+            not (default_value is None and not kwargs.get(\"allow_none\", False))\n+        ):\n+            kwargs[\"default_value\"] = default_value\n+        super().__init__(Unicode(), **kwargs)\n \n     def validate(self, obj, value):\n         if isinstance(value, str):\n", "issue": "CI: jupyter-server build fails since late september\nThe `test_singleuser_auth` step fails with the following error ([example failure](https://travis-ci.org/github/jupyterhub/jupyterhub/jobs/729518444))\r\n\r\n```\r\n404 Client Error: Not Found for url: http://127.0.0.1:59471/@/space%20word/user/nandy/api/spec.yaml?redirects=2\r\n```\r\n\r\nHas something change with regards to `@` symbols or spaces in words like `space word`? Yes it has, in `jupyter-server` it seems, because there have been releases in this time span.\r\n\r\n![image](https://user-images.githubusercontent.com/3837114/94790428-9275a400-03d6-11eb-807f-1a174e1b3721.png)\r\n\r\n## References\r\n- [jupyter-server changelog](https://github.com/jupyter/jupyter_server/blob/master/CHANGELOG.md)\r\n- [The only PR that I saw in the changelog with clear potential to cause our CI error](https://github.com/jupyter/jupyter_server/pull/304)\r\n- [A seemingly related PR by, @minrk](https://github.com/jupyterhub/jupyterhub/pull/3168)\r\n- [Another seemingly related PR, by @danlester](https://github.com/jupyterhub/jupyterhub/pull/3167)\n", "before_files": [{"content": "\"\"\"\nTraitlets that are used in JupyterHub\n\"\"\"\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nimport entrypoints\nfrom traitlets import Integer\nfrom traitlets import List\nfrom traitlets import TraitError\nfrom traitlets import TraitType\nfrom traitlets import Type\nfrom traitlets import Unicode\n\n\nclass URLPrefix(Unicode):\n    def validate(self, obj, value):\n        u = super().validate(obj, value)\n        if not u.startswith('/'):\n            u = '/' + u\n        if not u.endswith('/'):\n            u = u + '/'\n        return u\n\n\nclass Command(List):\n    \"\"\"Traitlet for a command that should be a list of strings,\n    but allows it to be specified as a single string.\n    \"\"\"\n\n    def __init__(self, default_value=None, **kwargs):\n        kwargs.setdefault('minlen', 1)\n        if isinstance(default_value, str):\n            default_value = [default_value]\n        super().__init__(Unicode(), default_value, **kwargs)\n\n    def validate(self, obj, value):\n        if isinstance(value, str):\n            value = [value]\n        return super().validate(obj, value)\n\n\nclass ByteSpecification(Integer):\n    \"\"\"\n    Allow easily specifying bytes in units of 1024 with suffixes\n\n    Suffixes allowed are:\n      - K -> Kilobyte\n      - M -> Megabyte\n      - G -> Gigabyte\n      - T -> Terabyte\n    \"\"\"\n\n    UNIT_SUFFIXES = {\n        'K': 1024,\n        'M': 1024 * 1024,\n        'G': 1024 * 1024 * 1024,\n        'T': 1024 * 1024 * 1024 * 1024,\n    }\n\n    # Default to allowing None as a value\n    allow_none = True\n\n    def validate(self, obj, value):\n        \"\"\"\n        Validate that the passed in value is a valid memory specification\n\n        It could either be a pure int, when it is taken as a byte value.\n        If it has one of the suffixes, it is converted into the appropriate\n        pure byte value.\n        \"\"\"\n        if isinstance(value, (int, float)):\n            return int(value)\n\n        try:\n            num = float(value[:-1])\n        except ValueError:\n            raise TraitError(\n                '{val} is not a valid memory specification. Must be an int or a string with suffix K, M, G, T'.format(\n                    val=value\n                )\n            )\n        suffix = value[-1]\n        if suffix not in self.UNIT_SUFFIXES:\n            raise TraitError(\n                '{val} is not a valid memory specification. Must be an int or a string with suffix K, M, G, T'.format(\n                    val=value\n                )\n            )\n        else:\n            return int(float(num) * self.UNIT_SUFFIXES[suffix])\n\n\nclass Callable(TraitType):\n    \"\"\"\n    A trait which is callable.\n\n    Classes are callable, as are instances\n    with a __call__() method.\n    \"\"\"\n\n    info_text = 'a callable'\n\n    def validate(self, obj, value):\n        if callable(value):\n            return value\n        else:\n            self.error(obj, value)\n\n\nclass EntryPointType(Type):\n    \"\"\"Entry point-extended Type\n\n    classes can be registered via entry points\n    in addition to standard 'mypackage.MyClass' strings\n    \"\"\"\n\n    _original_help = ''\n\n    def __init__(self, *args, entry_point_group, **kwargs):\n        self.entry_point_group = entry_point_group\n        super().__init__(*args, **kwargs)\n\n    @property\n    def help(self):\n        \"\"\"Extend help by listing currently installed choices\"\"\"\n        chunks = [self._original_help]\n        chunks.append(\"Currently installed: \")\n        for key, entry_point in self.load_entry_points().items():\n            chunks.append(\n                \"  - {}: {}.{}\".format(\n                    key, entry_point.module_name, entry_point.object_name\n                )\n            )\n        return '\\n'.join(chunks)\n\n    @help.setter\n    def help(self, value):\n        self._original_help = value\n\n    def load_entry_points(self):\n        \"\"\"Load my entry point group\"\"\"\n        # load the group\n        group = entrypoints.get_group_named(self.entry_point_group)\n        # make it case-insensitive\n        return {key.lower(): value for key, value in group.items()}\n\n    def validate(self, obj, value):\n        if isinstance(value, str):\n            # first, look up in entry point registry\n            registry = self.load_entry_points()\n            key = value.lower()\n            if key in registry:\n                value = registry[key].load()\n        return super().validate(obj, value)\n", "path": "jupyterhub/traitlets.py"}], "after_files": [{"content": "\"\"\"\nTraitlets that are used in JupyterHub\n\"\"\"\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nimport entrypoints\nfrom traitlets import Integer\nfrom traitlets import List\nfrom traitlets import TraitError\nfrom traitlets import TraitType\nfrom traitlets import Type\nfrom traitlets import Undefined\nfrom traitlets import Unicode\n\n\nclass URLPrefix(Unicode):\n    def validate(self, obj, value):\n        u = super().validate(obj, value)\n        if not u.startswith('/'):\n            u = '/' + u\n        if not u.endswith('/'):\n            u = u + '/'\n        return u\n\n\nclass Command(List):\n    \"\"\"Traitlet for a command that should be a list of strings,\n    but allows it to be specified as a single string.\n    \"\"\"\n\n    def __init__(self, default_value=Undefined, **kwargs):\n        kwargs.setdefault('minlen', 1)\n        if isinstance(default_value, str):\n            default_value = [default_value]\n        if default_value is not Undefined and (\n            not (default_value is None and not kwargs.get(\"allow_none\", False))\n        ):\n            kwargs[\"default_value\"] = default_value\n        super().__init__(Unicode(), **kwargs)\n\n    def validate(self, obj, value):\n        if isinstance(value, str):\n            value = [value]\n        return super().validate(obj, value)\n\n\nclass ByteSpecification(Integer):\n    \"\"\"\n    Allow easily specifying bytes in units of 1024 with suffixes\n\n    Suffixes allowed are:\n      - K -> Kilobyte\n      - M -> Megabyte\n      - G -> Gigabyte\n      - T -> Terabyte\n    \"\"\"\n\n    UNIT_SUFFIXES = {\n        'K': 1024,\n        'M': 1024 * 1024,\n        'G': 1024 * 1024 * 1024,\n        'T': 1024 * 1024 * 1024 * 1024,\n    }\n\n    # Default to allowing None as a value\n    allow_none = True\n\n    def validate(self, obj, value):\n        \"\"\"\n        Validate that the passed in value is a valid memory specification\n\n        It could either be a pure int, when it is taken as a byte value.\n        If it has one of the suffixes, it is converted into the appropriate\n        pure byte value.\n        \"\"\"\n        if isinstance(value, (int, float)):\n            return int(value)\n\n        try:\n            num = float(value[:-1])\n        except ValueError:\n            raise TraitError(\n                '{val} is not a valid memory specification. Must be an int or a string with suffix K, M, G, T'.format(\n                    val=value\n                )\n            )\n        suffix = value[-1]\n        if suffix not in self.UNIT_SUFFIXES:\n            raise TraitError(\n                '{val} is not a valid memory specification. Must be an int or a string with suffix K, M, G, T'.format(\n                    val=value\n                )\n            )\n        else:\n            return int(float(num) * self.UNIT_SUFFIXES[suffix])\n\n\nclass Callable(TraitType):\n    \"\"\"\n    A trait which is callable.\n\n    Classes are callable, as are instances\n    with a __call__() method.\n    \"\"\"\n\n    info_text = 'a callable'\n\n    def validate(self, obj, value):\n        if callable(value):\n            return value\n        else:\n            self.error(obj, value)\n\n\nclass EntryPointType(Type):\n    \"\"\"Entry point-extended Type\n\n    classes can be registered via entry points\n    in addition to standard 'mypackage.MyClass' strings\n    \"\"\"\n\n    _original_help = ''\n\n    def __init__(self, *args, entry_point_group, **kwargs):\n        self.entry_point_group = entry_point_group\n        super().__init__(*args, **kwargs)\n\n    @property\n    def help(self):\n        \"\"\"Extend help by listing currently installed choices\"\"\"\n        chunks = [self._original_help]\n        chunks.append(\"Currently installed: \")\n        for key, entry_point in self.load_entry_points().items():\n            chunks.append(\n                \"  - {}: {}.{}\".format(\n                    key, entry_point.module_name, entry_point.object_name\n                )\n            )\n        return '\\n'.join(chunks)\n\n    @help.setter\n    def help(self, value):\n        self._original_help = value\n\n    def load_entry_points(self):\n        \"\"\"Load my entry point group\"\"\"\n        # load the group\n        group = entrypoints.get_group_named(self.entry_point_group)\n        # make it case-insensitive\n        return {key.lower(): value for key, value in group.items()}\n\n    def validate(self, obj, value):\n        if isinstance(value, str):\n            # first, look up in entry point registry\n            registry = self.load_entry_points()\n            key = value.lower()\n            if key in registry:\n                value = registry[key].load()\n        return super().validate(obj, value)\n", "path": "jupyterhub/traitlets.py"}]}