Repository: pypa/twine

Issue:
Add disable progress bar option
While it's nice to have a progress bar when executing twine interactively, it would be nice to have the option of not displaying the progress bar for those of us who want to redirect twine's output to a file or otherwise use it in a non-interactive way. tqdm has a disable flag: https://github.com/tqdm/tqdm#documentation so it should quite simple to implement.

Discussion:

Patch:
diff --git a/AUTHORS b/AUTHORS
index d2f7095..dbbf634 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -22,4 +22,5 @@ Jesse Jarzynka <jesse@jessejoe.com> (http://jessejoe.com)
 László Kiss Kollár <kiss.kollar.laszlo@gmail.com>
 Frances Hocutt <frances.hocutt@gmail.com>
 Tathagata Dasgupta <tathagatadg@gmail.com>
-Wasim Thabraze <wasim@thabraze.me>
\ No newline at end of file
+Wasim Thabraze <wasim@thabraze.me>
+Varun Kamath <varunkamath18@gmail.com>
\ No newline at end of file
diff --git a/README.rst b/README.rst
index 4893582..1dd7514 100644
--- a/README.rst
+++ b/README.rst
@@ -160,6 +160,7 @@ Uploads one or more distributions to a repository.
                         [-s] [--sign-with SIGN_WITH] [-i IDENTITY] [-u USERNAME]
                         [-p PASSWORD] [-c COMMENT] [--config-file CONFIG_FILE]
                         [--skip-existing] [--cert path] [--client-cert path]
+                        [--verbose] [--disable-progress-bar]
                         dist [dist ...]
 
     positional arguments:
@@ -204,6 +205,9 @@ Uploads one or more distributions to a repository.
       --client-cert path    Path to SSL client certificate, a single file
                             containing the private key and the certificate in PEM
                             format.
+      --verbose             Show verbose output.
+      --disable-progress-bar
+                            Disable the progress bar.
 
 ``twine check``
 ^^^^^^^^^^^^^^^
diff --git a/twine/repository.py b/twine/repository.py
index 74e1968..327ccc9 100644
--- a/twine/repository.py
+++ b/twine/repository.py
@@ -47,7 +47,8 @@ class ProgressBar(tqdm):
 
 
 class Repository(object):
-    def __init__(self, repository_url, username, password):
+    def __init__(self, repository_url, username, password,
+                 disable_progress_bar=False):
         self.url = repository_url
         self.session = requests.session()
         self.session.auth = (username, password)
@@ -55,6 +56,7 @@ class Repository(object):
         for scheme in ('http://', 'https://'):
             self.session.mount(scheme, self._make_adapter_with_retries())
         self._releases_json_data = {}
+        self.disable_progress_bar = disable_progress_bar
 
     @staticmethod
     def _make_adapter_with_retries():
@@ -140,7 +142,8 @@ class Repository(object):
             encoder = MultipartEncoder(data_to_send)
             with ProgressBar(total=encoder.len,
                              unit='B', unit_scale=True, unit_divisor=1024,
-                             miniters=1, file=sys.stdout) as bar:
+                             miniters=1, file=sys.stdout,
+                             disable=self.disable_progress_bar) as bar:
                 monitor = MultipartEncoderMonitor(
                     encoder, lambda monitor: bar.update_to(monitor.bytes_read)
                 )
diff --git a/twine/settings.py b/twine/settings.py
index d4e3d1a..7d88f74 100644
--- a/twine/settings.py
+++ b/twine/settings.py
@@ -46,6 +46,7 @@ class Settings(object):
                  cacert=None, client_cert=None,
                  repository_name='pypi', repository_url=None,
                  verbose=False,
+                 disable_progress_bar=False,
                  **ignored_kwargs
                  ):
         """Initialize our settings instance.
@@ -95,10 +96,15 @@ class Settings(object):
             will override the settings inferred from ``repository_name``.
         :param bool verbose:
             Show verbose output.
+        :param bool disable_progress_bar:
+            Disable the progress bar.
+
+            This defaults to ``False``
         """
         self.config_file = config_file
         self.comment = comment
         self.verbose = verbose
+        self.disable_progress_bar = disable_progress_bar
         self.skip_existing = skip_existing
         self._handle_repository_options(
             repository_name=repository_name, repository_url=repository_url,
@@ -206,6 +212,13 @@ class Settings(object):
             action="store_true",
             help="Show verbose output."
         )
+        parser.add_argument(
+            "--disable-progress-bar",
+            default=False,
+            required=False,
+            action="store_true",
+            help="Disable the progress bar."
+        )
 
     @classmethod
     def from_argparse(cls, args):
@@ -276,6 +289,7 @@ class Settings(object):
             self.repository_config['repository'],
             self.username,
             self.password,
+            self.disable_progress_bar
         )
         repo.set_certificate_authority(self.cacert)
         repo.set_client_certificate(self.client_cert)


Test patch:
diff --git a/tests/test_repository.py b/tests/test_repository.py
index 5dd8fc5..143c5c7 100644
--- a/tests/test_repository.py
+++ b/tests/test_repository.py
@@ -17,6 +17,8 @@ from twine import repository
 from twine.utils import DEFAULT_REPOSITORY
 
 import pretend
+import pytest
+from contextlib import contextmanager
 
 
 def test_gpg_signature_structure_is_preserved():
@@ -140,3 +142,49 @@ def test_package_is_uploaded_200s_with_no_releases():
     )
 
     assert repo.package_is_uploaded(package) is False
+
+
+@pytest.mark.parametrize('disable_progress_bar', [
+    True,
+    False
+])
+def test_disable_progress_bar_is_forwarded_to_tqdm(monkeypatch, tmpdir,
+                                                   disable_progress_bar):
+    """Test whether the disable flag is passed to tqdm
+        when the disable_progress_bar option is passed to the
+        repository
+    """
+    @contextmanager
+    def progressbarstub(*args, **kwargs):
+        assert "disable" in kwargs
+        assert kwargs["disable"] == disable_progress_bar
+        yield
+
+    monkeypatch.setattr(repository, "ProgressBar", progressbarstub)
+    repo = repository.Repository(
+        repository_url=DEFAULT_REPOSITORY,
+        username='username',
+        password='password',
+        disable_progress_bar=disable_progress_bar
+    )
+
+    repo.session = pretend.stub(
+        post=lambda url, data, allow_redirects, headers: response_with(
+            status_code=200)
+    )
+
+    fakefile = tmpdir.join('fake.whl')
+    fakefile.write('.')
+
+    def dictfunc():
+        return {"name": "fake"}
+
+    package = pretend.stub(
+        safe_name='fake',
+        metadata=pretend.stub(version='2.12.0'),
+        basefilename="fake.whl",
+        filename=str(fakefile),
+        metadata_dictionary=dictfunc
+    )
+
+    repo.upload(package)
diff --git a/tests/test_settings.py b/tests/test_settings.py
index ae9b6db..aded930 100644
--- a/tests/test_settings.py
+++ b/tests/test_settings.py
@@ -49,6 +49,7 @@ def test_settings_transforms_config(tmpdir):
     assert s.password == 'password'
     assert s.cacert is None
     assert s.client_cert is None
+    assert s.disable_progress_bar is False
 
 
 def test_identity_requires_sign():