scipion-pyworkflow 3.10.5__py3-none-any.whl → 3.11.0__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 (127) hide show
  1. pyworkflow/config.py +131 -67
  2. pyworkflow/constants.py +12 -2
  3. pyworkflow/object.py +3 -2
  4. pyworkflow/plugin.py +93 -44
  5. pyworkflow/project/scripts/fix_links.py +4 -1
  6. pyworkflow/resources/showj/arrowDown.png +0 -0
  7. pyworkflow/resources/showj/arrowUp.png +0 -0
  8. pyworkflow/resources/showj/background_section.png +0 -0
  9. pyworkflow/resources/showj/colRowModeOff.png +0 -0
  10. pyworkflow/resources/showj/colRowModeOn.png +0 -0
  11. pyworkflow/resources/showj/delete.png +0 -0
  12. pyworkflow/resources/showj/doc_icon.png +0 -0
  13. pyworkflow/resources/showj/download_icon.png +0 -0
  14. pyworkflow/resources/showj/enabled_gallery.png +0 -0
  15. pyworkflow/resources/showj/galleryViewOff.png +0 -0
  16. pyworkflow/resources/showj/galleryViewOn.png +0 -0
  17. pyworkflow/resources/showj/goto.png +0 -0
  18. pyworkflow/resources/showj/menu.png +0 -0
  19. pyworkflow/resources/showj/separator.png +0 -0
  20. pyworkflow/resources/showj/tableViewOff.png +0 -0
  21. pyworkflow/resources/showj/tableViewOn.png +0 -0
  22. pyworkflow/resources/showj/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  23. pyworkflow/resources/showj/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  24. pyworkflow/resources/showj/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  25. pyworkflow/resources/showj/volumeOff.png +0 -0
  26. pyworkflow/resources/showj/volumeOn.png +0 -0
  27. pyworkflow/viewer.py +23 -1
  28. pyworkflowtests/objects.py +2 -2
  29. pyworkflowtests/protocols.py +1 -3
  30. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info}/METADATA +21 -25
  31. scipion_pyworkflow-3.11.0.dist-info/RECORD +71 -0
  32. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info}/WHEEL +1 -1
  33. scipion_pyworkflow-3.11.0.dist-info/entry_points.txt +2 -0
  34. pyworkflow/apps/__init__.py +0 -29
  35. pyworkflow/apps/pw_manager.py +0 -37
  36. pyworkflow/apps/pw_plot.py +0 -51
  37. pyworkflow/apps/pw_project.py +0 -113
  38. pyworkflow/apps/pw_protocol_list.py +0 -143
  39. pyworkflow/apps/pw_protocol_run.py +0 -51
  40. pyworkflow/apps/pw_run_tests.py +0 -267
  41. pyworkflow/apps/pw_schedule_run.py +0 -322
  42. pyworkflow/apps/pw_sleep.py +0 -37
  43. pyworkflow/apps/pw_sync_data.py +0 -439
  44. pyworkflow/apps/pw_viewer.py +0 -78
  45. pyworkflow/gui/__init__.py +0 -36
  46. pyworkflow/gui/browser.py +0 -726
  47. pyworkflow/gui/canvas.py +0 -1190
  48. pyworkflow/gui/dialog.py +0 -977
  49. pyworkflow/gui/form.py +0 -2637
  50. pyworkflow/gui/graph.py +0 -247
  51. pyworkflow/gui/graph_layout.py +0 -271
  52. pyworkflow/gui/gui.py +0 -566
  53. pyworkflow/gui/matplotlib_image.py +0 -233
  54. pyworkflow/gui/plotter.py +0 -247
  55. pyworkflow/gui/project/__init__.py +0 -25
  56. pyworkflow/gui/project/base.py +0 -192
  57. pyworkflow/gui/project/constants.py +0 -139
  58. pyworkflow/gui/project/labels.py +0 -205
  59. pyworkflow/gui/project/project.py +0 -492
  60. pyworkflow/gui/project/searchprotocol.py +0 -154
  61. pyworkflow/gui/project/searchrun.py +0 -181
  62. pyworkflow/gui/project/steps.py +0 -171
  63. pyworkflow/gui/project/utils.py +0 -332
  64. pyworkflow/gui/project/variables.py +0 -179
  65. pyworkflow/gui/project/viewdata.py +0 -472
  66. pyworkflow/gui/project/viewprojects.py +0 -510
  67. pyworkflow/gui/project/viewprotocols.py +0 -2093
  68. pyworkflow/gui/project/viewprotocols_extra.py +0 -560
  69. pyworkflow/gui/text.py +0 -771
  70. pyworkflow/gui/tooltip.py +0 -185
  71. pyworkflow/gui/tree.py +0 -684
  72. pyworkflow/gui/widgets.py +0 -307
  73. pyworkflow/mapper/__init__.py +0 -26
  74. pyworkflow/mapper/mapper.py +0 -222
  75. pyworkflow/mapper/sqlite.py +0 -1578
  76. pyworkflow/mapper/sqlite_db.py +0 -145
  77. pyworkflow/project/__init__.py +0 -31
  78. pyworkflow/project/config.py +0 -454
  79. pyworkflow/project/manager.py +0 -180
  80. pyworkflow/project/project.py +0 -2010
  81. pyworkflow/protocol/__init__.py +0 -38
  82. pyworkflow/protocol/bibtex.py +0 -48
  83. pyworkflow/protocol/constants.py +0 -87
  84. pyworkflow/protocol/executor.py +0 -455
  85. pyworkflow/protocol/hosts.py +0 -313
  86. pyworkflow/protocol/launch.py +0 -270
  87. pyworkflow/protocol/package.py +0 -42
  88. pyworkflow/protocol/params.py +0 -741
  89. pyworkflow/protocol/protocol.py +0 -2582
  90. pyworkflow/tests/__init__.py +0 -29
  91. pyworkflow/tests/test_utils.py +0 -25
  92. pyworkflow/tests/tests.py +0 -341
  93. pyworkflow/utils/__init__.py +0 -38
  94. pyworkflow/utils/dataset.py +0 -414
  95. pyworkflow/utils/echo.py +0 -104
  96. pyworkflow/utils/graph.py +0 -169
  97. pyworkflow/utils/log.py +0 -284
  98. pyworkflow/utils/path.py +0 -528
  99. pyworkflow/utils/process.py +0 -132
  100. pyworkflow/utils/profiler.py +0 -92
  101. pyworkflow/utils/progressbar.py +0 -154
  102. pyworkflow/utils/properties.py +0 -631
  103. pyworkflow/utils/reflection.py +0 -129
  104. pyworkflow/utils/utils.py +0 -879
  105. pyworkflow/utils/which.py +0 -229
  106. pyworkflow/webservices/__init__.py +0 -8
  107. pyworkflow/webservices/config.py +0 -11
  108. pyworkflow/webservices/notifier.py +0 -162
  109. pyworkflow/webservices/repository.py +0 -59
  110. pyworkflow/webservices/workflowhub.py +0 -74
  111. pyworkflowtests/tests/__init__.py +0 -0
  112. pyworkflowtests/tests/test_canvas.py +0 -72
  113. pyworkflowtests/tests/test_domain.py +0 -45
  114. pyworkflowtests/tests/test_logs.py +0 -74
  115. pyworkflowtests/tests/test_mappers.py +0 -392
  116. pyworkflowtests/tests/test_object.py +0 -507
  117. pyworkflowtests/tests/test_project.py +0 -42
  118. pyworkflowtests/tests/test_protocol_execution.py +0 -135
  119. pyworkflowtests/tests/test_protocol_export.py +0 -78
  120. pyworkflowtests/tests/test_protocol_output.py +0 -158
  121. pyworkflowtests/tests/test_streaming.py +0 -47
  122. pyworkflowtests/tests/test_utils.py +0 -210
  123. scipion_pyworkflow-3.10.5.dist-info/RECORD +0 -140
  124. scipion_pyworkflow-3.10.5.dist-info/dependency_links.txt +0 -1
  125. scipion_pyworkflow-3.10.5.dist-info/entry_points.txt +0 -5
  126. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info/licenses}/LICENSE.txt +0 -0
  127. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info}/top_level.txt +0 -0
@@ -1,414 +0,0 @@
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
- """
27
- # JMRT (2018-12-11) This module is almost not used at all. Maybe it
28
- can be removed in a future. Just kept here for the moment inside
29
- pw.utils and not imported by default
30
- """
31
-
32
- import os
33
- from collections import OrderedDict, namedtuple
34
-
35
- from pyworkflow.mapper import SqliteFlatDb, SqliteDb
36
-
37
-
38
- class DataSet(object):
39
- """ Holds several Tables
40
- All tables should have an unique tableName.
41
- """
42
-
43
- def __init__(self, tables, tableName=None, volumeName=None, numberSlices=0):
44
- self._tables = list(tables)
45
- self._tableName = tableName
46
- # FIXME: You have to see if the volumeName is used anywhere
47
- self._volumeName = volumeName
48
- self._numberSlices = numberSlices
49
- self.projectPath = None
50
-
51
- def currentTable(self):
52
- """ Returns the name of the last selected table. """
53
- return self._tableName
54
-
55
- def setVolumeName(self, volumeName):
56
- self._volumeName = volumeName
57
-
58
- def getVolumeName(self):
59
- return self._volumeName
60
-
61
- def setNumberSlices(self, numberSlices):
62
- self._numberSlices = numberSlices
63
-
64
- def getNumberSlices(self):
65
- return self._numberSlices
66
-
67
- def getNumberSlicesForTemplate(self):
68
- return range(self._numberSlices)
69
-
70
- def listTables(self):
71
- """ List the actual table names on the DataSet. """
72
- return self._tables
73
-
74
- def getTable(self, tableName=None):
75
- if tableName is None:
76
- tableName = self.listTables()[0]
77
- if tableName not in self._tables:
78
- raise Exception("DataSet: table '%s' not found.\n Current tables: %s" %
79
- (tableName, self._tables))
80
-
81
- table = self._loadTable(tableName)
82
- self._tableName = tableName
83
-
84
- return table
85
-
86
- def getTypeOfColumn(self, label):
87
- """ this method should be implemented by subclasses. """
88
- pass
89
-
90
- def _loadTable(self, tableName):
91
- """ this method should be implemented by subclasses. """
92
- pass
93
-
94
-
95
- class Table(object):
96
- """ Table to hold rows of data.
97
- A table contains a list of columns. """
98
- def __init__(self, *columns):
99
- self._columns = OrderedDict()
100
- self._rowDict = OrderedDict()
101
- self._addColumn(Column('id', int))
102
-
103
- for col in columns:
104
- self._addColumn(col)
105
-
106
- colNames = [col.getName() for col in self.iterColumns()]
107
- # This imply that columns can only be added in __init__
108
- self.Row = namedtuple('Row', colNames)
109
-
110
- def setLabelToRender(self, labelToRender):
111
- self._labelToRender = labelToRender
112
-
113
- def _addColumn(self, col):
114
- self._columns[col.getName()] = col
115
-
116
- def getColumnValues(self, columnName):
117
- if self.hasColumn(columnName):
118
- return [getattr(row, columnName) for row in self.iterRows()]
119
- else:
120
- return [None] * self.getSize()
121
-
122
- def iterColumns(self):
123
- return self._columns.values()
124
-
125
- def hasColumn(self, columnName):
126
- """ Return true if column exists """
127
- return columnName in self._columns
128
-
129
- def getColumn(self, columnName):
130
- if columnName not in self._columns:
131
- raise Exception('Table: column "%s" not found.\nCurrent columns: %s' % (
132
- columnName, '\n'.join(self._columns.keys())))
133
- return self._columns[columnName]
134
-
135
- def hasEnabledColumn(self):
136
- """ Return true if enabled column exists """
137
- return self.hasColumn('enabled')
138
-
139
- def getColumns(self):
140
- """ Return all columns. """
141
- return self._columns.values()
142
-
143
- def getNumberOfColumns(self):
144
- return len(self._columns)
145
-
146
- def getSize(self):
147
- """ Return the number of rows. """
148
- return len(self._rowDict)
149
-
150
- def getRows(self):
151
- """ Return all rows. """
152
- return [row for row in self.iterRows()]
153
-
154
- def getRow(self, rowId):
155
- return self._rowDict[rowId]
156
-
157
- def _setRow(self, rowId, row):
158
- self._rowDict[rowId] = row
159
-
160
- def getDataToRenderAndExtra(self):
161
- return zip(self.getIdColumn(),
162
- self.getColumnValues("enabled"),
163
- self.getDataToRender(),
164
- self.getTransformationMatrix())
165
-
166
- def getDataToRender(self):
167
- return self.getColumnValues(self._labelToRender)
168
-
169
- def getIdColumn(self):
170
- return self.getColumnValues("id")
171
-
172
- def getTransformationMatrix(self):
173
- return self.getColumnValues(self._labelToRender+"_transformationMatrix")
174
-
175
- def _convertValues(self, values):
176
- """ Convert the input values to the actual
177
- expected type of each column.
178
- """
179
- cValues = {}
180
- for k, v in values.items():
181
- col = self.getColumn(k)
182
- cValues[k] = col.convert(v)
183
-
184
- return cValues
185
-
186
- def addRow(self, rowId, **values):
187
- """ With this implementation the rowId should be provided.
188
- We need to work around to also allow automatic generation of id's
189
- """
190
- values['id'] = rowId
191
-
192
- for col in self.iterColumns():
193
- if col.getName() not in values:
194
- if col.hasDefault():
195
- values[col.getName()] = col.getDefault()
196
- else:
197
- raise Exception('Table: value for column "%s" not provided.' % col.getName())
198
-
199
- row = self.Row(**self._convertValues(values))
200
- self._setRow(rowId, row)
201
-
202
- def updateRow(self, rowId, **values):
203
- """ Update a row given its rowId and some values to update. """
204
- row = self.getRow(rowId)
205
- self._setRow(rowId, row._replace(**self._convertValues(values)))
206
-
207
- def iterRows(self):
208
- """ Iterate over the rows. """
209
- return self._rowDict.values()
210
-
211
- def getValueFromIndex(self, index, label):
212
- """ Return the value of the property 'label'
213
- in the element that has this 'index'.
214
- """
215
- value = list(self._rowDict.values())[index]._asdict()[label]
216
- return value
217
-
218
- def getIndexFromValue(self, value, label):
219
- """ Search the element that has property 'label'
220
- equals to value and returns its index.
221
- """
222
- for index, row in enumerate(self.iterRows()):
223
- if value == row._asdict()[label]:
224
- return index
225
- return -1
226
-
227
- def __str__(self):
228
- return '\n'.join([str(row) for row in self.iterRows()])
229
-
230
-
231
- # JMRT (2018-12-11) This constants are duplicated in showj, since this module
232
- # is not widely used I don't find convenient such a dependency
233
- COL_RENDER_NONE = 0
234
- COL_RENDER_ID = 1
235
- COL_RENDER_TEXT = 2
236
- COL_RENDER_IMAGE = 3
237
- COL_RENDER_CHECKBOX = 4
238
- COL_RENDER_VOLUME = 5
239
-
240
-
241
- class Column(object):
242
- def __init__(self, colName, colType=None, default=None,
243
- label=None, renderType=COL_RENDER_NONE):
244
- self._name = colName
245
- self._type = colType
246
- self._default = default
247
- self._label = label or colName
248
- self._renderType = renderType
249
-
250
- def getName(self):
251
- return self._name
252
-
253
- def getLabel(self):
254
- return self._label
255
-
256
- def getType(self):
257
- return self._type
258
-
259
- def convert(self, value):
260
- """ Try to convert the value to the column type. """
261
- return self._type(value)
262
-
263
- def hasDefault(self):
264
- return self._default is not None
265
-
266
- def getDefault(self):
267
- return self._default
268
-
269
- def getRenderType(self):
270
- return self._renderType
271
-
272
- def setRenderType(self, renderType):
273
- self._renderType = renderType
274
-
275
-
276
- class SqliteDataSet(DataSet):
277
- """ Provide a DataSet implementation based on sqlite file.
278
- The tables of the dataset will be the object tables in database.
279
- Each block is a table on the dataset.
280
- """
281
-
282
- def __init__(self, filename):
283
- self._dbName = filename
284
- db = SqliteDb()
285
- db._createConnection(filename, 1000)
286
- # Tables should be at pairs:
287
- # PREFIX_Classes
288
- # PREFIX_Objects
289
- # where PREFIX can be empty
290
- self.tablePrefixes = OrderedDict()
291
- tables = db.getTables()
292
- for t in tables:
293
- if t.endswith('Classes'):
294
- prefix = t.replace('Classes', '')
295
- to = prefix + 'Objects'
296
- if to not in tables:
297
- raise Exception('SqliteDataSet: table "%s" found, but not "%s"' % (t, to))
298
- flatDb = SqliteFlatDb(filename, tablePrefix=prefix)
299
- tableName = prefix + self._getPlural(flatDb.getSelfClassName())
300
- self.tablePrefixes[tableName] = prefix
301
- # tablePrefixes.append(prefix)
302
- DataSet.__init__(self, self.tablePrefixes.keys())
303
- db.close()
304
-
305
- def _getPlural(self, className):
306
- """ Get the plural of word for tables labels. """
307
- if className.startswith('Class'):
308
- return className.replace('Class', 'Classes')
309
- return className + 's'
310
-
311
- def _loadTable(self, tableName):
312
- """ Load information from tables PREFIX_Classes, PREFIX_Objects. """
313
-
314
- tableName = self.tablePrefixes[tableName]
315
-
316
- BASIC_COLUMNS = [Column('id', int, renderType=COL_RENDER_ID),
317
- Column('enabled', bool, renderType=COL_RENDER_CHECKBOX),
318
- Column('label', str),
319
- Column('comment', str),
320
- Column('creation', str)]
321
- # Load columns from PREFIX_Classes table
322
- columns = list(BASIC_COLUMNS)
323
- db = SqliteDb()
324
- db._createConnection(self._dbName, 1000)
325
- db.executeCommand("SELECT * FROM %sClasses;" % tableName)
326
- # This will store the images columns to join
327
- # the _index and the _filename
328
- imgCols = {}
329
- for row in db._iterResults():
330
- renderType = COL_RENDER_NONE
331
- colName = row['column_name']
332
- colLabel = row['label_property']
333
-
334
- if colLabel != 'self':
335
- # Keep track of _index and _filename pairs to mark as renderable images
336
- if colLabel.endswith('_index'):
337
- imgCols[colLabel.replace('_index', '')] = colName
338
-
339
- elif colLabel.endswith('_filename'):
340
-
341
- # TODO: Maybe not all the labels endswith "_filename"
342
- # have to be rendered.
343
- # for example in the RotSpectra with '_representative._filename'
344
-
345
- prefix = colLabel.replace('_filename', '')
346
- if prefix in imgCols:
347
- renderType = COL_RENDER_IMAGE
348
- imgCols[colName] = imgCols[prefix]
349
-
350
- # CTF FIX
351
- elif (colLabel.endswith('_psdFile') or
352
- colLabel.endswith('_enhanced_psd') or
353
- colLabel.endswith('_ctfmodel_quadrant') or
354
- colLabel.endswith('_ctfmodel_halfplane')):
355
-
356
- renderType = COL_RENDER_IMAGE
357
-
358
- if row['class_name'] == 'Boolean':
359
- renderType = COL_RENDER_CHECKBOX
360
- columns.append(Column(colName, str, label=colLabel, renderType=renderType))
361
- table = Table(*columns)
362
-
363
- checkedImgCols = {} # Check if the image columns are volumes
364
- # FIXME: Move this to scipion-em? Maybe remove the whole module that is not used?
365
- from pwem.emlib.image import ImageHandler
366
- ih = ImageHandler()
367
-
368
- # Populate the table in the DataSet
369
- db.executeCommand("SELECT * FROM %sObjects;" % tableName)
370
- for row in db._iterResults():
371
- rowDict = dict(row)
372
- for k, v in rowDict.items():
373
- if v is None:
374
- rowDict[k] = ''
375
- # Set the index@filename for images columns values
376
- if k in imgCols:
377
- colName = imgCols[k]
378
- index = rowDict[colName]
379
-
380
- filename = os.path.join(self.projectPath, rowDict[k])
381
- filepath = filename.replace(":mrc", "")
382
- if not checkedImgCols.get(colName, False):
383
- if os.path.exists(filepath):
384
- # print "Fn to get dims: %s@%s" % (index,filename)
385
- x, y, z, n = ih.getDimensions((index, filename))
386
- if z > 1:
387
- table.getColumn(k).setRenderType(COL_RENDER_VOLUME)
388
- checkedImgCols[colName] = True
389
- if index:
390
- rowDict[k] = '%06d@%s' % (index, filename)
391
- table.addRow(row['id'], **rowDict)
392
-
393
- return table
394
-
395
-
396
- class SingleFileDataSet(DataSet):
397
- """ DataSet implementation for single files such as Images or Volumes.
398
- """
399
-
400
- def __init__(self, filename):
401
- self._filename = filename
402
- self._tableName = ""
403
- DataSet.__init__(self, [self._tableName])
404
- self._table = self._createSingleTable()
405
-
406
- def _createSingleTable(self):
407
- table = Table(Column('filename', str,
408
- renderType=COL_RENDER_VOLUME)) # FIXME: for single images we need to read the dimensions
409
- table.addRow(1, filename=self._filename)
410
-
411
- return table
412
-
413
- def _loadTable(self, tableName):
414
- return self._table
pyworkflow/utils/echo.py DELETED
@@ -1,104 +0,0 @@
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
- """
27
- This module trace through printing
28
- module and class functions...
29
- Code from: http://wordaligned.org/articles/echo
30
- """
31
-
32
-
33
- import inspect
34
- import sys
35
-
36
-
37
- def name(item):
38
- """ Return an item's name. """
39
- return item.__name__
40
-
41
-
42
- def is_classmethod(instancemethod):
43
- """ Determine if an instancemethod is a classmethod. """
44
- return instancemethod.im_self is not None
45
-
46
-
47
- def is_class_private_name(name):
48
- """ Determine if a name is a class private name. """
49
- # Exclude system defined names such as __init__, __add__ etc
50
- return name.startswith("__") and not name.endswith("__")
51
-
52
-
53
- def method_name(method):
54
- """ Return a method's name.
55
-
56
- This function returns the name the method is accessed by from
57
- outside the class (i.e. it prefixes "private" methods appropriately).
58
- """
59
- mname = name(method)
60
- if is_class_private_name(mname):
61
- mname = "_%s%s" % (name(method.im_class), mname)
62
- return mname
63
-
64
-
65
- def format_args(args):
66
- print(args)
67
-
68
-
69
- def echo(fn, write=sys.stdout.write):
70
- print(fn)
71
-
72
-
73
- def echo_instancemethod(klass, method, write=sys.stdout.write):
74
- """ Change an instancemethod so that calls to it are echoed.
75
-
76
- Replacing a classmethod is a little more tricky.
77
- See: http://www.python.org/doc/current/ref/types.html
78
- """
79
- mname = method_name(method)
80
- never_echo = "__str__", "__repr__", # Avoid recursion printing method calls
81
- if mname in never_echo:
82
- pass
83
- elif is_classmethod(method):
84
- setattr(klass, mname, classmethod(echo(method.im_func, write)))
85
- else:
86
- setattr(klass, mname, echo(method, write))
87
-
88
-
89
- def echo_class(klass, write=sys.stdout.write):
90
- """ Echo calls to class methods and static functions
91
- """
92
- for _, method in inspect.getmembers(klass, inspect.ismethod):
93
- echo_instancemethod(klass, method, write)
94
- for _, fn in inspect.getmembers(klass, inspect.isfunction):
95
- setattr(klass, name(fn), staticmethod(echo(fn, write)))
96
-
97
-
98
- def echo_module(mod, write=sys.stdout.write):
99
- """ Echo calls to functions and methods in a module.
100
- """
101
- for fname, fn in inspect.getmembers(mod, inspect.isfunction):
102
- setattr(mod, fname, echo(fn, write))
103
- for _, klass in inspect.getmembers(mod, inspect.isclass):
104
- echo_class(klass, write)
pyworkflow/utils/graph.py DELETED
@@ -1,169 +0,0 @@
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
- """
27
- This module define a Graph class and some utilities
28
- """
29
- import logging
30
- logger = logging.getLogger(__name__)
31
-
32
-
33
- class Node(object):
34
- """ A node inside the graph. """
35
- _count = 1
36
-
37
- def __init__(self, name=None, label=None):
38
- self._children = []
39
- self._parents = []
40
-
41
- if name is None:
42
- name = str(self._count)
43
- self._count += 1
44
- self._name = name
45
-
46
- if label is None:
47
- label = name
48
- self._label = label
49
- self._fixed = False
50
-
51
- def getName(self):
52
- return self._name
53
-
54
- def getLabel(self):
55
- return self._label
56
-
57
- def setLabel(self, newLabel):
58
- self._label = newLabel
59
-
60
- def isRoot(self):
61
- return len(self._parents) == 0
62
-
63
- def getChildren(self):
64
- return self._children
65
-
66
- def addChild(self, *nodes):
67
- for n in nodes:
68
- if n not in self._children:
69
- self._children.append(n)
70
- n._parents.append(self)
71
-
72
- def getParent(self):
73
- """ Return the first parent in the list,
74
- if the node isRoot, None is returned.
75
- """
76
- if self.isRoot():
77
- return None
78
-
79
- return self._parents[0]
80
-
81
- def getParents(self):
82
- return self._parents
83
-
84
- def iterChildren(self):
85
- """ Iterate over all children and sub-children.
86
- Nodes can be visited more than once if it has
87
- more than one parent.
88
- """
89
- for child in self._children:
90
- for c in child.iterChildren():
91
- yield c
92
-
93
- yield self
94
-
95
- def countChildren(self, visitedNode=None, count=0):
96
- """ Iterate over all childs and subchilds.
97
- Nodes can be visited once
98
- """
99
- for child in self._children:
100
- if child._name not in visitedNode:
101
- visitedNode[child._name] = True
102
- child.countChildren(visitedNode)
103
- return len(visitedNode)
104
-
105
-
106
- def iterChildrenBreadth(self):
107
- """ Iter child nodes in a breadth-first order
108
- """
109
- for child in self._children:
110
- yield child
111
-
112
- for child in self._children:
113
- for child2 in child.iterChildrenBreadth():
114
- yield child2
115
-
116
- def __str__(self):
117
- return "Node (id=%s, label=%s, root=%s)" % (self._name,
118
- self.getLabel(),
119
- self.isRoot())
120
-
121
-
122
- class Graph(object):
123
- """Simple directed Graph class.
124
- Implemented using adjacency lists.
125
- """
126
-
127
- def __init__(self, rootName='ROOT', root=None):
128
- self._nodes = []
129
- self._nodesDict = {} # To retrieve nodes from name
130
- if root is None:
131
- self._root = self.createNode(rootName)
132
- else:
133
- self._root = root
134
- self._registerNode(root)
135
-
136
- def _registerNode(self, node):
137
- self._nodes.append(node)
138
- self._nodesDict[node.getName()] = node
139
- for child in node.getChildren():
140
- self._registerNode(child)
141
-
142
- def getRoot(self) -> Node:
143
- return self._root
144
-
145
- def createNode(self, nodeName, nodeLabel=None) -> Node:
146
- """ Add a node to the graph """
147
- node = Node(nodeName, nodeLabel)
148
- self._registerNode(node)
149
-
150
- return node
151
-
152
- def aliasNode(self, node, aliasName):
153
- """ Register an alias name for the node. """
154
- self._nodesDict[aliasName] = node
155
-
156
- def getNode(self, nodeName) -> Node:
157
- return self._nodesDict.get(nodeName, None)
158
-
159
- def getNodeNames(self):
160
- """ Returns all the keys in the node dictionary"""
161
- return self._nodesDict.keys()
162
-
163
- def getNodes(self):
164
- return self._nodes
165
-
166
- def getRootNodes(self):
167
- """ Return all nodes that have no parent. """
168
- return [n for n in self._nodes if n.isRoot()]
169
-