Commits

Jason R. Coombs committed f92dbed

Adopted progress bar from yg.stream

Comments (0)

Files changed (2)

jaraco/util/ui.py

-from __future__ import print_function, absolute_import, unicode_literals
+from __future__ import (print_function, absolute_import, unicode_literals,
+	division)
 
-from itertools import count
+import time
+import sys
+import itertools
+import abc
 
 import six
 
 		number_width = len(str(n)) + 1
 		menu_fmt = '{number:{number_width}}) {choice}'
 		formatted_choices = map(self.formatter, self.choices)
-		for number, choice in zip(count(1), formatted_choices):
+		for number, choice in zip(itertools.count(1), formatted_choices):
 			print(menu_fmt.format(**vars()))
 		print()
 		try:
 		except KeyboardInterrupt:
 			result = None
 		return result
+
+
+six.patch_with_metaclass(abc.ABCMeta)
+class AbstractProgressBar(object):
+	def __init__(self, unit='', size=70):
+		"""
+		Size is the nominal size in characters
+		"""
+		self.unit = unit
+		self.size = size
+
+	def report(self, amt):
+		sys.stdout.write('\r%s' % self.get_bar(amt))
+		sys.stdout.flush()
+
+	@abc.abstractmethod
+	def get_bar(self, amt):
+		"Return the string to be printed. Should be size >= self.size"
+
+	def summary(self, str):
+		return ' (' + self.unit_str(str) + ')'
+
+	def unit_str(self, str):
+		if self.unit:
+			str += ' ' + self.unit
+		return str
+
+	def finish(self):
+		print()
+
+	def __enter__(self):
+		self.report(0)
+		return self
+
+	def __exit__(self, exc, exc_val, tb):
+		if exc is None:
+			self.finish()
+		else:
+			print()
+
+
+class SimpleProgressBar(AbstractProgressBar):
+
+	_PROG_DISPGLYPH = itertools.cycle(['|', '/', '-', '\\'])
+
+	def get_bar(self, amt):
+		bar = next(self._PROG_DISPGLYPH)
+		template = ' [{bar:^{bar_len}}]'
+		summary = self.summary('{amt}')
+		template += summary
+		empty = template.format(
+			bar='',
+			bar_len=0,
+			amt=amt,
+		)
+		bar_len = self.size - len(empty)
+		return template.format(**vars())
+
+	@classmethod
+	def demo(cls):
+		bar3 = cls(unit='cubes', size=30)
+		with bar3:
+			for x in six.moves.range(1, 759):
+				bar3.report(x)
+				time.sleep(0.01)
+
+class TargetProgressBar(AbstractProgressBar):
+	def __init__(self, total=None, unit='', size=70):
+		"""
+		Size is the nominal size in characters
+		"""
+		self.total = total
+		super(TargetProgressBar, self).__init__(unit, size)
+
+	def get_bar(self, amt):
+		template = ' [{bar:<{bar_len}}]'
+		completed = amt / self.total
+		percent = int(completed * 100)
+		percent_str = ' {percent:3}%'
+		template += percent_str
+		summary = self.summary('{amt}/{total}')
+		template += summary
+		empty = template.format(
+			total=self.total,
+			bar='',
+			bar_len=0,
+			**vars()
+		)
+		bar_len = self.size - len(empty)
+		bar = '=' * int(completed * bar_len)
+		return template.format(total=self.total, **vars())
+
+	@classmethod
+	def demo(cls):
+		bar1 = cls(100, 'blocks')
+		with bar1:
+			for x in six.moves.range(1, 101):
+				bar1.report(x)
+				time.sleep(0.05)
+
+		bar2 = cls(758, size=50)
+		with bar2:
+			for x in six.moves.range(1, 759):
+				bar2.report(x)
+				time.sleep(0.01)
+
+	def finish(self):
+		self.report(self.total)
+		super(TargetProgressBar, self).finish()
 			'calc-prorate = jaraco.tempora:calculate_prorated_values',
 		],
 	},
+	dependency_links=[
+		'https://bitbucket.org/jaraco/six/downloads',
+	],
 	install_requires=[
-		'six>=1.3.0',
+		'six>=1.4.0dev',
 	],
 	tests_require=[
 		'pytest>=2',
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.