Repository: jupyterhub/jupyterhub

Issue:
Fix docs on services
The docs for services say that you can set a key 'env' with a dict in order to update the environment variables for services. In fact, the key should be 'environment' not 'env'. 


Discussion:
Thanks, would you like to make a PR with the fix?

Resolving patch:
diff --git a/jupyterhub/app.py b/jupyterhub/app.py
--- a/jupyterhub/app.py
+++ b/jupyterhub/app.py
@@ -146,18 +146,18 @@ def start(self):
 
 class UpgradeDB(Application):
     """Upgrade the JupyterHub database schema."""
-    
+
     name = 'jupyterhub-upgrade-db'
     version = jupyterhub.__version__
     description = """Upgrade the JupyterHub database to the current schema.
-    
+
     Usage:
 
         jupyterhub upgrade-db
     """
     aliases = common_aliases
     classes = []
-    
+
     def _backup_db_file(self, db_file):
         """Backup a database file"""
         if not os.path.exists(db_file):
@@ -171,7 +171,7 @@ def _backup_db_file(self, db_file):
             backup_db_file = '{}.{}.{}'.format(db_file, timestamp, i)
         if os.path.exists(backup_db_file):
             self.exit("backup db file already exists: %s" % backup_db_file)
-        
+
         self.log.info("Backing up %s => %s", db_file, backup_db_file)
         shutil.copy(db_file, backup_db_file)
 
@@ -222,12 +222,12 @@ class JupyterHub(Application):
         Authenticator,
         PAMAuthenticator,
     ])
-    
+
     load_groups = Dict(List(Unicode()),
         help="""Dict of 'group': ['usernames'] to load at startup.
-        
+
         This strictly *adds* groups and users to groups.
-        
+
         Loading one set of groups, then starting JupyterHub again with a different
         set will not remove users or groups from previous launches.
         That must be done through the API.
@@ -414,7 +414,7 @@ def _update_hub_prefix(self, change):
 
     api_tokens = Dict(Unicode(),
         help="""PENDING DEPRECATION: consider using service_tokens
-        
+
         Dict of token:username to be loaded into the database.
 
         Allows ahead-of-time generation of API tokens for use by externally managed services,
@@ -437,14 +437,14 @@ def _deprecate_api_tokens(self, change):
         Allows ahead-of-time generation of API tokens for use by externally managed services.
         """
     ).tag(config=True)
-    
+
     services = List(Dict(),
         help="""List of service specification dictionaries.
-        
+
         A service
-        
+
         For instance::
-        
+
             services = [
                 {
                     'name': 'cull_idle',
@@ -454,7 +454,7 @@ def _deprecate_api_tokens(self, change):
                     'name': 'formgrader',
                     'url': 'http://127.0.0.1:1234',
                     'token': 'super-secret',
-                    'env': 
+                    'environment': 
                 }
             ]
         """
@@ -608,7 +608,7 @@ def _log_format_default(self):
         Instance(logging.Handler),
         help="Extra log handlers to set on JupyterHub logger",
     ).tag(config=True)
-    
+
     statsd = Any(allow_none=False, help="The statsd client, if any. A mock will be used if we aren't using statsd")
     @default('statsd')
     def _statsd(self):
@@ -919,7 +919,7 @@ def init_users(self):
         # The whitelist set and the users in the db are now the same.
         # From this point on, any user changes should be done simultaneously
         # to the whitelist set and user db, unless the whitelist is empty (all users allowed).
-    
+
     @gen.coroutine
     def init_groups(self):
         """Load predefined groups into the database"""
@@ -941,7 +941,7 @@ def init_groups(self):
                     db.add(user)
                 group.users.append(user)
         db.commit()
-    
+
     @gen.coroutine
     def _add_tokens(self, token_dict, kind):
         """Add tokens for users or services to the database"""
@@ -982,13 +982,13 @@ def _add_tokens(self, token_dict, kind):
             else:
                 self.log.debug("Not duplicating token %s", orm_token)
         db.commit()
-    
+
     @gen.coroutine
     def init_api_tokens(self):
         """Load predefined API tokens (for services) into database"""
         yield self._add_tokens(self.service_tokens, kind='service')
         yield self._add_tokens(self.api_tokens, kind='user')
-    
+
     def init_services(self):
         self._service_map.clear()
         if self.domain:
@@ -1458,7 +1458,7 @@ def start(self):
         except Exception as e:
             self.log.critical("Failed to start proxy", exc_info=True)
             self.exit(1)
-        
+
         for service_name, service in self._service_map.items():
             if not service.managed:
                 continue
diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py
--- a/jupyterhub/services/service.py
+++ b/jupyterhub/services/service.py
@@ -70,12 +70,12 @@ class _MockUser(HasTraits):
 
 class _ServiceSpawner(LocalProcessSpawner):
     """Subclass of LocalProcessSpawner
-    
+
     Removes notebook-specific-ness from LocalProcessSpawner.
     """
     cwd = Unicode()
     cmd = Command(minlen=0)
-    
+
     def make_preexec_fn(self, name):
         if not name or name == getuser():
             # no setuid if no name
@@ -116,25 +116,25 @@ class Service(LoggingConfigurable):
     - url: str (None)
         The URL where the service is/should be.
         If specified, the service will be added to the proxy at /services/:name
-    
+
     If a service is to be managed by the Hub, it has a few extra options:
-    
+
     - command: (str/Popen list)
         Command for JupyterHub to spawn the service.
         Only use this if the service should be a subprocess.
         If command is not specified, it is assumed to be managed
         by a
-    - env: dict
-        environment variables to add to the current env
+    - environment: dict
+        Additional environment variables for the service.
     - user: str
         The name of a system user to become.
         If unspecified, run as the same user as the Hub.
     """
-    
+
     # inputs:
     name = Unicode(
         help="""The name of the service.
-        
+
         If the service has an http endpoint, it
         """
     ).tag(input=True)
@@ -143,14 +143,14 @@ class Service(LoggingConfigurable):
     ).tag(input=True)
     url = Unicode(
         help="""URL of the service.
-        
+
         Only specify if the service runs an HTTP(s) endpoint that.
         If managed, will be passed as JUPYTERHUB_SERVICE_URL env.
         """
     ).tag(input=True)
     api_token = Unicode(
         help="""The API token to use for the service.
-        
+
         If unspecified, an API token will be generated for managed services.
         """
     ).tag(input=True)


Test patch: