    def options_from_query(self, query_data):
        """Interpret query arguments passed to /spawn

        Query arguments will always arrive as a dict of unicode strings.
        Override this function to understand single-values, numbers, etc.

        By default, options_from_form is called from this function. You can however override
        this function if you need to process the query arguments differently.

        This should coerce form data into the structure expected by self.user_options,
        which must be a dict, and should be JSON-serializeable,
        though it can contain bytes in addition to standard JSON data types.

        This method should not have any side effects.
        Any handling of `user_options` should be done in `.start()`
        to ensure consistent behavior across servers
        spawned via the API and form submission page.

        Instances will receive this data on self.user_options, after passing through this function,
        prior to `Spawner.start`.

        .. versionadded:: 1.2
            user_options are persisted in the JupyterHub database to be reused
            on subsequent spawns if no options are given.
            user_options is serialized to JSON as part of this persistence
            (with additional support for bytes in case of uploaded file data),
            and any non-bytes non-jsonable values will be replaced with None
            if the user_options are re-used.
        """
        return self.options_from_form(query_data)
Interpret query arguments passed to /spawn

Query arguments will always arrive as a dict of unicode strings.
Override this function to understand single-values, numbers, etc.

By default, options_from_form is called from this function. You can however override
this function if you need to process the query arguments differently.

This should coerce form data into the structure expected by self.user_options,
which must be a dict, and should be JSON-serializeable,
though it can contain bytes in addition to standard JSON data types.

This method should not have any side effects.
Any handling of `user_options` should be done in `.start()`
to ensure consistent behavior across servers
spawned via the API and form submission page.

Instances will receive this data on self.user_options, after passing through this function,
prior to `Spawner.start`.

.. versionadded:: 1.2
user_options are persisted in the JupyterHub database to be reused
on subsequent spawns if no options are given.
user_options is serialized to JSON as part of this persistence
(with additional support for bytes in case of uploaded file data),
and any non-bytes non-jsonable values will be replaced with None
if the user_options are re-used.
jupyterhub/spawner.py