Repository: glotzerlab/signac

Issue:
Make config module internal
The config.py module no longer contains any public APIs. The only publicly visible items are the constants `PROJECT_CONFIG_FN` and `USER_CONFIG_FN`. Should we change this module to `_config`? If so, do we want to keep those two variables public so that users can easily and programmatically see where to expect signac's config files to be stored? To do so I would suggest importing those into `signac/__init__.py` and adding them to `__all__` in that package.

Discussion:

Patch:
diff --git a/changelog.txt b/changelog.txt
index 9baa08f3..24e74b2b 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -54,7 +54,7 @@ Removed
  - The ability to pass indexes to various ``Project`` methods (#599).
  - The following ``JobsCursor`` methods: ``groupbydoc``, ``next`` (#601, #604).
  - The ``Project.config`` property is no longer mutable. Use the command line ``$ signac config`` to modify configuration (#608, #246, #244).
- - The following config related functions: ``get_config``, ``load_config``, ``read_config_file``, ``search_standard_dirs`` (#674, #753, #789, #847).
+ - The config module and all its functions, all of which have been made private (#674, #753, #789, #847, #877).
  - ``Project`` subclasses can no longer define a ``Job`` subclass to use (#588, #693).
  - The ``Collection`` class (#664, #667, #683).
  - The ``project`` CLI subcommand (#752).
diff --git a/signac/__main__.py b/signac/__main__.py
index b18f54c8..7211be8e 100644
--- a/signac/__main__.py
+++ b/signac/__main__.py
@@ -29,7 +29,15 @@ except ImportError:
 else:
     READLINE = True
 
-from . import config, get_project, init_project
+from . import get_project, init_project
+from ._config import (
+    PROJECT_CONFIG_FN,
+    USER_CONFIG_FN,
+    _Config,
+    _load_config,
+    _locate_config_dir,
+    _read_config_file,
+)
 from ._utility import _add_verbosity_argument, _print_err, _query_yes_no, _safe_relpath
 from ._vendor.configobj import Section, flatten_errors
 from .diff import diff_jobs
@@ -663,12 +671,12 @@ def main_config_show(args):
     if args.local and args.globalcfg:
         raise ValueError("You can specify either -l/--local or -g/--global, not both.")
     elif args.local:
-        if os.path.isfile(config.PROJECT_CONFIG_FN):
-            cfg = config._read_config_file(config.PROJECT_CONFIG_FN)
+        if os.path.isfile(PROJECT_CONFIG_FN):
+            cfg = _read_config_file(PROJECT_CONFIG_FN)
     elif args.globalcfg:
-        cfg = config._read_config_file(config.USER_CONFIG_FN)
+        cfg = _read_config_file(USER_CONFIG_FN)
     else:
-        cfg = config._load_config(config._locate_config_dir(os.getcwd()))
+        cfg = _load_config(_locate_config_dir(os.getcwd()))
     if not cfg:
         if args.local:
             mode = "local"
@@ -686,7 +694,7 @@ def main_config_show(args):
     if not isinstance(cfg, Section):
         print(cfg)
     else:
-        for line in config._Config(cfg).write():
+        for line in _Config(cfg).write():
             print(line)
 
 
@@ -717,12 +725,12 @@ def main_config_verify(args):
     if args.local and args.globalcfg:
         raise ValueError("You can specify either -l/--local or -g/--global, not both.")
     elif args.local:
-        if os.path.isfile(config.PROJECT_CONFIG_FN):
-            cfg = config._read_config_file(config.PROJECT_CONFIG_FN)
+        if os.path.isfile(PROJECT_CONFIG_FN):
+            cfg = _read_config_file(PROJECT_CONFIG_FN)
     elif args.globalcfg:
-        cfg = config._read_config_file(config.USER_CONFIG_FN)
+        cfg = _read_config_file(USER_CONFIG_FN)
     else:
-        cfg = config._load_config(config._locate_config_dir(os.getcwd()))
+        cfg = _load_config(_locate_config_dir(os.getcwd()))
     if not cfg:
         if args.local:
             mode = "local"
@@ -746,16 +754,16 @@ def main_config_set(args):
     if args.local and args.globalcfg:
         raise ValueError("You can specify either -l/--local or -g/--global, not both.")
     elif args.local:
-        if os.path.isfile(config.PROJECT_CONFIG_FN):
-            fn_config = config.PROJECT_CONFIG_FN
+        if os.path.isfile(PROJECT_CONFIG_FN):
+            fn_config = PROJECT_CONFIG_FN
     elif args.globalcfg:
-        fn_config = config.USER_CONFIG_FN
+        fn_config = USER_CONFIG_FN
     else:
         raise ValueError(
             "You need to specify either -l/--local or -g/--global "
             "to specify which configuration to modify."
         )
-    cfg = config._read_config_file(fn_config)
+    cfg = _read_config_file(fn_config)
     keys = args.key.split(".")
     if len(args.value) == 0:
         raise ValueError("No value argument provided!")
diff --git a/signac/config.py b/signac/_config.py
similarity index 100%
rename from signac/config.py
rename to signac/_config.py
diff --git a/signac/migration/v1_to_v2.py b/signac/migration/v1_to_v2.py
index e2da1e52..224c1d58 100644
--- a/signac/migration/v1_to_v2.py
+++ b/signac/migration/v1_to_v2.py
@@ -15,11 +15,10 @@ This migration involves the following changes:
 
 import os
 
-from signac._synced_collections.backends.collection_json import BufferedJSONAttrDict
-from signac._vendor import configobj
-from signac.config import _get_project_config_fn
-from signac.project import Project
-
+from .._config import _get_project_config_fn
+from .._synced_collections.backends.collection_json import BufferedJSONAttrDict
+from .._vendor import configobj
+from ..project import Project
 from .v0_to_v1 import _load_config_v1
 
 # A minimal v2 config.
diff --git a/signac/project.py b/signac/project.py
index fe43f5cb..54c76bf9 100644
--- a/signac/project.py
+++ b/signac/project.py
@@ -20,10 +20,7 @@ from multiprocessing.pool import ThreadPool
 from tempfile import TemporaryDirectory
 from threading import RLock
 
-from ._search_indexer import _SearchIndexer
-from ._synced_collections.backends.collection_json import BufferedJSONAttrDict
-from ._utility import _mkdir_p, _nested_dicts_to_dotted_keys, _split_and_print_progress
-from .config import (
+from ._config import (
     _Config,
     _get_project_config_fn,
     _load_config,
@@ -31,6 +28,9 @@ from .config import (
     _raise_if_older_schema,
     _read_config_file,
 )
+from ._search_indexer import _SearchIndexer
+from ._synced_collections.backends.collection_json import BufferedJSONAttrDict
+from ._utility import _mkdir_p, _nested_dicts_to_dotted_keys, _split_and_print_progress
 from .errors import (
     DestinationExistsError,
     IncompatibleSchemaVersion,


Test patch:
diff --git a/tests/test_job.py b/tests/test_job.py
index 3979461f..85df7de8 100644
--- a/tests/test_job.py
+++ b/tests/test_job.py
@@ -12,7 +12,8 @@ from tempfile import TemporaryDirectory
 
 import pytest
 
-import signac.config
+import signac
+from signac._config import _load_config
 from signac.errors import (
     DestinationExistsError,
     InvalidKeyError,
@@ -64,7 +65,7 @@ class TestJobBase:
         request.addfinalizer(self._tmp_dir.cleanup)
         self._tmp_pr = os.path.join(self._tmp_dir.name, "pr")
         os.mkdir(self._tmp_pr)
-        self.config = signac.config._load_config()
+        self.config = _load_config()
         self.project = self.project_class.init_project(path=self._tmp_pr)
 
     def tearDown(self):
diff --git a/tests/test_project.py b/tests/test_project.py
index e5c9cca6..42b860b3 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -22,7 +22,7 @@ from packaging import version
 from test_job import TestJobBase
 
 import signac
-from signac.config import (
+from signac._config import (
     PROJECT_CONFIG_FN,
     _get_project_config_fn,
     _load_config,
diff --git a/tests/test_shell.py b/tests/test_shell.py
index 83fd1d37..073223e7 100644
--- a/tests/test_shell.py
+++ b/tests/test_shell.py
@@ -12,7 +12,7 @@ import pytest
 from test_project import _initialize_v1_project
 
 import signac
-from signac import config
+from signac._config import USER_CONFIG_FN, _Config, _load_config, _read_config_file
 
 # Skip linked view tests on Windows
 WINDOWS = sys.platform == "win32"
@@ -743,18 +743,18 @@ class TestBasicShell:
 
         self.call("python -m signac init".split())
         out = self.call("python -m signac config --local show".split()).strip()
-        cfg = config._read_config_file(".signac/config")
-        expected = config._Config(cfg).write()
+        cfg = _read_config_file(".signac/config")
+        expected = _Config(cfg).write()
         assert out.split(os.linesep) == expected
 
         out = self.call("python -m signac config show".split()).strip()
-        cfg = config._load_config()
-        expected = config._Config(cfg).write()
+        cfg = _load_config()
+        expected = _Config(cfg).write()
         assert out.split(os.linesep) == expected
 
         out = self.call("python -m signac config --global show".split()).strip()
-        cfg = config._read_config_file(config.USER_CONFIG_FN)
-        expected = config._Config(cfg).write()
+        cfg = _read_config_file(USER_CONFIG_FN)
+        expected = _Config(cfg).write()
         assert out.split(os.linesep) == expected
 
     def test_config_set(self):
@@ -769,12 +769,12 @@ class TestBasicShell:
         assert "[x]" in cfg
         assert "y = z" in cfg
 
-        backup_config = os.path.exists(config.USER_CONFIG_FN)
-        global_config_path_backup = config.USER_CONFIG_FN + ".tmp"
+        backup_config = os.path.exists(USER_CONFIG_FN)
+        global_config_path_backup = USER_CONFIG_FN + ".tmp"
         try:
             # Make a backup of the global config if it exists
             if backup_config:
-                shutil.copy2(config.USER_CONFIG_FN, global_config_path_backup)
+                shutil.copy2(USER_CONFIG_FN, global_config_path_backup)
 
             # Test the global config CLI
             self.call("python -m signac config --global set b c".split())
@@ -785,9 +785,9 @@ class TestBasicShell:
             # Revert the global config to its previous state (or remove it if
             # it did not exist)
             if backup_config:
-                shutil.move(global_config_path_backup, config.USER_CONFIG_FN)
+                shutil.move(global_config_path_backup, USER_CONFIG_FN)
             else:
-                os.remove(config.USER_CONFIG_FN)
+                os.remove(USER_CONFIG_FN)
 
     def test_config_verify(self):
         # no config file