PyOPIA 2.5.13__tar.gz → 2.6.1__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.
Files changed (26) hide show
  1. {pyopia-2.5.13 → pyopia-2.6.1}/PKG-INFO +1 -1
  2. pyopia-2.6.1/pyopia/__init__.py +1 -0
  3. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/cli.py +43 -13
  4. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/pipeline.py +13 -3
  5. pyopia-2.5.13/pyopia/__init__.py +0 -1
  6. {pyopia-2.5.13 → pyopia-2.6.1}/LICENSE +0 -0
  7. {pyopia-2.5.13 → pyopia-2.6.1}/README.md +0 -0
  8. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/background.py +0 -0
  9. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/classify.py +0 -0
  10. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/exampledata.py +0 -0
  11. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/instrument/__init__.py +0 -0
  12. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/instrument/common.py +0 -0
  13. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/instrument/holo.py +0 -0
  14. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/instrument/silcam.py +0 -0
  15. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/instrument/uvp.py +0 -0
  16. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/io.py +0 -0
  17. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/plotting.py +0 -0
  18. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/process.py +0 -0
  19. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/simulator/__init__.py +0 -0
  20. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/simulator/silcam.py +0 -0
  21. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/statistics.py +0 -0
  22. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/tests/__init__.py +0 -0
  23. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/tests/test_classify.py +0 -0
  24. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/tests/test_notebooks.py +0 -0
  25. {pyopia-2.5.13 → pyopia-2.6.1}/pyopia/tests/test_pipeline.py +0 -0
  26. {pyopia-2.5.13 → pyopia-2.6.1}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyOPIA
3
- Version: 2.5.13
3
+ Version: 2.6.1
4
4
  Summary: A Python Ocean Particle Image Analysis toolbox.
5
5
  Home-page: https://github.com/sintef/pyopia
6
6
  Keywords: Ocean,Particles,Imaging,Measurement,Size distribution
@@ -0,0 +1 @@
1
+ __version__ = '2.6.1'
@@ -5,11 +5,13 @@ PyOPIA top-level code primarily for managing cmd line entry points
5
5
  import typer
6
6
  import toml
7
7
  import os
8
+ import time
8
9
  import datetime
9
10
  import traceback
10
11
  import logging
11
- from rich.progress import track, Progress
12
+ from rich.progress import Progress
12
13
  from rich.logging import RichHandler
14
+ import rich.progress
13
15
  import pandas as pd
14
16
  import threading
15
17
 
@@ -129,6 +131,8 @@ def process(config_filename: str, num_chunks: int = 1):
129
131
  from pyopia.io import load_toml
130
132
  from pyopia.pipeline import Pipeline
131
133
 
134
+ t1 = time.time()
135
+
132
136
  with Progress(transient=True) as progress:
133
137
  progress.console.print("[blue]LOAD CONFIG")
134
138
  pipeline_config = load_toml(config_filename)
@@ -139,7 +143,7 @@ def process(config_filename: str, num_chunks: int = 1):
139
143
 
140
144
  check_chunks(num_chunks, pipeline_config)
141
145
 
142
- progress.console.print("[blue]OBTAIN FILE LIST")
146
+ progress.console.print("[blue]OBTAIN IMAGE LIST")
143
147
  raw_files = pyopia.pipeline.FilesToProcess(pipeline_config['general']['raw_files'])
144
148
  conf_corrbg = pipeline_config['steps'].get('correctbackground', dict())
145
149
  average_window = conf_corrbg.get('average_window', 0)
@@ -164,25 +168,35 @@ def process(config_filename: str, num_chunks: int = 1):
164
168
 
165
169
  def process_file_list(file_list, c):
166
170
  processing_pipeline = Pipeline(pipeline_config)
167
- for filename in track(file_list, description=f'[blue]Processing progress (chunk {c})',
168
- disable=c != 0):
169
- try:
170
- logger.debug(f'Chunk {c} starting to process {filename}')
171
- processing_pipeline.run(filename)
172
- except Exception as e:
173
- logger.warning('[red]An error occured in processing, ' +
174
- 'skipping rest of pipeline and moving to next image.' +
175
- f'(chunk {c})')
176
- logger.error(e)
177
- logger.debug(''.join(traceback.format_tb(e.__traceback__)))
171
+
172
+ with get_custom_progress_bar(f'[blue]Processing progress (chunk {c})', disable=c != 0) as pbar:
173
+ for filename in pbar.track(file_list, description=f'[blue]Processing progress (chunk {c})'):
174
+ try:
175
+ logger.debug(f'Chunk {c} starting to process {filename}')
176
+ processing_pipeline.run(filename)
177
+ except Exception as e:
178
+ logger.warning('[red]An error occured in processing, ' +
179
+ 'skipping rest of pipeline and moving to next image.' +
180
+ f'(chunk {c})')
181
+ logger.error(e)
182
+ logger.debug(''.join(traceback.format_tb(e.__traceback__)))
178
183
 
179
184
  # With one chunk we keep the non-threaded functionality to ensure backwards compatibility
185
+ job_list = []
180
186
  if num_chunks == 1:
181
187
  process_file_list(raw_files, 0)
182
188
  else:
183
189
  for c, chunk in enumerate(raw_files.chunked_files):
184
190
  job = threading.Thread(target=process_file_list, args=(chunk, c, ))
185
191
  job.start()
192
+ job_list.append(job)
193
+
194
+ # Calculate and print total processing time
195
+ # If we are using threads, make sure all jobs have finished
196
+ [job.join() for job in job_list]
197
+ time_total = pd.to_timedelta(time.time() - t1, 'seconds')
198
+ with Progress(transient=True) as progress:
199
+ progress.console.print(f"[blue]PROCESSING COMPLETED IN {time_total}")
186
200
 
187
201
 
188
202
  @app.command()
@@ -249,5 +263,21 @@ def check_chunks(chunks, pipeline_config):
249
263
  raise RuntimeError('Output mode must be set to "append = false" in "output" step when using more than one chunk')
250
264
 
251
265
 
266
+ def get_custom_progress_bar(description, disable):
267
+ ''' Create a custom rich.progress.Progress object for displaying progress bars'''
268
+ progress = Progress(
269
+ rich.progress.TextColumn(description),
270
+ rich.progress.BarColumn(),
271
+ rich.progress.TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
272
+ rich.progress.MofNCompleteColumn(),
273
+ rich.progress.TextColumn("•"),
274
+ rich.progress.TimeElapsedColumn(),
275
+ rich.progress.TextColumn("•"),
276
+ rich.progress.TimeRemainingColumn(),
277
+ disable=disable
278
+ )
279
+ return progress
280
+
281
+
252
282
  if __name__ == "__main__":
253
283
  app()
@@ -4,6 +4,7 @@ Module for managing the PyOpia processing pipeline
4
4
  Refer to the :class:`Pipeline` class documentation for examples of how to process datasets and images
5
5
  '''
6
6
  from typing import TypedDict
7
+ import time
7
8
  import datetime
8
9
  import pandas as pd
9
10
  from operator import methodcaller
@@ -114,7 +115,10 @@ class Pipeline():
114
115
  continue
115
116
 
116
117
  logger.info(f'Running pipeline step: {stepname}')
118
+ t1 = time.time()
117
119
  self.run_step(stepname)
120
+ t2 = time.time()
121
+ logger.debug(f'Running pipeline step {stepname} took {t2-t1:.3f} seconds')
118
122
 
119
123
  # Check for signal from this step that we should skip remaining pipeline for this image
120
124
  if self.data['skip_next_steps']:
@@ -331,26 +335,32 @@ class FilesToProcess:
331
335
  '''Build file list from glob pattern if specified.
332
336
  Create FilesToProcess.chunked_files is chunks specified
333
337
  File list from glob will be sorted.
338
+ If a filelist file is specified, load the list from there without sorting.
334
339
 
335
340
  Parameters
336
341
  ----------
337
342
  glob_pattern : str, optional
338
- Glob pattern, by default None
343
+ Glob pattern, by default None. If it ends with .txt, interpret as a filelist file.
339
344
  '''
340
345
  def __init__(self, glob_pattern=None):
341
346
  self.files = None
342
347
  self.background_files = []
343
348
  self.chunked_files = []
344
349
  if glob_pattern is not None:
345
- self.files = sorted(glob(glob_pattern))
350
+ # If a .txt file is specified, this indicates we should get the filelist from there
351
+ if glob_pattern.endswith('.txt'):
352
+ self.from_filelist_file(glob_pattern)
353
+ else:
354
+ self.files = sorted(glob(glob_pattern))
346
355
 
347
356
  def from_filelist_file(self, path_to_filelist):
348
357
  '''
349
358
  Initialize explicit list of files to process from a text file.
350
359
  The text file should contain one path to an image per line, which should be processed in order.
351
360
  '''
361
+ logger.info(f'Loading explicit image file list from file: {path_to_filelist}')
352
362
  with open(path_to_filelist, 'r') as fh:
353
- self.files = list(fh.readlines())
363
+ self.files = [line.rstrip() for line in fh.readlines()]
354
364
 
355
365
  def to_filelist_file(self, path_to_filelist):
356
366
  '''Write file list to a txt file
@@ -1 +0,0 @@
1
- __version__ = '2.5.13'
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