diff --git a/remoteappmanager/command_line_config.py b/remoteappmanager/command_line_config.py index 3e68a7cdf..894bcbee0 100644 --- a/remoteappmanager/command_line_config.py +++ b/remoteappmanager/command_line_config.py @@ -3,7 +3,7 @@ from traitlets import HasTraits, Int, Unicode -from remoteappmanager.utils import with_end_slash +from remoteappmanager.utils import with_end_slash, remove_quotes from remoteappmanager.traitlets import set_traits_from_dict @@ -62,7 +62,13 @@ def parse_config(self): tornado.options.parse_command_line() - set_traits_from_dict(self, options.as_dict()) + # Workaround for change in jupyterhub 0.7.0. + # Args are passed with quotes, that are preserved in the arguments when + # we retrieve them. We just get rid of the quotes, until a better + # solution comes along. + # See jupyterhub/jupyterhub#836 for details. + opts = {k: remove_quotes(v) for k, v in options.as_dict().items()} + set_traits_from_dict(self, opts) # Normalize the base_urlpath to end with a slash self.base_urlpath = with_end_slash(self.base_urlpath) diff --git a/remoteappmanager/jupyterhub/tests/test_spawners.py b/remoteappmanager/jupyterhub/tests/test_spawners.py index b2fb73423..ec8fa729f 100644 --- a/remoteappmanager/jupyterhub/tests/test_spawners.py +++ b/remoteappmanager/jupyterhub/tests/test_spawners.py @@ -78,13 +78,13 @@ def test_args(self): args = self.spawner.get_args() self.assertIn("--proxy-api-url=http://127.0.0.1:12345/foo/bar/", args) self.assertIn("--config-file={}".format(path), args) - self.assertIn("--base-urlpath=/", args) + self.assertIn("--base-urlpath=\"/\"", args) def test_args_without_config_file_path(self): args = self.spawner.get_args() self.assertIn("--proxy-api-url=http://127.0.0.1:12345/foo/bar/", args) self.assertFalse(any("--config-file=" in arg for arg in args)) - self.assertIn("--base-urlpath=/", args) + self.assertIn("--base-urlpath=\"/\"", args) def test_cmd(self): self.assertEqual(self.spawner.cmd, ['remoteappmanager']) diff --git a/remoteappmanager/tests/test_command_line_config.py b/remoteappmanager/tests/test_command_line_config.py index e194e61f4..09e865694 100644 --- a/remoteappmanager/tests/test_command_line_config.py +++ b/remoteappmanager/tests/test_command_line_config.py @@ -1,7 +1,7 @@ import unittest from remoteappmanager.command_line_config import CommandLineConfig -from remoteappmanager.utils import with_end_slash +from remoteappmanager.utils import with_end_slash, remove_quotes # The arguments we pass from remoteappmanager.tests.utils import arguments, invocation_argv @@ -19,7 +19,10 @@ def setUp(self): def test_initialization(self): for key, value in arguments.items(): if key == "base-urlpath": - value = with_end_slash(value) + value = with_end_slash(remove_quotes(value)) self.assertEqual(getattr(self.config, key.replace("-", "_")), value) + + def test_base_urlpath(self): + self.assertEqual(self.config.base_urlpath, "/user/username/") diff --git a/remoteappmanager/tests/test_utils.py b/remoteappmanager/tests/test_utils.py index 2eb172392..424df784a 100644 --- a/remoteappmanager/tests/test_utils.py +++ b/remoteappmanager/tests/test_utils.py @@ -27,3 +27,10 @@ def foo(self): """two""" self.assertEqual(Derived.foo.__doc__, "one\ntwo") + + def test_remove_quotes(self): + self.assertEqual(utils.remove_quotes('"foo bar"'), "foo bar") + self.assertEqual(utils.remove_quotes('foo'), "foo") + self.assertEqual(utils.remove_quotes('f'), "f") + self.assertEqual(utils.remove_quotes(''), "") + self.assertEqual(utils.remove_quotes('"'), '"') diff --git a/remoteappmanager/tests/utils.py b/remoteappmanager/tests/utils.py index d24df5288..30715c947 100644 --- a/remoteappmanager/tests/utils.py +++ b/remoteappmanager/tests/utils.py @@ -11,13 +11,14 @@ from remoteappmanager.environment_config import EnvironmentConfig from remoteappmanager.db.orm import Database from remoteappmanager.tests import fixtures +from remoteappmanager.utils import remove_quotes -# A set of viable start arguments +# A set of viable start arguments. As they would arrive from outside arguments = { "user": "username", "port": 57022, "cookie-name": "jupyter-hub-token-username", - "base-urlpath": "/user/username/", + "base-urlpath": "\"/user/username/\"", "hub-host": "", "hub-prefix": "/hub/", "hub-api-url": "http://172.17.5.167:8081/hub/api", @@ -38,7 +39,8 @@ def basic_command_line_config(): """Returns a basic application config for testing purposes. The database is in memory. """ - options = {k.replace("-", "_"): v for k, v in arguments.items()} + options = {k.replace("-", "_"): remove_quotes(v) + for k, v in arguments.items()} return CommandLineConfig(**options) diff --git a/remoteappmanager/utils.py b/remoteappmanager/utils.py index 7c80dbdd6..dd3058e3d 100644 --- a/remoteappmanager/utils.py +++ b/remoteappmanager/utils.py @@ -83,3 +83,19 @@ def __call__(self, cls): def one(elements): """Returns True if only one element is not None, false otherwise""" return sum([False if e is None else True for e in elements]) == 1 + + +def remove_quotes(s): + """Removes start/end quotes from a string, if needed. + If s is not a string, it is returned untouched. + """ + if not isinstance(s, str): + return s + + if len(s) < 2: + return s + + if s[0]+s[-1] in ['""', "''"]: + return s[1:-1] + + return s diff --git a/requirements.txt b/requirements.txt index 8562b70fe..8facead03 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ requests==2.10.0 docker-py==1.8 escapism==0.0.1 jinja2==2.8 -git+git://github.com/jupyterhub/jupyterhub.git@42a993fd084780ad23e475f27f67ade3ae68d801#egg=jupyterhub +git+git://github.com/jupyterhub/jupyterhub.git@0.7.2#egg=jupyterhub jupyter_client==4.3.0 click==6.6 tabulate==0.7.5 diff --git a/setup.py b/setup.py index f2bd77690..917a0e85b 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ requirements.extend(["sqlalchemy>=1.0"]) else: requirements.extend([ - "jupyterhub>=0.7.0dev0", + "jupyterhub~=0.7", "docker-py==1.8", "tornadowebapi>=0.4.2"])