Repository: tqdm/tqdm (Python)

Issue:
Rename RMOTR Notebooks to Notebooks AI
Guys, we've moved RMOTR Notebooks into its own domain https://notebooks.ai/, to keep it as a separated product.

Single line PR to update the Demo link URL.
Move progress bar back to a value? 
If i want to set the progress bar to a specific point, update only allows postive values, so how do i do that? 


Hints:

just set n manually and then update. See #374 #432 
```python
from tqdm import tqdm
from time import sleep
pbar = tqdm(range(100))
pbar.update(50)
pbar.refresh()
sleep(2)
pbar.n = 10 #check this
pbar.refresh() #check this
sleep(2)
pbar.update(30)
```

@casperdcl how about we add this into Faq of README and close #545, #432, #374?

Patch:
diff --git a/mkdocs.py b/mkdocs.py
--- a/mkdocs.py
+++ b/mkdocs.py
@@ -20,14 +20,20 @@
 """
 
 
-def doc2rst(doc, arglist=True):
+def doc2rst(doc, arglist=True, raw=False):
     """
     arglist  : bool, whether to create argument lists
+    raw  : bool, ignores arglist and indents by 2 spaces
     """
-    doc = dedent(doc).replace('`', '``')
-    if arglist:
-        doc = '\n'.join([i if not i or i[0] == ' ' else '* ' + i + '  '
-                         for i in doc.split('\n')])
+    doc = doc.replace('`', '``')
+    if raw:
+        doc = doc.replace('\n ', '\n   ')
+        #doc = '\n'.join(i.rstrip() for i in doc.split('\n'))
+    else:
+        doc = dedent(doc)
+        if arglist:
+            doc = '\n'.join([i if not i or i[0] == ' ' else '* ' + i + '  '
+                             for i in doc.split('\n')])
     return doc
 
 
@@ -42,6 +48,11 @@ def doc2rst(doc, arglist=True):
 DOC_tqdm_init_args, _, DOC_tqdm_init_rets = DOC_tqdm_init_args\
     .partition(doc2rst(HEAD_RETS))
 DOC_cli = doc2rst(tqdm._main.CLI_EXTRA_DOC).partition(doc2rst(HEAD_CLI))[-1]
+DOC_tqdm_tqdm = {}
+for i in dir(tqdm.tqdm):
+    doc = getattr(tqdm.tqdm, i).__doc__
+    if doc:
+        DOC_tqdm_tqdm[i] = doc2rst(doc, raw=True)
 
 # special cases
 DOC_tqdm_init_args = DOC_tqdm_init_args.replace(' *,', ' ``*``,')
@@ -51,6 +62,8 @@ def doc2rst(doc, arglist=True):
     .replace('{DOC_tqdm.tqdm.__init__.Parameters}', DOC_tqdm_init_args)\
     .replace('{DOC_tqdm._main.CLI_EXTRA_DOC}', DOC_cli)\
     .replace('{DOC_tqdm.tqdm.__init__.Returns}', DOC_tqdm_init_rets)
+for k, v in DOC_tqdm_tqdm.items():
+    README_rst = README_rst.replace('{DOC_tqdm.tqdm.%s}' % k, v)
 
 if __name__ == "__main__":
     fndoc = path.join(src_dir, 'README.rst')
diff --git a/tqdm/_tqdm.py b/tqdm/_tqdm.py
--- a/tqdm/_tqdm.py
+++ b/tqdm/_tqdm.py
@@ -480,7 +480,7 @@ def __new__(cls, *args, **kwargs):
 
     @classmethod
     def _get_free_pos(cls, instance=None):
-        """Skips specified instance"""
+        """Skips specified instance."""
         positions = set(abs(inst.pos) for inst in cls._instances
                         if inst is not instance and hasattr(inst, "pos"))
         return min(set(range(len(positions) + 1)).difference(positions))
@@ -517,9 +517,7 @@ def _decr_instances(cls, instance):
 
     @classmethod
     def write(cls, s, file=None, end="\n", nolock=False):
-        """
-        Print a message via tqdm (without overlap with bars)
-        """
+        """Print a message via tqdm (without overlap with bars)."""
         fp = file if file is not None else sys.stdout
         with cls.external_write_mode(file=file, nolock=nolock):
             # Write the message
@@ -965,21 +963,6 @@ def __exit__(self, *exc):
     def __del__(self):
         self.close()
 
-    @property
-    def format_dict(self):
-        """Public API for read-only member access"""
-        return dict(
-            n=self.n, total=self.total,
-            elapsed=self._time() - self.start_t
-            if hasattr(self, 'start_t') else 0,
-            ncols=self.dynamic_ncols(self.fp)
-            if self.dynamic_ncols else self.ncols,
-            prefix=self.desc, ascii=self.ascii, unit=self.unit,
-            unit_scale=self.unit_scale,
-            rate=1 / self.avg_time if self.avg_time else None,
-            bar_format=self.bar_format, postfix=self.postfix,
-            unit_divisor=self.unit_divisor)
-
     def __repr__(self):
         return self.format_meter(**self.format_dict)
 
@@ -1100,7 +1083,7 @@ def update(self, n=1):
             return
 
         if n < 0:
-            raise ValueError("n ({0}) cannot be negative".format(n))
+            self.last_print_n += n  # for auto-refresh logic to work
         self.n += n
 
         # check counter first to reduce calls to time()
@@ -1152,9 +1135,7 @@ def update(self, n=1):
                 self.last_print_t = cur_t
 
     def close(self):
-        """
-        Cleanup and (if leave=False) close the progressbar.
-        """
+        """Cleanup and (if leave=False) close the progressbar."""
         if self.disable:
             return
 
@@ -1195,14 +1176,53 @@ def fp_write(s):
                 if not pos:
                     fp_write('\r')
 
+    def clear(self, nolock=False):
+        """Clear current bar display."""
+        if self.disable:
+            return
+
+        if not nolock:
+            self._lock.acquire()
+        self.moveto(abs(self.pos))
+        self.sp('')
+        self.fp.write('\r')  # place cursor back at the beginning of line
+        self.moveto(-abs(self.pos))
+        if not nolock:
+            self._lock.release()
+
+    def refresh(self, nolock=False):
+        """Force refresh the display of this bar."""
+        if self.disable:
+            return
+
+        if not nolock:
+            self._lock.acquire()
+        self.display()
+        if not nolock:
+            self._lock.release()
+
     def unpause(self):
-        """
-        Restart tqdm timer from last print time.
-        """
+        """Restart tqdm timer from last print time."""
         cur_t = self._time()
         self.start_t += cur_t - self.last_print_t
         self.last_print_t = cur_t
 
+    def reset(self, total=None):
+        """
+        Resets to 0 iterations for repeated use.
+
+        Consider combining with `leave=True`.
+
+        Parameters
+        ----------
+        total  : int, optional. Total to use for the new bar.
+        """
+        self.last_print_n = self.n = 0
+        self.last_print_t = self.start_t = self._time()
+        if total is not None:
+            self.total = total
+        self.refresh()
+
     def set_description(self, desc=None, refresh=True):
         """
         Set/modify description of the progress bar.
@@ -1218,9 +1238,7 @@ def set_description(self, desc=None, refresh=True):
             self.refresh()
 
     def set_description_str(self, desc=None, refresh=True):
-        """
-        Set/modify description without ': ' appended.
-        """
+        """Set/modify description without ': ' appended."""
         self.desc = desc or ''
         if refresh:
             self.refresh()
@@ -1269,43 +1287,33 @@ def moveto(self, n):
         self.fp.write(_unicode('\n' * n + _term_move_up() * -n))
         self.fp.flush()
 
-    def clear(self, nolock=False):
-        """
-        Clear current bar display
-        """
-        if self.disable:
-            return
-
-        if not nolock:
-            self._lock.acquire()
-        self.moveto(abs(self.pos))
-        self.sp('')
-        self.fp.write('\r')  # place cursor back at the beginning of line
-        self.moveto(-abs(self.pos))
-        if not nolock:
-            self._lock.release()
-
-    def refresh(self, nolock=False):
-        """
-        Force refresh the display of this bar
-        """
-        if self.disable:
-            return
-
-        if not nolock:
-            self._lock.acquire()
-        self.display()
-        if not nolock:
-            self._lock.release()
+    @property
+    def format_dict(self):
+        """Public API for read-only member access."""
+        return dict(
+            n=self.n, total=self.total,
+            elapsed=self._time() - self.start_t
+            if hasattr(self, 'start_t') else 0,
+            ncols=self.dynamic_ncols(self.fp)
+            if self.dynamic_ncols else self.ncols,
+            prefix=self.desc, ascii=self.ascii, unit=self.unit,
+            unit_scale=self.unit_scale,
+            rate=1 / self.avg_time if self.avg_time else None,
+            bar_format=self.bar_format, postfix=self.postfix,
+            unit_divisor=self.unit_divisor)
 
     def display(self, msg=None, pos=None):
         """
-        Use `self.sp` and to display `msg` in the specified `pos`.
+        Use `self.sp` to display `msg` in the specified `pos`.
+
+        Consider overloading this function when inheriting to use e.g.:
+        `self.some_frontend(**self.format_dict)` instead of `self.sp`.
 
         Parameters
         ----------
-        msg  : what to display (default: repr(self))
-        pos  : position to display in. (default: abs(self.pos))
+        msg  : str, optional. What to display (default: `repr(self)`).
+        pos  : int, optional. Position to `moveto`
+          (default: `abs(self.pos)`).
         """
         if pos is None:
             pos = abs(self.pos)
diff --git a/tqdm/_tqdm_notebook.py b/tqdm/_tqdm_notebook.py
--- a/tqdm/_tqdm_notebook.py
+++ b/tqdm/_tqdm_notebook.py
@@ -150,7 +150,7 @@ def print_status(s='', close=False, bar_style=None, desc=None):
                     npos = s.find(r'/|/')  # cause we use bar_format=r'{n}|...'
                     # Check that n can be found in s (else n > total)
                     if npos >= 0:
-                        n = int(s[:npos])  # get n from string
+                        n = float(s[:npos])  # get n from string
                         s = s[npos + 3:]  # remove from string
 
                         # Update bar with current n value
@@ -208,8 +208,9 @@ def __init__(self, *args, **kwargs):
         self.ncols = '100%' if self.dynamic_ncols else kwargs.get("ncols", None)
 
         # Replace with IPython progress bar display (with correct total)
+        unit_scale = 1 if self.unit_scale is True else self.unit_scale or 1
         self.sp = self.status_printer(
-            self.fp, self.total, self.desc, self.ncols)
+            self.fp, self.total * unit_scale, self.desc, self.ncols)
         self.desc = None  # trick to place description before the bar
 
         # Print initial bar state


Test patch:
diff --git a/tqdm/tests/tests_tqdm.py b/tqdm/tests/tests_tqdm.py
--- a/tqdm/tests/tests_tqdm.py
+++ b/tqdm/tests/tests_tqdm.py
@@ -895,15 +895,9 @@ def test_update():
             assert '| 2/2' in our_file.getvalue()
             progressbar.desc = 'dynamically notify of 4 increments in total'
             progressbar.total = 4
-            try:
-                progressbar.update(-10)
-            except ValueError as e:
-                if str(e) != "n (-10) cannot be negative":
-                    raise
-                progressbar.update()  # should default to +1
-            else:
-                raise ValueError("Should not support negative updates")
-            res = our_file.getvalue()
+            progressbar.update(-1)
+            progressbar.update(2)
+        res = our_file.getvalue()
     assert '| 3/4 ' in res
     assert 'dynamically notify of 4 increments in total' in res
 
@@ -1132,6 +1126,21 @@ def test_unpause():
     assert r_before == r_after
 
 
+@with_setup(pretest, posttest)
+def test_reset():
+    """Test resetting a bar for re-use"""
+    with closing(StringIO()) as our_file:
+        with tqdm(total=10, file=our_file,
+                  miniters=1, mininterval=0, maxinterval=0) as t:
+            t.update(9)
+            t.reset()
+            t.update()
+            t.reset(total=12)
+            t.update(10)
+        assert '| 1/10' in our_file.getvalue()
+        assert '| 10/12' in our_file.getvalue()
+
+
 @with_setup(pretest, posttest)
 def test_position():
     """Test positioned progress bars"""