Repository: jupyterhub/zero-to-jupyterhub-k8s

Issue:
extraConfigMap - get_config takes 0 positional arguments
[it sais in the docs](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/doc/source/advanced.md#hubextraconfigmap) I should be able to use the `get_config` function (defined in jupyterhub_config.py) within hub.extraConfig, but when I do, an error is thrown saying: `TypeError: get_config() takes 0 positional arguments but 1 was given`

I currently workaround this by copying the `get_config` definition from `jupyterhub_config.py` into `hub.extraConfig`.

---

__An excerpt from my `values.yaml`__

```yaml
    extraConfig: |
      # Useful functions duplicated from z2jh/images/hub/jupyterhub_config.py
      # See https://github.com/jupyterhub/zero-to-jupyterhub-k8s/issues/374
      # -----------------------------------------------------------------------
      import os
      import yaml

      def get_config(key, default=None):
          """
          Find a config item of a given name & return it

          Parses everything as YAML, so lists and dicts are available too
          """
          path = os.path.join('/etc/jupyterhub/config', key)
          try:
              with open(path) as f:
                  data = yaml.safe_load(f)
                  return data
          except FileNotFoundError:
              return default

      def get_secret(key, default=None):
          """Get a secret from /etc/jupyterhub/secret"""
          path = os.path.join('/etc/jupyterhub/secret', key)
          try:
              with open(path) as f:
                  return f.read().strip()
          except FileNotFoundError:
              return default
      # -----------------------------------------------------------------------
```



Discussion:
Ah whoops, it's because load_subconfig doesn't put the get_config and get_secret functions into the env of the files it is loading. Not sure how to fix that...

Resolving patch:
diff --git a/images/hub/jupyterhub_config.py b/images/hub/jupyterhub_config.py
--- a/images/hub/jupyterhub_config.py
+++ b/images/hub/jupyterhub_config.py
@@ -1,32 +1,8 @@
 import os
 import glob
-import sys
-import yaml
 from tornado.httpclient import AsyncHTTPClient
 
-def get_config(key, default=None):
-    """
-    Find a config item of a given name & return it
-
-    Parses everything as YAML, so lists and dicts are available too
-    """
-    path = os.path.join('/etc/jupyterhub/config', key)
-    try:
-        with open(path) as f:
-            data = yaml.safe_load(f)
-            return data
-    except FileNotFoundError:
-        return default
-
-def get_secret(key, default=None):
-    """Get a secret from /etc/jupyterhub/secret"""
-    path = os.path.join('/etc/jupyterhub/secret', key)
-    try:
-        with open(path) as f:
-            return f.read().strip()
-    except FileNotFoundError:
-        return default
-
+from z2jh import get_config, get_secret
 
 # Configure JupyterHub to use the curl backend for making HTTP requests,
 # rather than the pure-python implementations. The default one starts
diff --git a/images/hub/z2jh.py b/images/hub/z2jh.py
new file mode 100644
--- /dev/null
+++ b/images/hub/z2jh.py
@@ -0,0 +1,31 @@
+"""
+Utility methods for use in jupyterhub_config.py and dynamic subconfigs.
+
+Methods here can be imported by extraConfig in values.yaml
+"""
+import os
+import sys
+import yaml
+
+def get_config(key, default=None):
+    """
+    Find a config item of a given name & return it
+
+    Parses everything as YAML, so lists and dicts are available too
+    """
+    path = os.path.join('/etc/jupyterhub/config', key)
+    try:
+        with open(path) as f:
+            data = yaml.safe_load(f)
+            return data
+    except FileNotFoundError:
+        return default
+
+def get_secret(key, default=None):
+    """Get a secret from /etc/jupyterhub/secret"""
+    path = os.path.join('/etc/jupyterhub/secret', key)
+    try:
+        with open(path) as f:
+            return f.read().strip()
+    except FileNotFoundError:
+        return default


Test patch: