Repository: python-gitlab/python-gitlab

Issue:
Handle missing config file
## Description of the problem, including code/CLI snippet

When '~/.python-gitlab.cfg' is missing, an full traceback is printed

## Expected Behavior

Create a default '~/.python-gitlab.cfg' file and print
"The tool is not configured yet. Edit ~/.python-gitlab.cfg and run the command again"

## Actual Behavior

See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=912537

## Specifications

  - python-gitlab version: 1.6.0




Discussion:

Resolving patch:
diff --git a/gitlab/cli.py b/gitlab/cli.py
--- a/gitlab/cli.py
+++ b/gitlab/cli.py
@@ -17,6 +17,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 from __future__ import print_function
+
 import argparse
 import functools
 import importlib
@@ -143,9 +144,13 @@ def main():
     # load the propermodule (v3 or v4) accordingly. At that point we don't have
     # any subparser setup
     (options, args) = parser.parse_known_args(sys.argv)
-
-    config = gitlab.config.GitlabConfigParser(options.gitlab,
-                                              options.config_file)
+    try:
+        config = gitlab.config.GitlabConfigParser(
+            options.gitlab,
+            options.config_file
+        )
+    except gitlab.config.ConfigError as e:
+        sys.exit(e)
     cli_module = importlib.import_module('gitlab.v%s.cli' % config.api_version)
 
     # Now we build the entire set of subcommands and do the complete parsing
diff --git a/gitlab/config.py b/gitlab/config.py
--- a/gitlab/config.py
+++ b/gitlab/config.py
@@ -37,10 +37,27 @@ class GitlabDataError(ConfigError):
     pass
 
 
+class GitlabConfigMissingError(ConfigError):
+    pass
+
+
 class GitlabConfigParser(object):
     def __init__(self, gitlab_id=None, config_files=None):
         self.gitlab_id = gitlab_id
         _files = config_files or _DEFAULT_FILES
+        file_exist = False
+        for file in _files:
+            if os.path.exists(file):
+                file_exist = True
+        if not file_exist:
+            raise GitlabConfigMissingError(
+                "Config file not found. \nPlease create one in "
+                "one of the following locations: {} \nor "
+                "specify a config file using the '-c' parameter.".format(
+                    ", ".join(_DEFAULT_FILES)
+                )
+            )
+
         self._config = configparser.ConfigParser()
         self._config.read(_files)
 


Test patch:
diff --git a/gitlab/tests/test_config.py b/gitlab/tests/test_config.py
--- a/gitlab/tests/test_config.py
+++ b/gitlab/tests/test_config.py
@@ -76,11 +76,20 @@
 
 
 class TestConfigParser(unittest.TestCase):
+    @mock.patch('os.path.exists')
+    def test_missing_config(self, path_exists):
+        path_exists.return_value = False
+        with self.assertRaises(config.GitlabConfigMissingError):
+            config.GitlabConfigParser('test')
+
+    @mock.patch('os.path.exists')
     @mock.patch('six.moves.builtins.open')
-    def test_invalid_id(self, m_open):
+    def test_invalid_id(self, m_open, path_exists):
         fd = six.StringIO(no_default_config)
         fd.close = mock.Mock(return_value=None)
         m_open.return_value = fd
+        path_exists.return_value = True
+        config.GitlabConfigParser('there')
         self.assertRaises(config.GitlabIDError, config.GitlabConfigParser)
 
         fd = six.StringIO(valid_config)
@@ -90,12 +99,15 @@ def test_invalid_id(self, m_open):
                           config.GitlabConfigParser,
                           gitlab_id='not_there')
 
+    @mock.patch('os.path.exists')
     @mock.patch('six.moves.builtins.open')
-    def test_invalid_data(self, m_open):
+    def test_invalid_data(self, m_open, path_exists):
         fd = six.StringIO(missing_attr_config)
         fd.close = mock.Mock(return_value=None,
                              side_effect=lambda: fd.seek(0))
         m_open.return_value = fd
+        path_exists.return_value = True
+
         config.GitlabConfigParser('one')
         config.GitlabConfigParser('one')
         self.assertRaises(config.GitlabDataError, config.GitlabConfigParser,
@@ -107,11 +119,13 @@ def test_invalid_data(self, m_open):
         self.assertEqual('Unsupported per_page number: 200',
                          emgr.exception.args[0])
 
+    @mock.patch('os.path.exists')
     @mock.patch('six.moves.builtins.open')
-    def test_valid_data(self, m_open):
+    def test_valid_data(self, m_open, path_exists):
         fd = six.StringIO(valid_config)
         fd.close = mock.Mock(return_value=None)
         m_open.return_value = fd
+        path_exists.return_value = True
 
         cp = config.GitlabConfigParser()
         self.assertEqual("one", cp.gitlab_id)