scipion-pyworkflow 3.11.0__py3-none-any.whl → 3.11.2__py3-none-any.whl

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 (104) hide show
  1. pyworkflow/apps/__init__.py +29 -0
  2. pyworkflow/apps/pw_manager.py +37 -0
  3. pyworkflow/apps/pw_plot.py +51 -0
  4. pyworkflow/apps/pw_project.py +130 -0
  5. pyworkflow/apps/pw_protocol_list.py +143 -0
  6. pyworkflow/apps/pw_protocol_run.py +51 -0
  7. pyworkflow/apps/pw_run_tests.py +268 -0
  8. pyworkflow/apps/pw_schedule_run.py +322 -0
  9. pyworkflow/apps/pw_sleep.py +37 -0
  10. pyworkflow/apps/pw_sync_data.py +440 -0
  11. pyworkflow/apps/pw_viewer.py +78 -0
  12. pyworkflow/constants.py +1 -1
  13. pyworkflow/gui/__init__.py +36 -0
  14. pyworkflow/gui/browser.py +768 -0
  15. pyworkflow/gui/canvas.py +1190 -0
  16. pyworkflow/gui/dialog.py +981 -0
  17. pyworkflow/gui/form.py +2727 -0
  18. pyworkflow/gui/graph.py +247 -0
  19. pyworkflow/gui/graph_layout.py +271 -0
  20. pyworkflow/gui/gui.py +571 -0
  21. pyworkflow/gui/matplotlib_image.py +233 -0
  22. pyworkflow/gui/plotter.py +247 -0
  23. pyworkflow/gui/project/__init__.py +25 -0
  24. pyworkflow/gui/project/base.py +193 -0
  25. pyworkflow/gui/project/constants.py +139 -0
  26. pyworkflow/gui/project/labels.py +205 -0
  27. pyworkflow/gui/project/project.py +491 -0
  28. pyworkflow/gui/project/searchprotocol.py +240 -0
  29. pyworkflow/gui/project/searchrun.py +181 -0
  30. pyworkflow/gui/project/steps.py +171 -0
  31. pyworkflow/gui/project/utils.py +332 -0
  32. pyworkflow/gui/project/variables.py +179 -0
  33. pyworkflow/gui/project/viewdata.py +472 -0
  34. pyworkflow/gui/project/viewprojects.py +519 -0
  35. pyworkflow/gui/project/viewprotocols.py +2141 -0
  36. pyworkflow/gui/project/viewprotocols_extra.py +562 -0
  37. pyworkflow/gui/text.py +774 -0
  38. pyworkflow/gui/tooltip.py +185 -0
  39. pyworkflow/gui/tree.py +684 -0
  40. pyworkflow/gui/widgets.py +307 -0
  41. pyworkflow/mapper/__init__.py +26 -0
  42. pyworkflow/mapper/mapper.py +226 -0
  43. pyworkflow/mapper/sqlite.py +1583 -0
  44. pyworkflow/mapper/sqlite_db.py +145 -0
  45. pyworkflow/object.py +1 -0
  46. pyworkflow/plugin.py +4 -4
  47. pyworkflow/project/__init__.py +31 -0
  48. pyworkflow/project/config.py +454 -0
  49. pyworkflow/project/manager.py +180 -0
  50. pyworkflow/project/project.py +2095 -0
  51. pyworkflow/project/usage.py +165 -0
  52. pyworkflow/protocol/__init__.py +38 -0
  53. pyworkflow/protocol/bibtex.py +48 -0
  54. pyworkflow/protocol/constants.py +87 -0
  55. pyworkflow/protocol/executor.py +515 -0
  56. pyworkflow/protocol/hosts.py +318 -0
  57. pyworkflow/protocol/launch.py +277 -0
  58. pyworkflow/protocol/package.py +42 -0
  59. pyworkflow/protocol/params.py +781 -0
  60. pyworkflow/protocol/protocol.py +2712 -0
  61. pyworkflow/resources/protlabels.xcf +0 -0
  62. pyworkflow/resources/sprites.png +0 -0
  63. pyworkflow/resources/sprites.xcf +0 -0
  64. pyworkflow/template.py +1 -1
  65. pyworkflow/tests/__init__.py +29 -0
  66. pyworkflow/tests/test_utils.py +25 -0
  67. pyworkflow/tests/tests.py +342 -0
  68. pyworkflow/utils/__init__.py +38 -0
  69. pyworkflow/utils/dataset.py +414 -0
  70. pyworkflow/utils/echo.py +104 -0
  71. pyworkflow/utils/graph.py +169 -0
  72. pyworkflow/utils/log.py +293 -0
  73. pyworkflow/utils/path.py +528 -0
  74. pyworkflow/utils/process.py +154 -0
  75. pyworkflow/utils/profiler.py +92 -0
  76. pyworkflow/utils/progressbar.py +154 -0
  77. pyworkflow/utils/properties.py +618 -0
  78. pyworkflow/utils/reflection.py +129 -0
  79. pyworkflow/utils/utils.py +880 -0
  80. pyworkflow/utils/which.py +229 -0
  81. pyworkflow/webservices/__init__.py +8 -0
  82. pyworkflow/webservices/config.py +8 -0
  83. pyworkflow/webservices/notifier.py +152 -0
  84. pyworkflow/webservices/repository.py +59 -0
  85. pyworkflow/webservices/workflowhub.py +86 -0
  86. pyworkflowtests/tests/__init__.py +0 -0
  87. pyworkflowtests/tests/test_canvas.py +72 -0
  88. pyworkflowtests/tests/test_domain.py +45 -0
  89. pyworkflowtests/tests/test_logs.py +74 -0
  90. pyworkflowtests/tests/test_mappers.py +392 -0
  91. pyworkflowtests/tests/test_object.py +507 -0
  92. pyworkflowtests/tests/test_project.py +42 -0
  93. pyworkflowtests/tests/test_protocol_execution.py +146 -0
  94. pyworkflowtests/tests/test_protocol_export.py +78 -0
  95. pyworkflowtests/tests/test_protocol_output.py +158 -0
  96. pyworkflowtests/tests/test_streaming.py +47 -0
  97. pyworkflowtests/tests/test_utils.py +210 -0
  98. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.2.dist-info}/METADATA +2 -2
  99. scipion_pyworkflow-3.11.2.dist-info/RECORD +162 -0
  100. scipion_pyworkflow-3.11.0.dist-info/RECORD +0 -71
  101. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.2.dist-info}/WHEEL +0 -0
  102. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.2.dist-info}/entry_points.txt +0 -0
  103. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.2.dist-info}/licenses/LICENSE.txt +0 -0
  104. {scipion_pyworkflow-3.11.0.dist-info → scipion_pyworkflow-3.11.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,440 @@
1
+ #!/usr/bin/env python
2
+ # **************************************************************************
3
+ # *
4
+ # * Authors: I. Foche Perez (ifoche@cnb.csic.es)
5
+ # * J. Burguet Castell (jburguet@cnb.csic.es)
6
+ # *
7
+ # * Unidad de Bioinformatica of Centro Nacional de Biotecnologia, CSIC
8
+ # *
9
+ # * This program is free software; you can redistribute it and/or modify
10
+ # * it under the terms of the GNU General Public License as published by
11
+ # * the Free Software Foundation; either version 3 of the License, or
12
+ # * (at your option) any later version.
13
+ # *
14
+ # * This program is distributed in the hope that it will be useful,
15
+ # * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # * GNU General Public License for more details.
18
+ # *
19
+ # * You should have received a copy of the GNU General Public License
20
+ # * along with this program; if not, write to the Free Software
21
+ # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22
+ # * 02111-1307 USA
23
+ # *
24
+ # * All comments concerning this program package may be sent to the
25
+ # * e-mail address 'scipion@cnb.csic.es'
26
+ # *
27
+ # **************************************************************************
28
+
29
+ """
30
+ Scipion data synchronization.
31
+
32
+ Get(put) tests data, from(to) the server to(from) the $SCIPION_TESTS folder.
33
+ """
34
+ import logging
35
+ logger = None
36
+
37
+ import sys
38
+ import os
39
+ from os.path import join, isdir, exists, relpath, dirname
40
+ from subprocess import call
41
+ import time
42
+ import argparse
43
+ import hashlib
44
+ import getpass
45
+ from urllib.request import urlopen, urlretrieve
46
+
47
+ import pyworkflow as pw
48
+ from pyworkflow.utils import redB, red, green, yellow
49
+
50
+
51
+ def main():
52
+
53
+ #Configure logging
54
+ logging.basicConfig(level=pw.Config.SCIPION_LOG_LEVEL, format=pw.Config.SCIPION_LOG_FORMAT)
55
+ global logger
56
+ logger = logging.getLogger(__name__)
57
+
58
+ # Get arguments.
59
+ args = get_parser().parse_args()
60
+
61
+ # Dispatch the easy cases first (list and check), and then take care of
62
+ # the more complex ones.
63
+ if args.list:
64
+ listDatasets(args.url)
65
+ sys.exit(0)
66
+
67
+ if args.check:
68
+ if not args.datasets:
69
+ datasets = [x.decode("utf-8").strip('./\n') for x in urlopen('%s/MANIFEST' % args.url)]
70
+ else:
71
+ datasets = args.datasets
72
+
73
+ logger.info('Checking %s at %s.' % (' '.join(datasets), args.url))
74
+
75
+ all_uptodate = True
76
+ for dataset in datasets:
77
+ all_uptodate &= check(dataset, url=args.url, verbose=args.verbose)
78
+ if all_uptodate:
79
+ logger.info('All datasets are up-to-date.')
80
+ sys.exit(0)
81
+ else:
82
+ logger.error('Some datasets are not updated.')
83
+ sys.exit(1)
84
+
85
+ if not args.datasets:
86
+ sys.exit('At least --list, --check or datasets needed.\n'
87
+ 'Run with --help for more info.')
88
+
89
+ logger.info('Selected datasets: %s' % yellow(' '.join(args.datasets)))
90
+
91
+ testFolder = pw.Config.SCIPION_TESTS
92
+
93
+ if args.format:
94
+ for dataset in args.datasets:
95
+ datasetFolder = join(testFolder, dataset)
96
+ logger.info('Formatting %s (creating MANIFEST file)' % dataset)
97
+
98
+ if not exists(datasetFolder):
99
+ sys.exit('ERROR: %s does not exist in datasets folder %s.' %
100
+ (dataset, testFolder))
101
+ createMANIFEST(datasetFolder)
102
+ sys.exit(0)
103
+
104
+ if args.download:
105
+ # Download datasets.
106
+ try:
107
+ for dataset in args.datasets:
108
+ if exists(join(testFolder, dataset)):
109
+ logger.info('Local copy of dataset %s detected.' % dataset)
110
+ logger.info('Checking for updates...')
111
+ update(dataset, url=args.url, verbose=args.verbose)
112
+ else:
113
+ logger.info('Dataset %s not in local machine. '
114
+ 'Downloading...' % dataset)
115
+ download(dataset, url=args.url, verbose=args.verbose)
116
+ except IOError as e:
117
+ logger.warning('%s' % e)
118
+ if e.errno == 13: # permission denied
119
+ logger.warning('Maybe you need to run as the user that '
120
+ 'did the global installation?')
121
+ sys.exit(1)
122
+ sys.exit(0)
123
+
124
+ if args.upload:
125
+ # Upload datasets.
126
+ for dataset in args.datasets:
127
+ try:
128
+ upload(dataset, login=args.login,
129
+ remoteFolder=args.remotefolder, delete=args.delete)
130
+ except Exception as e:
131
+ logger.error('Error when uploading dataset %s: %s' % (dataset, e))
132
+ if ask() != 'y':
133
+ sys.exit(1)
134
+ sys.exit(0)
135
+
136
+ # If we get here, we did not use the right arguments. Show a little help.
137
+ get_parser().print_usage()
138
+
139
+
140
+ def get_parser():
141
+ """ Return the argparse parser, so we can get the arguments """
142
+
143
+ parser = argparse.ArgumentParser(description=__doc__)
144
+ g = parser.add_mutually_exclusive_group()
145
+ g.add_argument('--download', action='store_true', help="Download dataset.")
146
+ g.add_argument(
147
+ '--upload', action='store_true',
148
+ help=("Upload local dataset to the server. The dataset name must be "
149
+ "the name of its folder relative to the $%s folder." % pw.SCIPION_TESTS))
150
+ g.add_argument(
151
+ '--list', action='store_true',
152
+ help=('List local datasets (from $%s) and remote ones '
153
+ '(remote url can be specified with --url).' % pw.SCIPION_TESTS))
154
+ g.add_argument(
155
+ '--format', action='store_true',
156
+ help='Create a MANIFEST file with checksums in the datasets folders.')
157
+ add = parser.add_argument # shortcut
158
+ add('datasets', metavar='DATASET', nargs='*', help='Name of a dataset.')
159
+ add('--delete', action='store_true',
160
+ help=('When uploading, delete any remote files in the dataset not '
161
+ 'present in local. It leaves the remote scipion data directory '
162
+ 'as it is in the local one. Dangerous, use with caution.'))
163
+ add('-u', '--url', default=pw.Config.SCIPION_URL_TESTDATA,
164
+ help='URL where remote datasets will be looked for.')
165
+ add('--check', action='store_true',
166
+ help='See if there is any remote dataset not in sync with locals.')
167
+ add('-l', '--login', default='scipion@scipion.cnb.csic.es', help='ssh login string. For upload')
168
+ add('-rf', '--remotefolder', default='scipionfiles/downloads/scipion/data/tests',
169
+ help='remote folder to put the dataset there. For upload.')
170
+ add('-v', '--verbose', action='store_true', help='Print more details.')
171
+
172
+ return parser
173
+
174
+
175
+ def listDatasets(url):
176
+ """ Print a list of local and remote datasets """
177
+
178
+ tdir = pw.Config.SCIPION_TESTS
179
+ if exists(tdir):
180
+ print("Local datasets in %s" % yellow(tdir))
181
+ for folder in sorted(os.listdir(tdir)):
182
+ if isdir(join(tdir, folder)):
183
+ if exists(join(tdir, folder, 'MANIFEST')):
184
+ print(" * %s" % folder)
185
+ else:
186
+ print(" * %s (not in dataset format)" % folder)
187
+ else:
188
+ print(yellow("No local datasets were detected. Test dataset directory is "
189
+ "missing. Expected: %s" % tdir))
190
+
191
+ try:
192
+ print("\nRemote datasets in %s" % yellow(url))
193
+ for line in sorted(urlopen('%s/MANIFEST' % url)):
194
+ print(" * %s" % line.decode("utf-8").strip('./\n'))
195
+ except Exception as e:
196
+ logger.info("Error reading %s (%s)" % (url, e))
197
+
198
+
199
+ def check(dataset, url, verbose=False, updateMANIFEST=False):
200
+ """ See if our local copy of dataset is the same as the remote one.
201
+ Return True if it is (if all the checksums are equal), False if not.
202
+ """
203
+ def vlog(txt): logger.info(txt) if verbose else None # verbose log
204
+
205
+ vlog("Checking dataset %s ... " % dataset)
206
+
207
+ if updateMANIFEST:
208
+ createMANIFEST(join(pw.Config.SCIPION_TESTS, dataset))
209
+ else:
210
+ vlog("(not updating local MANIFEST) ")
211
+
212
+ try:
213
+ md5sRemote = dict(x.decode("utf-8").split() for x in
214
+ urlopen('%s/%s/MANIFEST' % (url, dataset)))
215
+
216
+ md5sLocal = dict(x.split() for x in
217
+ open('%s/MANIFEST' %
218
+ join(pw.Config.SCIPION_TESTS, dataset)))
219
+ if md5sRemote == md5sLocal:
220
+ vlog("\tlooks up-to-date\n")
221
+ return True
222
+ else:
223
+ vlog("\thas differences\n")
224
+ flocal = set(md5sLocal.keys())
225
+ fremote = set(md5sRemote.keys())
226
+
227
+ def show(txt, lst):
228
+ if lst:
229
+ vlog(" %s: %s\n" % (txt, ' '.join(lst)))
230
+ show("Local files missing in the server", flocal - fremote)
231
+ show("Remote files missing locally", fremote - flocal)
232
+ show("Files with differences", [f for f in fremote & flocal
233
+ if md5sLocal[f] != md5sRemote[f]])
234
+ return False
235
+ except Exception as e:
236
+ logger.error("Can't check dataset %s." % dataset, exc_info=e)
237
+ return False
238
+
239
+
240
+ def download(dataset, destination=None, url=None, verbose=False):
241
+ """ Download all the data files mentioned in url/dataset/MANIFEST """
242
+ # Get default values for variables if we got None.
243
+ destination = destination or pw.Config.SCIPION_TESTS
244
+
245
+ # First make sure that we ask for a known dataset.
246
+ if dataset not in [x.decode('utf-8').strip('./\n') for x in urlopen('%s/MANIFEST' % url)]:
247
+ logger.info("Unknown dataset: %s" % red(dataset))
248
+ logger.info("Use --list to see the available datasets.")
249
+ return
250
+
251
+ # Retrieve the dataset's MANIFEST file.
252
+ # It contains a list of "file md5sum" of all files included in the dataset.
253
+ datasetFolder = join(destination, dataset)
254
+ os.makedirs(datasetFolder)
255
+ manifest = join(destination, dataset, 'MANIFEST')
256
+ try:
257
+ if verbose:
258
+ logger.info("Retrieving MANIFEST file")
259
+ open(manifest, 'wb').writelines(
260
+ urlopen('%s/%s/MANIFEST' % (url, dataset)))
261
+ except Exception as e:
262
+ logger.info("ERROR reading %s/%s/MANIFEST (%s)" % (url, dataset, e))
263
+ return
264
+
265
+ # Now retrieve all of the files mentioned in MANIFEST, and check their md5.
266
+ logger.info('Fetching files of dataset "%s"...' % dataset)
267
+ lines = open(manifest).readlines()
268
+ done = 0.0 # fraction already done
269
+ inc = 1.0 / len(lines) # increment, how much each iteration represents
270
+ for line in lines:
271
+ fname, md5Remote = line.strip().split()
272
+ fpath = join(datasetFolder, fname)
273
+ try:
274
+ # Download content and create file with it.
275
+ if not isdir(dirname(fpath)):
276
+ os.makedirs(dirname(fpath))
277
+ open(fpath, 'wb').writelines(
278
+ urlopen('%s/%s/%s' % (url, dataset, fname)))
279
+
280
+ md5 = md5sum(fpath)
281
+ if md5 != md5Remote:
282
+ raise AssertionError("Bad md5. Expected: %s Computed: %s" % (md5Remote, md5))
283
+
284
+ done += inc
285
+ if verbose:
286
+ logger.info(redB("%3d%% " % (100 * done)) + fname)
287
+ else:
288
+ sys.stdout.write(redB("#") * (int(50*done)-int(50*(done-inc))))
289
+ sys.stdout.flush()
290
+ except Exception as e:
291
+ logger.info("\nError in %s (%s)" % (fname, e))
292
+ logger.info("URL: %s/%s/%s" % (url, dataset, fname))
293
+ logger.info("Destination: %s" % fpath)
294
+ if ask("Continue downloading? (y/[n]): ", ['y', 'n', '']) != 'y':
295
+ return
296
+
297
+
298
+ def update(dataset, workingCopy=None, url=None, verbose=False):
299
+ """ Update local dataset with the contents of the remote one.
300
+ It compares the md5 of remote files in url/dataset/MANIFEST with the
301
+ ones in workingCopy/dataset/MANIFEST, and downloads only when necessary.
302
+ """
303
+ # Get default values for variables if we got None.
304
+ workingCopy = workingCopy or pw.Config.SCIPION_TESTS
305
+
306
+ # Verbose log
307
+ def vlog(txt): logger.info(txt) if verbose else None
308
+
309
+ # Read contents of *remote* MANIFEST file, and create a dict {fname: md5}
310
+ manifest = urlopen('%s/%s/MANIFEST' % (url, dataset)).readlines()
311
+ md5sRemote = dict(x.decode("utf-8").strip().split() for x in manifest)
312
+
313
+ # Update and read contents of *local* MANIFEST file, and create a dict
314
+ datasetFolder = join(workingCopy, dataset)
315
+ try:
316
+ last = max(os.stat(join(datasetFolder, x)).st_mtime for x in md5sRemote)
317
+ t_manifest = os.stat(join(datasetFolder, 'MANIFEST')).st_mtime
318
+ if not (t_manifest > last and time.time() - t_manifest < 60*60*24*7):
319
+ raise AssertionError("Manifest times seems to be wrong.")
320
+ except (OSError, IOError, AssertionError) as e:
321
+ logger.info("Regenerating local MANIFEST...")
322
+ createMANIFEST(datasetFolder)
323
+ md5sLocal = dict(x.strip().split() for x in open(join(datasetFolder, 'MANIFEST')))
324
+
325
+ # Check that all the files mentioned in MANIFEST are up-to-date
326
+ logger.info("Verifying MD5s...")
327
+
328
+ filesUpdated = 0 # number of files that have been updated
329
+ taintedMANIFEST = False # can MANIFEST be out of sync?
330
+ downloadingPrinted = False
331
+ for fname in md5sRemote:
332
+ fpath = join(datasetFolder, fname)
333
+ try:
334
+ if exists(fpath) and md5sLocal[fname] == md5sRemote[fname]:
335
+ vlog("\r %s %s\n" % (green("OK"), fname))
336
+ pass # just to emphasize that we do nothing in this case
337
+ else:
338
+ if not downloadingPrinted:
339
+ verboseMsg = " Next time use -v for more details." if not verbose else ""
340
+ logger.info("%s differs. Downloading new version.%s" % (fname, verboseMsg))
341
+
342
+ vlog("\r %s %s (downloading... " % (red("XX"), fname))
343
+ if not isdir(dirname(fpath)):
344
+ os.makedirs(dirname(fpath))
345
+
346
+ urlretrieve('%s/%s/%s' % (url, dataset, fname)
347
+ , fpath)
348
+
349
+ vlog("done)")
350
+ filesUpdated += 1
351
+ except Exception as e:
352
+ logger.error("Couldn't update %s." % fname, exc_info= e)
353
+ taintedMANIFEST = True # if we don't update, it can be wrong
354
+
355
+ logger.info("...done. Updated files: %d" % filesUpdated)
356
+
357
+ # Save the new MANIFEST file in the folder of the downloaded dataset
358
+ if filesUpdated > 0:
359
+ open(join(datasetFolder, 'MANIFEST'), 'w').writelines(md5sRemote)
360
+
361
+ if taintedMANIFEST:
362
+ logger.info("Some files could not be updated. Regenerating local MANIFEST ...")
363
+ createMANIFEST(datasetFolder)
364
+
365
+
366
+ def upload(dataset, login, remoteFolder, delete=False):
367
+ """ Upload a dataset to our repository """
368
+
369
+ localFolder = join(pw.Config.SCIPION_TESTS, dataset)
370
+
371
+ if not exists(localFolder):
372
+ sys.exit("ERROR: local folder %s does not exist." % localFolder)
373
+
374
+ logger.info("Warning: Uploading, please BE CAREFUL! This can be dangerous.")
375
+ logger.info('You are going to be connected to "%s" to write in folder '
376
+ '"%s" the dataset "%s".' % (login, remoteFolder, dataset))
377
+ if ask() == 'n':
378
+ return
379
+
380
+ # First make sure we have our MANIFEST file up-to-date
381
+ logger.info("Updating local MANIFEST file with MD5 info...")
382
+ createMANIFEST(localFolder)
383
+
384
+ # Upload the dataset files (with rsync)
385
+ logger.info("Uploading files...")
386
+ call(['rsync', '-rlv', '--chmod=a+r', localFolder,
387
+ '%s:%s' % (login, remoteFolder)] + (['--delete'] if delete else []))
388
+
389
+ # Regenerate remote MANIFEST (which contains a list of datasets)
390
+ logger.info("Regenerating remote MANIFEST file...")
391
+ call(['ssh', login,
392
+ 'cd %s && find -type d -mindepth 1 -maxdepth 1 > MANIFEST' % remoteFolder])
393
+ # This is a file that just contains the name of the directories
394
+ # in remoteFolder. Nothing to do with the MANIFEST files in
395
+ # the datasets, which contain file names and md5s.
396
+
397
+ # Leave a register (log file)
398
+ logger.info("Logging modification attempt in modifications.log ...")
399
+ log = """++++
400
+ Modification to %s dataset made at
401
+ %s
402
+ by %s at %s
403
+ ----""" % (dataset, time.asctime(), getpass.getuser(), ' '.join(os.uname()))
404
+ call(['ssh', login,
405
+ 'echo "%s" >> %s' % (log, join(remoteFolder, 'modifications.log'))])
406
+ logger.info("...done.")
407
+
408
+
409
+ def createMANIFEST(path):
410
+ """ Create a MANIFEST file in path with the md5 of all files below """
411
+
412
+ with open(join(path, 'MANIFEST'), 'w') as manifest:
413
+ for root, dirs, files in os.walk(path):
414
+ for filename in set(files) - {'MANIFEST'}: # all but ourselves
415
+ fn = join(root, filename) # file to check
416
+ logger.info("Calculating md5 for local %s ... " % filename)
417
+ manifest.write('%s %s\n' % (relpath(fn, path), md5sum(fn)))
418
+ logger.info(green("DONE!"))
419
+
420
+ def md5sum(fname):
421
+ """ Return the md5 hash of file fname """
422
+
423
+ mhash = hashlib.md5()
424
+ with open(fname, 'rb') as f:
425
+ for chunk in iter(lambda: f.read(128 * mhash.block_size), b""):
426
+ mhash.update(chunk)
427
+ return mhash.hexdigest()
428
+
429
+
430
+ def ask(question="Continue? (y/n): ", allowed=None):
431
+ """ Ask the question until it returns one of the allowed responses """
432
+
433
+ while True:
434
+ ans = input(question)
435
+ if ans.lower() in (allowed if allowed else ['y', 'n']):
436
+ return ans
437
+
438
+
439
+ if __name__ == "__main__":
440
+ main()
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env python
2
+ # **************************************************************************
3
+ # *
4
+ # * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
5
+ # *
6
+ # * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
7
+ # *
8
+ # * This program is free software; you can redistribute it and/or modify
9
+ # * it under the terms of the GNU General Public License as published by
10
+ # * the Free Software Foundation; either version 3 of the License, or
11
+ # * (at your option) any later version.
12
+ # *
13
+ # * This program is distributed in the hope that it will be useful,
14
+ # * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # * GNU General Public License for more details.
17
+ # *
18
+ # * You should have received a copy of the GNU General Public License
19
+ # * along with this program; if not, write to the Free Software
20
+ # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21
+ # * 02111-1307 USA
22
+ # *
23
+ # * All comments concerning this program package may be sent to the
24
+ # * e-mail address 'scipion@cnb.csic.es'
25
+ # *
26
+ # **************************************************************************
27
+
28
+ import os
29
+ import sys
30
+
31
+ from pwem.viewers import DataView
32
+ from pyworkflow import Config
33
+ from pyworkflow.gui.browser import FileBrowserWindow
34
+
35
+
36
+ def showDir(path):
37
+ window = FileBrowserWindow("Browsing: " + path, path=path)
38
+ window.show()
39
+
40
+
41
+ def showFile(path, viewParams):
42
+ DataView(path, viewParams).show()
43
+
44
+
45
+ if __name__ == '__main__':
46
+
47
+ if '-h' in sys.argv or '--help' in sys.argv:
48
+ print("usage: scipion3 view [file1 file2 file3 ... fileN]")
49
+
50
+ else:
51
+ if len(sys.argv) == 1: # no extra arguments, show current directory
52
+ showDir(os.getcwd())
53
+ else:
54
+ args = {'-i': []}
55
+ lastOpt = '-i'
56
+
57
+ for a in sys.argv[1:]:
58
+ if a.startswith('-'):
59
+ lastOpt = a
60
+ if lastOpt not in args:
61
+ args[lastOpt] = []
62
+ else:
63
+ args[lastOpt].append(a)
64
+
65
+ inputFiles = args['-i']
66
+ del args['-i']
67
+ viewParams = {}
68
+ for k, v in args.items():
69
+ viewParams[k.replace('-', '')] = ' '.join(v)
70
+
71
+ # Trigger plugin initialization
72
+ Config.getDomain().getPlugins()
73
+
74
+ for fn in inputFiles:
75
+ if os.path.isdir(fn):
76
+ showDir(fn)
77
+ else:
78
+ showFile(fn, viewParams)
pyworkflow/constants.py CHANGED
@@ -43,7 +43,7 @@ VERSION_1 = '1.0.0'
43
43
  VERSION_1_1 = '1.1.0'
44
44
  VERSION_1_2 = '1.2.0'
45
45
  VERSION_2_0 = '2.0.0'
46
- VERSION_3_0 = '3.11.0'
46
+ VERSION_3_0 = '3.11.2'
47
47
 
48
48
  # For a new release, define a new constant and assign it to LAST_VERSION
49
49
  # The existing one has to be added to OLD_VERSIONS list.
@@ -0,0 +1,36 @@
1
+ # **************************************************************************
2
+ # *
3
+ # * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
4
+ # *
5
+ # * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6
+ # *
7
+ # * This program is free software; you can redistribute it and/or modify
8
+ # * it under the terms of the GNU General Public License as published by
9
+ # * the Free Software Foundation; either version 3 of the License, or
10
+ # * (at your option) any later version.
11
+ # *
12
+ # * This program is distributed in the hope that it will be useful,
13
+ # * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # * GNU General Public License for more details.
16
+ # *
17
+ # * You should have received a copy of the GNU General Public License
18
+ # * along with this program; if not, write to the Free Software
19
+ # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20
+ # * 02111-1307 USA
21
+ # *
22
+ # * All comments concerning this program package may be sent to the
23
+ # * e-mail address 'scipion@cnb.csic.es'
24
+ # *
25
+ # **************************************************************************
26
+ from .gui import *
27
+ from .canvas import *
28
+ from .widgets import *
29
+ from .graph import *
30
+ from .graph_layout import *
31
+ from .tree import *
32
+ from .browser import *
33
+ from .text import *
34
+ from .dialog import *
35
+
36
+ from . import tooltip