scope 0.4.4__tar.gz → 0.4.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scope
3
- Version: 0.4.4
3
+ Version: 0.4.5
4
4
  Summary: Metrics logging and analysis
5
5
  Home-page: http://github.com/danijar/scope
6
6
  Classifier: Intended Audience :: Science/Research
@@ -17,10 +17,10 @@ Scalable metrics logging and analysis.
17
17
 
18
18
  - 🚀 **Scalable:** Quickly log and view petabytes of metrics, thousands of keys, and large videos.
19
19
  - 🎞️ **Formats:** Log and view scalars, text, images, and videos. Easy to extend with custom formats.
20
- - 🧑🏻‍🔬 **Productivity:** Metrics viewer with focus on power users and full keyboard support.
20
+ - 🧑🏻‍🔬 **Productivity:** Metrics viewer with focus on power users with full keyboard support.
21
21
  - ☁️ **Cloud support:** Directly write to and read from Cloud storage via pathlib interface.
22
22
  - 🍃 **Lightweight:** The writer and reader measure only ~400 lines of Python code.
23
- - 🧱 **Reliability:** Unit tested and used across diverse research projects.
23
+ - 🧱 **Reliable:** Unit tested and used across diverse research projects.
24
24
 
25
25
  ## Usage
26
26
 
@@ -36,10 +36,14 @@ pip install scope
36
36
  import scope
37
37
 
38
38
  writer = scope.Writer(logdir)
39
- for step in range(3)
40
- video = np.zeros((100, 640, 360, 3), np.uint8)
41
- writer.add(step, {'foo': 42, 'bar': video, 'baz': 'Hello World'})
42
- writer.flush()
39
+
40
+ for step in range(3):
41
+ writer.add(step, {
42
+ 'foo': 42,
43
+ 'bar': np.zeros((100, 640, 360, 3), np.uint8),
44
+ 'baz': 'Hello World',
45
+ })
46
+ writer.flush()
43
47
  ```
44
48
 
45
49
  ### Viewing
@@ -1,55 +1,59 @@
1
- # 🔬 Scope
2
-
3
- Scalable metrics logging and analysis.
4
-
5
- ## Features
6
-
7
- - 🚀 **Scalable:** Quickly log and view petabytes of metrics, thousands of keys, and large videos.
8
- - 🎞️ **Formats:** Log and view scalars, text, images, and videos. Easy to extend with custom formats.
9
- - 🧑🏻‍🔬 **Productivity:** Metrics viewer with focus on power users and full keyboard support.
10
- - ☁️ **Cloud support:** Directly write to and read from Cloud storage via pathlib interface.
11
- - 🍃 **Lightweight:** The writer and reader measure only ~400 lines of Python code.
12
- - 🧱 **Reliability:** Unit tested and used across diverse research projects.
13
-
14
- ## Usage
15
-
16
- ### Installation
17
-
18
- ```sh
19
- pip install scope
20
- ```
21
-
22
- ### Writing
23
-
24
- ```python
25
- import scope
26
-
27
- writer = scope.Writer(logdir)
28
- for step in range(3)
29
- video = np.zeros((100, 640, 360, 3), np.uint8)
30
- writer.add(step, {'foo': 42, 'bar': video, 'baz': 'Hello World'})
31
- writer.flush()
32
- ```
33
-
34
- ### Viewing
35
-
36
- ```sh
37
- python -m scope.viewer --basedir ... --port 8000
38
- ```
39
-
40
- ### Reading
41
-
42
- ```python
43
- import scope
44
-
45
- reader = scope.Reader(logdir)
46
- print(reader.keys()) # ('foo', 'bar', 'baz')
47
-
48
- print(reader.length('foo')) # 3
49
- steps, values = reader['foo']
50
- print(steps) # np.array([0, 1, 2], np.int64)
51
- print(values) # np.array([42, 42, 42], np.float64)
52
-
53
- steps, filenames = reader['bar']
54
- reader.load('bar', filenames[-1]) # np.zeros((100, 640, 360, 3), np.uint8)
55
- ```
1
+ # 🔬 Scope
2
+
3
+ Scalable metrics logging and analysis.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Scalable:** Quickly log and view petabytes of metrics, thousands of keys, and large videos.
8
+ - 🎞️ **Formats:** Log and view scalars, text, images, and videos. Easy to extend with custom formats.
9
+ - 🧑🏻‍🔬 **Productivity:** Metrics viewer with focus on power users with full keyboard support.
10
+ - ☁️ **Cloud support:** Directly write to and read from Cloud storage via pathlib interface.
11
+ - 🍃 **Lightweight:** The writer and reader measure only ~400 lines of Python code.
12
+ - 🧱 **Reliable:** Unit tested and used across diverse research projects.
13
+
14
+ ## Usage
15
+
16
+ ### Installation
17
+
18
+ ```sh
19
+ pip install scope
20
+ ```
21
+
22
+ ### Writing
23
+
24
+ ```python
25
+ import scope
26
+
27
+ writer = scope.Writer(logdir)
28
+
29
+ for step in range(3):
30
+ writer.add(step, {
31
+ 'foo': 42,
32
+ 'bar': np.zeros((100, 640, 360, 3), np.uint8),
33
+ 'baz': 'Hello World',
34
+ })
35
+ writer.flush()
36
+ ```
37
+
38
+ ### Viewing
39
+
40
+ ```sh
41
+ python -m scope.viewer --basedir ... --port 8000
42
+ ```
43
+
44
+ ### Reading
45
+
46
+ ```python
47
+ import scope
48
+
49
+ reader = scope.Reader(logdir)
50
+ print(reader.keys()) # ('foo', 'bar', 'baz')
51
+
52
+ print(reader.length('foo')) # 3
53
+ steps, values = reader['foo']
54
+ print(steps) # np.array([0, 1, 2], np.int64)
55
+ print(values) # np.array([42, 42, 42], np.float64)
56
+
57
+ steps, filenames = reader['bar']
58
+ reader.load('bar', filenames[-1]) # np.zeros((100, 640, 360, 3), np.uint8)
59
+ ```
@@ -1,4 +1,4 @@
1
- __version__ = '0.4.4'
1
+ __version__ = '0.4.5'
2
2
 
3
3
  from .reader import Reader
4
4
  from .writer import Writer
@@ -7,6 +7,8 @@ config = elements.Flags(
7
7
  port=int(os.environ.get('SCOPE_PORT', 8000)),
8
8
  basedir=os.environ.get('SCOPE_BASEDIR', ''),
9
9
  filesystem=os.environ.get('SCOPE_FILESYSTEM', 'elements'),
10
+ cachedir='/tmp/scope-cache',
11
+ cachesize=int(4e9), # 4 GB
10
12
  maxdepth=2,
11
13
  workers=32,
12
14
  debug=False,
@@ -1,8 +1,11 @@
1
- import elements
1
+ import collections
2
2
  import io
3
3
  import os
4
+ import pathlib
4
5
  import subprocess
5
6
 
7
+ import elements
8
+
6
9
 
7
10
  class Local:
8
11
 
@@ -87,3 +90,58 @@ class Fileutil:
87
90
  return subprocess.check_output(cmd.split(), shell=False)
88
91
  except subprocess.CalledProcessError as e:
89
92
  raise RuntimeError(f'Error in subprocess: {e}')
93
+
94
+
95
+ class WithFileCache:
96
+
97
+ def __init__(self, fs, cachedir, maxsize):
98
+ # Cache size can be exceeded if multiple workers download in parallel.
99
+ assert not isinstance(fs, Local)
100
+ if isinstance(cachedir, str):
101
+ cachedir = pathlib.Path(cachedir)
102
+ cachedir.mkdir(exist_ok=True, parents=True)
103
+ self.fs = fs
104
+ self.localfs = Local()
105
+ self.cachedir = cachedir
106
+ self.maxsize = maxsize
107
+
108
+ def list(self, path):
109
+ return self.fs.list(path)
110
+
111
+ def size(self, path):
112
+ localpath = self._getfile(path)
113
+ return self.localfs.size(localpath)
114
+
115
+ def read(self, path):
116
+ localpath = self._getfile(path)
117
+ return self.localfs.read(localpath)
118
+
119
+ def open(self, path, seek=0, limit=None):
120
+ localpath = self._getfile(path)
121
+ return self.localfs.open(localpath, seek, limit)
122
+
123
+ def _getfile(self, path):
124
+ name = str(path).replace(':', '').replace('//', '/').replace('/', ':')
125
+ localpath = self.cachedir / name
126
+ if not localpath.exists():
127
+ buffer = self.fs.read(path)
128
+ self._freeup(len(buffer), path)
129
+ localpath.write_bytes(buffer)
130
+ return localpath
131
+
132
+ def _freeup(self, needed, path):
133
+ # Catch errors because parallel workers share the cache.
134
+ pairs = []
135
+ for path in self.cachedir.glob('*'):
136
+ try:
137
+ stat = path.stat()
138
+ pairs.append((path, stat))
139
+ except FileNotFoundError:
140
+ pass
141
+ pairs = sorted(pairs, key=lambda x: x[1].st_ctime)
142
+ while sum([s.st_size for p, s in pairs]) + needed > self.maxsize:
143
+ path, _ = pairs.pop(0)
144
+ try:
145
+ path.unlink()
146
+ except IndexError:
147
+ pass
@@ -20,6 +20,10 @@ fs = dict(
20
20
  local=filesystems.Local,
21
21
  )[config.filesystem]()
22
22
 
23
+ is_local = isinstance(fs, filesystems.Local)
24
+ if config.cachedir and config.cachesize and not is_local:
25
+ fs = filesystems.WithFileCache(fs, config.cachedir, config.cachesize)
26
+
23
27
 
24
28
  @app.get('/api/exps')
25
29
  def get_exps():
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes