tqdm 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +4 -0
- data/README.md +51 -13
- data/lib/core_ext/enumerable.rb +15 -10
- data/lib/tqdm.rb +76 -7
- data/lib/tqdm/sequel.rb +14 -1
- data/lib/tqdm/utils.rb +10 -6
- data/lib/tqdm/version.rb +2 -1
- data/tqdm.gemspec +2 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18fbbebb6aadc15bb9b2cea3caf012e49e087908
|
4
|
+
data.tar.gz: 3da06e2b16e451592014ebdf94b0012ad165d589
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0aefc092a3fb9a925107689fe03eaf8196393a60331fcb41031bca5159423693e65db4bd5cf60a333cb0d16c1cb0eaf9dfe5682003955665d1bdedcf0ea49d70
|
7
|
+
data.tar.gz: 7bdd329b81bca2cc2951753815c7459f58ac6009b8dffa8e5a650cbb921f67cc7ac7b4e976478a5fd9d09fcbcea82842757dc80d1f8b83a28ebd55adc711abca
|
data/.yardopts
ADDED
data/README.md
CHANGED
@@ -2,22 +2,32 @@
|
|
2
2
|
|
3
3
|
tqdm-ruby is a small utility to show a progress indicator while iterating through an Enumerable object.
|
4
4
|
|
5
|
-
It is a port of the excellent tdqm library for python
|
5
|
+
It is a port of the excellent [tdqm library][tqdm] for python.
|
6
6
|
|
7
|
-
Call
|
7
|
+
Call `#tqdm` on any `Enumerable`, which enhances the object so that iterating over it will produce an animated progress bar on `$stderr`.
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
```ruby
|
10
|
+
require 'tqdm'
|
11
|
+
(0...1000).tqdm.each { |x| sleep 0.01 }
|
12
|
+
```
|
11
13
|
|
12
14
|
The default output looks like this:
|
13
15
|
|
14
|
-
|
16
|
+
![|####------| 492/1000 49% [elapsed: 00:05 left: 00:05, 88.81 iters/sec]](http://i.imgur.com/6y0t7XS.gif)
|
15
17
|
|
16
|
-
It works equally well from within [pry](http://pryrepl.org/) and [Jupyter notebooks](https://jupyter.org/).
|
18
|
+
It works equally well from within irb, [pry](http://pryrepl.org/), and [Jupyter notebooks](https://jupyter.org/).
|
19
|
+
|
20
|
+
*Why not progressbar, ruby-progressbar, etc.?* These have a bazillion formatting options and you typically have to update the progressbar object throughout other code. tqdm pleasantly encourages the laziest imaginable usage, in that you "set it and forget it".
|
21
|
+
|
22
|
+
[tqdm]: https://github.com/tqdm/tqdm
|
17
23
|
|
18
24
|
## Install
|
19
25
|
|
20
|
-
|
26
|
+
Install it globally from [Rubygems](https://rubygems.org/gems/tqdm):
|
27
|
+
|
28
|
+
$ gem install tqdm # (might need sudo on OS X)
|
29
|
+
|
30
|
+
*or* add this line to your application's Gemfile:
|
21
31
|
|
22
32
|
gem 'tqdm'
|
23
33
|
|
@@ -25,16 +35,44 @@ And then execute:
|
|
25
35
|
|
26
36
|
$ bundle
|
27
37
|
|
28
|
-
|
38
|
+
## Usage
|
29
39
|
|
30
|
-
|
40
|
+
All `Enumerable` objects gain access to the `#tqdm` method, which returns an enhanced object wherein any iteration (by calling `#each` or any of its relatives, e.g., `#each_with_index`, `#each_with_object`, etc.) produces an animated progress bar on `$stderr`.
|
31
41
|
|
32
|
-
|
42
|
+
Options can be provided for `#tqdm`:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
require 'tqdm'
|
46
|
+
Hash[*(1..1000)].tqdm(desc: "working on it", leave: true).each { |x| sleep 0.01 }
|
47
|
+
```
|
48
|
+
|
49
|
+
The following options are available:
|
50
|
+
|
51
|
+
- `desc`: Short string, describing the progress, added to the beginning of the line
|
52
|
+
- `total`: Expected number of iterations, if not given, `self.size` is used
|
53
|
+
- `file`: A file-like object to output the progress message to, by default, `$stderr`
|
54
|
+
- `leave`: A boolean (default false). Should the progress bar should stay on screen after it's done?
|
55
|
+
- `min_interval`: Default is `0.5`. If less than `min_interval` seconds or `min_iters` iterations have passed since the last progress meter update, it is not re-printed (decreases IO thrashing).
|
56
|
+
- `min_iters`: Default is `1`. See previous.
|
57
|
+
|
58
|
+
[Sequel](http://sequel.jeremyevans.net/) is an amazing database library for Ruby. tqdm can enhance its [`Dataset`](http://sequel.jeremyevans.net/rdoc/classes/Sequel/Dataset.html) objects to show progress while iterating (same options as above):
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
require 'tqdm/sequel' # Automatically requires tqdm and sequel
|
62
|
+
|
63
|
+
# In-memory database for demonstration purposes
|
64
|
+
DB = Sequel.sqlite
|
65
|
+
DB.create_table :items do
|
66
|
+
primary_key :id
|
67
|
+
Float :price
|
68
|
+
end
|
33
69
|
|
34
|
-
|
70
|
+
# Show progress during big inserts (this isn't new)
|
71
|
+
(0..100000).tqdm.each { DB[:items].insert(price: rand * 100) }
|
35
72
|
|
36
|
-
|
37
|
-
|
73
|
+
# Show progress during long SELECT queries
|
74
|
+
DB[:items].where{ price > 10 }.tqdm.each { |row| "do some processing here" }
|
75
|
+
```
|
38
76
|
|
39
77
|
## Contributing
|
40
78
|
|
data/lib/core_ext/enumerable.rb
CHANGED
@@ -1,18 +1,23 @@
|
|
1
1
|
require "tqdm"
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# We enhance all enumerable objects (e.g. `Array`, `Hash`, `Range`, ...) by extending the `Enumerable` module.
|
4
|
+
# This mixin is only supposed to be present on objects that provide an `#each` method.
|
5
|
+
#
|
6
|
+
# @see http://ruby-doc.org/core-2.2.3/Enumerable.html
|
5
7
|
module Enumerable
|
6
8
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
9
|
+
# Returns a clone of `self` where all calls to `#each` and related methods will print an animated progress bar
|
10
|
+
# while iterating.
|
11
|
+
#
|
12
|
+
# @param opts [Hash] more options used to control behavior of the progress bar
|
13
|
+
# @option opts [String] :desc a short description added to the beginning of the progress bar
|
14
|
+
# @option opts [Integer] :total (self.size) the expected number of iterations
|
15
|
+
# @option opts [File, IO] :file ($stderr) a file-like object to output the progress bar to
|
16
|
+
# @option opts [Boolean] :leave (false) should the progress bar should stay on screen after it's done?
|
17
|
+
# @option opts [Integer] :min_iters see `:min_interval`
|
18
|
+
# @option opts [Float] :min_interval If less than min_interval seconds or min_iters iterations have passed since
|
15
19
|
# the last progress meter update, it is not updated again.
|
20
|
+
# @return [Enumerable] `self` with the `#each` method wrapped as described above
|
16
21
|
def tqdm(opts = {})
|
17
22
|
Tqdm::TqdmDecorator.new(self, opts).enhance
|
18
23
|
end
|
data/lib/tqdm.rb
CHANGED
@@ -2,35 +2,89 @@ require "tqdm/version"
|
|
2
2
|
require "tqdm/utils"
|
3
3
|
require "core_ext/enumerable"
|
4
4
|
|
5
|
+
# Add a progress bar to your loops in a second.
|
6
|
+
# A port of Python's [tqdm library](https://github.com/tqdm/tqdm), although we're currently
|
7
|
+
# closer to the feature set of [@noamraph's original release](https://github.com/noamraph/tqdm).
|
8
|
+
#
|
9
|
+
# Specifically, `Tqdm` enhances `Enumerable` by printing a progress indicator whenever
|
10
|
+
# iterating with `#each` or its close relatives.
|
11
|
+
#
|
12
|
+
# @author Theodore Pak
|
13
|
+
# @see https://github.com/tqdm/tqdm
|
5
14
|
module Tqdm
|
6
15
|
|
16
|
+
# The default width of the progress bar, in characters.
|
17
|
+
N_BARS = 10
|
18
|
+
|
7
19
|
class << self
|
20
|
+
# Upgrades `Sequel::Datasets` with the #tqdm method.
|
21
|
+
# @see Enumerable#tqdm
|
8
22
|
def enhance_sequel!
|
9
23
|
require "tqdm/sequel"
|
10
24
|
end
|
11
25
|
end
|
12
|
-
|
26
|
+
|
27
|
+
# Prints a status line, handling the deletion of previously printed lines with carriage
|
28
|
+
# returns as necessary. Instantiated by a `TqdmDecorator`.
|
29
|
+
#
|
30
|
+
# @private
|
13
31
|
class StatusPrinter
|
32
|
+
# Initialize a new StatusPrinter.
|
33
|
+
#
|
34
|
+
# @param file [File, IO] the status will be printed to this via `#write` and `#flush`
|
14
35
|
def initialize(file)
|
15
36
|
@file = file
|
16
37
|
@last_printed_len = 0
|
17
38
|
end
|
18
39
|
|
19
|
-
|
20
|
-
|
40
|
+
# Prints a line of text to @file, after deleting the previously printed line
|
41
|
+
#
|
42
|
+
# @param line [String] a line of text to be printed
|
43
|
+
# @return [Integer] the number of bytes written
|
44
|
+
def print_status(line)
|
45
|
+
@file.write("\r" + line + ' ' * [@last_printed_len - line.size, 0].max)
|
21
46
|
@file.flush
|
22
|
-
@last_printed_len =
|
47
|
+
@last_printed_len = line.size
|
23
48
|
end
|
24
49
|
end
|
25
50
|
|
26
51
|
|
52
|
+
# Decorates the #each method of an `Enumerable` by wrapping it so that each
|
53
|
+
# iteration produces a pretty progress bar printed to the console or a file handle.
|
54
|
+
#
|
55
|
+
# @note The `Enumerable` is cloned before it is enhanced; it is not modified directly.
|
56
|
+
#
|
57
|
+
# @example Enhances `arr` so that an animated progress bar prints while iterating.
|
58
|
+
# arr = (0...1000)
|
59
|
+
# arr_tqdm = TqdmDecorator.new(arr).enhance
|
60
|
+
# arr_tqdm.each { |x| sleep 0.01 }
|
27
61
|
class TqdmDecorator
|
28
62
|
|
29
63
|
include Utils
|
30
|
-
|
64
|
+
|
65
|
+
# Initialize a new TqdmDecorator. Typically you wouldn't use this object, but
|
66
|
+
# would immediately call `#enhance` to retrieve the enhanced `Enumerable`.
|
67
|
+
#
|
68
|
+
# @param enumerable [Enumerable] the Enumerable object to be enhanced
|
69
|
+
# @param opts [Hash] more options used to control behavior of the progress bar
|
70
|
+
# @option opts [String] :desc a short description added to the beginning of the progress bar
|
71
|
+
# @option opts [Integer] :total (self.size) the expected number of iterations
|
72
|
+
# @option opts [File, IO] :file ($stderr) a file-like object to output the progress bar to
|
73
|
+
# @option opts [Boolean] :leave (false) should the progress bar should stay on screen after it's done?
|
74
|
+
# @option opts [Integer] :min_iters see `:min_interval`
|
75
|
+
# @option opts [Float] :min_interval If less than min_interval seconds or min_iters iterations have passed since
|
76
|
+
# the last progress meter update, it is not updated again.
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
# a = (1...1000)
|
80
|
+
# TqdmDecorator.new(a).enhance.each { |x| sleep 0.01 }
|
81
|
+
#
|
82
|
+
# @example
|
83
|
+
# a = [1, 2, 3, 4]
|
84
|
+
# TqdmDecorator.new(a, file: $stdout, leave: true)
|
31
85
|
def initialize(enumerable, opts={})
|
32
86
|
@enumerable = enumerable
|
33
|
-
@total = opts[:total] || @enumerable.size rescue nil
|
87
|
+
@total = opts[:total] || @enumerable.size rescue @enumerable.count rescue nil
|
34
88
|
@prefix = opts[:desc] ? opts[:desc] + ': ' : ''
|
35
89
|
@file = opts[:file] || $stderr
|
36
90
|
@sp = StatusPrinter.new(@file)
|
@@ -39,6 +93,7 @@ module Tqdm
|
|
39
93
|
@leave = opts[:leave] || false
|
40
94
|
end
|
41
95
|
|
96
|
+
# Starts the textual progress bar.
|
42
97
|
def start!
|
43
98
|
@start_t = @last_print_t = Time.now
|
44
99
|
@last_print_n = 0
|
@@ -47,11 +102,17 @@ module Tqdm
|
|
47
102
|
@sp.print_status(@prefix + format_meter(0, @total, 0))
|
48
103
|
end
|
49
104
|
|
105
|
+
# Called everytime the textual progress bar might need to be updated (i.e. on
|
106
|
+
# every iteration). We still check whether the update is appropriate to print to
|
107
|
+
# the progress bar before doing so, according to the `:min_iters` and `:min_interval`
|
108
|
+
# options.
|
109
|
+
#
|
110
|
+
# @see #initialize
|
50
111
|
def increment!
|
51
112
|
@n += 1
|
52
113
|
|
53
114
|
if @n - @last_print_n >= @min_iters
|
54
|
-
# We check the counter first, to reduce the overhead of
|
115
|
+
# We check the counter first, to reduce the overhead of Time.now
|
55
116
|
cur_t = Time.now
|
56
117
|
if cur_t - @last_print_t >= @min_interval
|
57
118
|
@sp.print_status(@prefix + format_meter(@n, @total, cur_t - @start_t))
|
@@ -61,6 +122,8 @@ module Tqdm
|
|
61
122
|
end
|
62
123
|
end
|
63
124
|
|
125
|
+
# Prints the final state of the textual progress bar. Based on the `:leave` option, this
|
126
|
+
# may include deleting it entirely.
|
64
127
|
def finish!
|
65
128
|
if !@leave
|
66
129
|
@sp.print_status('')
|
@@ -73,6 +136,12 @@ module Tqdm
|
|
73
136
|
end
|
74
137
|
end
|
75
138
|
|
139
|
+
# Enhances the wrapped `Enumerable`.
|
140
|
+
#
|
141
|
+
# @note The `Enumerable` is cloned (shallow copied) before it is enhanced; it is not modified directly.
|
142
|
+
#
|
143
|
+
# @return [Enumerable] a clone of Enumerable enhanced so that every call to `#each` animates the
|
144
|
+
# progress bar.
|
76
145
|
def enhance
|
77
146
|
tqdm = self
|
78
147
|
|
data/lib/tqdm/sequel.rb
CHANGED
@@ -1,12 +1,25 @@
|
|
1
1
|
require "sequel"
|
2
2
|
require "tqdm"
|
3
3
|
|
4
|
+
# @see Sequel::Dataset
|
4
5
|
module Sequel
|
5
6
|
|
7
|
+
# In order to use `Tqdm` with Sequel Datasets, we can simply extend `Sequel::Dataset`
|
8
|
+
# with the same `#tqdm` method
|
9
|
+
#
|
10
|
+
# @see Enumerable#tqdm
|
11
|
+
# @see http://sequel.jeremyevans.net/
|
12
|
+
# @see http://sequel.jeremyevans.net/rdoc/classes/Sequel/Dataset.html
|
6
13
|
class Dataset
|
14
|
+
|
15
|
+
# Returns a clone of `self` where all calls to `#each` and related methods will print an animated progress bar
|
16
|
+
# while iterating.
|
17
|
+
#
|
18
|
+
# @see Enumerable#tqdm
|
7
19
|
def tqdm(opts = {})
|
8
|
-
Tqdm::TqdmDecorator.new(self,
|
20
|
+
Tqdm::TqdmDecorator.new(self, opts).enhance
|
9
21
|
end
|
22
|
+
|
10
23
|
end
|
11
24
|
|
12
25
|
end
|
data/lib/tqdm/utils.rb
CHANGED
@@ -2,11 +2,13 @@ require "tqdm"
|
|
2
2
|
|
3
3
|
module Tqdm
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
# Utility functions related to `Tqdm`.
|
7
6
|
module Utils
|
8
7
|
|
9
8
|
# Formats a number of seconds into an hh:mm:ss string.
|
9
|
+
#
|
10
|
+
# @param t [Integer] a number of seconds
|
11
|
+
# @return [String] an hh:mm:ss string
|
10
12
|
def format_interval(t)
|
11
13
|
mins, s = t.to_i.divmod(60)
|
12
14
|
h, m = mins.divmod(60)
|
@@ -14,11 +16,13 @@ module Tqdm
|
|
14
16
|
end
|
15
17
|
|
16
18
|
# Formats a count (n) of total items processed + an elapsed time into a
|
17
|
-
# textual progress meter.
|
19
|
+
# textual progress bar + meter.
|
20
|
+
#
|
21
|
+
# @param n [Integer] number of finished iterations
|
22
|
+
# @param total [Integer, nil] total number of iterations, or nil
|
23
|
+
# @param elapsed [Integer] number of seconds passed since start
|
24
|
+
# @return [String] a textual progress bar + meter
|
18
25
|
def format_meter(n, total, elapsed)
|
19
|
-
# n - number of finished iterations
|
20
|
-
# total - total number of iterations, or nil
|
21
|
-
# elapsed - number of seconds passed since start
|
22
26
|
total = (n > total ? nil : total) if total
|
23
27
|
|
24
28
|
elapsed_str = format_interval(elapsed)
|
data/lib/tqdm/version.rb
CHANGED
data/tqdm.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tqdm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theodore Pak
|
@@ -47,6 +47,7 @@ extensions: []
|
|
47
47
|
extra_rdoc_files: []
|
48
48
|
files:
|
49
49
|
- ".gitignore"
|
50
|
+
- ".yardopts"
|
50
51
|
- Gemfile
|
51
52
|
- LICENSE.txt
|
52
53
|
- README.md
|
@@ -69,7 +70,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
69
70
|
requirements:
|
70
71
|
- - ">="
|
71
72
|
- !ruby/object:Gem::Version
|
72
|
-
version:
|
73
|
+
version: 1.9.2
|
73
74
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
75
|
requirements:
|
75
76
|
- - ">="
|