ProjectDjango/DjangoMigrationsListDialog.py

branch
eric7
changeset 180
64339135bd61
parent 175
30cb5e553e7e
child 181
2f5c3487139c
equal deleted inserted replaced
179:8413c2429808 180:64339135bd61
7 Module implementing a dialog show a list of all available migrations. 7 Module implementing a dialog show a list of all available migrations.
8 """ 8 """
9 9
10 from PyQt6.QtCore import pyqtSlot, Qt, QProcess, QTimer, QPoint 10 from PyQt6.QtCore import pyqtSlot, Qt, QProcess, QTimer, QPoint
11 from PyQt6.QtWidgets import ( 11 from PyQt6.QtWidgets import (
12 QDialog, QDialogButtonBox, QAbstractButton, 12 QDialog,
13 QHeaderView, QTreeWidgetItem, QMenu, QAbstractItemView, QInputDialog, 13 QDialogButtonBox,
14 QLineEdit 14 QAbstractButton,
15 QHeaderView,
16 QTreeWidgetItem,
17 QMenu,
18 QAbstractItemView,
19 QInputDialog,
20 QLineEdit,
15 ) 21 )
16 22
17 from EricWidgets import EricMessageBox 23 from EricWidgets import EricMessageBox
18 24
19 from .Ui_DjangoMigrationsListDialog import Ui_DjangoMigrationsListDialog 25 from .Ui_DjangoMigrationsListDialog import Ui_DjangoMigrationsListDialog
23 29
24 class DjangoMigrationsListDialog(QDialog, Ui_DjangoMigrationsListDialog): 30 class DjangoMigrationsListDialog(QDialog, Ui_DjangoMigrationsListDialog):
25 """ 31 """
26 Class implementing a dialog show a list of all available migrations. 32 Class implementing a dialog show a list of all available migrations.
27 """ 33 """
34
28 MigrationsListMode = "L" 35 MigrationsListMode = "L"
29 MigrationsPlanMode = "P" 36 MigrationsPlanMode = "P"
30 37
31 def __init__(self, mode, django, parent=None): 38 def __init__(self, mode, django, parent=None):
32 """ 39 """
33 Constructor 40 Constructor
34 41
35 @param mode mode of the dialog 42 @param mode mode of the dialog
36 @type str 43 @type str
37 @param django reference to the Django project object 44 @param django reference to the Django project object
38 @type Project 45 @type Project
39 @param parent reference to the parent widget 46 @param parent reference to the parent widget
40 @type QWidget 47 @type QWidget
41 """ 48 """
42 super().__init__(parent) 49 super().__init__(parent)
43 self.setupUi(self) 50 self.setupUi(self)
44 51
45 self.buttonBox.button( 52 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
46 QDialogButtonBox.StandardButton.Close).setEnabled(False) 53 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
47 self.buttonBox.button( 54
48 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
49
50 self.ioEncoding = Preferences.getSystem("IOEncoding") 55 self.ioEncoding = Preferences.getSystem("IOEncoding")
51 56
52 self.proc = QProcess() 57 self.proc = QProcess()
53 self.proc.finished.connect(self.__procFinished) 58 self.proc.finished.connect(self.__procFinished)
54 self.proc.readyReadStandardOutput.connect(self.__readStdout) 59 self.proc.readyReadStandardOutput.connect(self.__readStdout)
55 self.proc.readyReadStandardError.connect(self.__readStderr) 60 self.proc.readyReadStandardError.connect(self.__readStderr)
56 61
57 self.__pyExe = "" 62 self.__pyExe = ""
58 self.__sitePath = "" 63 self.__sitePath = ""
59 64
60 self.__django = django 65 self.__django = django
61 66
62 self.__mode = mode 67 self.__mode = mode
63 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode: 68 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode:
64 self.setWindowTitle(self.tr("Available Migrations")) 69 self.setWindowTitle(self.tr("Available Migrations"))
65 self.migrationsList.setHeaderLabels([ 70 self.migrationsList.setHeaderLabels(
66 self.tr("Name"), 71 [
67 ]) 72 self.tr("Name"),
73 ]
74 )
68 self.migrationsList.setSelectionMode( 75 self.migrationsList.setSelectionMode(
69 QAbstractItemView.SelectionMode.ExtendedSelection) 76 QAbstractItemView.SelectionMode.ExtendedSelection
77 )
70 else: 78 else:
71 self.setWindowTitle(self.tr("Migrations Plan")) 79 self.setWindowTitle(self.tr("Migrations Plan"))
72 self.migrationsList.setHeaderLabels([ 80 self.migrationsList.setHeaderLabels(
73 self.tr("Migration"), 81 [
74 self.tr("Dependencies"), 82 self.tr("Migration"),
75 ]) 83 self.tr("Dependencies"),
84 ]
85 )
76 self.migrationsList.setSelectionMode( 86 self.migrationsList.setSelectionMode(
77 QAbstractItemView.SelectionMode.SingleSelection) 87 QAbstractItemView.SelectionMode.SingleSelection
78 88 )
89
79 self.refreshButton = self.buttonBox.addButton( 90 self.refreshButton = self.buttonBox.addButton(
80 self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole) 91 self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole
81 self.refreshButton.setToolTip( 92 )
82 self.tr("Press to refresh the list")) 93 self.refreshButton.setToolTip(self.tr("Press to refresh the list"))
83 self.refreshButton.setEnabled(False) 94 self.refreshButton.setEnabled(False)
84 95
85 @pyqtSlot(QAbstractButton) 96 @pyqtSlot(QAbstractButton)
86 def on_buttonBox_clicked(self, button): 97 def on_buttonBox_clicked(self, button):
87 """ 98 """
88 Private slot called by a button of the button box clicked. 99 Private slot called by a button of the button box clicked.
89 100
90 @param button button that was clicked 101 @param button button that was clicked
91 @type QAbstractButton 102 @type QAbstractButton
92 """ 103 """
93 if button == self.buttonBox.button( 104 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
94 QDialogButtonBox.StandardButton.Close
95 ):
96 self.close() 105 self.close()
97 elif button == self.buttonBox.button( 106 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
98 QDialogButtonBox.StandardButton.Cancel
99 ):
100 self.__finish() 107 self.__finish()
101 elif button == self.refreshButton: 108 elif button == self.refreshButton:
102 self.on_refreshButton_clicked() 109 self.on_refreshButton_clicked()
103 110
104 def __finish(self): 111 def __finish(self):
105 """ 112 """
106 Private slot called when the process finished or the user pressed the 113 Private slot called when the process finished or the user pressed the
107 button. 114 button.
108 """ 115 """
109 if ( 116 if (
110 self.proc is not None and 117 self.proc is not None
111 self.proc.state() != QProcess.ProcessState.NotRunning 118 and self.proc.state() != QProcess.ProcessState.NotRunning
112 ): 119 ):
113 self.proc.terminate() 120 self.proc.terminate()
114 QTimer.singleShot(2000, self.proc.kill) 121 QTimer.singleShot(2000, self.proc.kill)
115 self.proc.waitForFinished(3000) 122 self.proc.waitForFinished(3000)
116 123
117 self.buttonBox.button( 124 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
118 QDialogButtonBox.StandardButton.Close).setEnabled(True) 125 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
119 self.buttonBox.button( 126 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
120 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) 127
121 self.buttonBox.button(
122 QDialogButtonBox.StandardButton.Close).setDefault(True)
123
124 self.refreshButton.setEnabled(True) 128 self.refreshButton.setEnabled(True)
125 129
126 self.__resizeColumns() 130 self.__resizeColumns()
127 131
128 def __procFinished(self, exitCode, exitStatus): 132 def __procFinished(self, exitCode, exitStatus):
129 """ 133 """
130 Private slot connected to the finished signal. 134 Private slot connected to the finished signal.
131 135
132 @param exitCode exit code of the process 136 @param exitCode exit code of the process
133 @type int 137 @type int
134 @param exitStatus exit status of the process 138 @param exitStatus exit status of the process
135 @type QProcess.ExitStatus 139 @type QProcess.ExitStatus
136 """ 140 """
137 self.__finish() 141 self.__finish()
138 142
139 def __resizeColumns(self): 143 def __resizeColumns(self):
140 """ 144 """
141 Private method to resize the list columns. 145 Private method to resize the list columns.
142 """ 146 """
143 self.migrationsList.header().resizeSections( 147 self.migrationsList.header().resizeSections(
144 QHeaderView.ResizeMode.ResizeToContents) 148 QHeaderView.ResizeMode.ResizeToContents
149 )
145 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode: 150 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode:
146 self.migrationsList.header().setStretchLastSection(True) 151 self.migrationsList.header().setStretchLastSection(True)
147 152
148 def start(self, pythonExecutable, sitePath, databaseName): 153 def start(self, pythonExecutable, sitePath, databaseName):
149 """ 154 """
150 Public slot used to start the process. 155 Public slot used to start the process.
151 156
152 @param pythonExecutable Python executable to be used 157 @param pythonExecutable Python executable to be used
153 @type str 158 @type str
154 @param sitePath path of the site 159 @param sitePath path of the site
155 @type str 160 @type str
156 @param databaseName name of the database to be used 161 @param databaseName name of the database to be used
158 @return flag indicating a successful start of the process 163 @return flag indicating a successful start of the process
159 @rtype bool 164 @rtype bool
160 """ 165 """
161 self.__pyExe = pythonExecutable 166 self.__pyExe = pythonExecutable
162 self.__sitePath = sitePath 167 self.__sitePath = sitePath
163 168
164 self.errorGroup.hide() 169 self.errorGroup.hide()
165 self.migrationsList.clear() 170 self.migrationsList.clear()
166 171
167 self.__lastTopItem = None 172 self.__lastTopItem = None
168 173
169 if sitePath: 174 if sitePath:
170 self.proc.setWorkingDirectory(sitePath) 175 self.proc.setWorkingDirectory(sitePath)
171 176
172 args = [] 177 args = []
173 args.append("manage.py") 178 args.append("manage.py")
174 args.append("showmigrations") 179 args.append("showmigrations")
175 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode: 180 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode:
176 args.append("--list") 181 args.append("--list")
178 args.append("--plan") 183 args.append("--plan")
179 args.append("--verbosity") 184 args.append("--verbosity")
180 args.append("2") 185 args.append("2")
181 if databaseName: 186 if databaseName:
182 args.append("--database={0}".format(databaseName)) 187 args.append("--database={0}".format(databaseName))
183 188
184 self.proc.start(pythonExecutable, args) 189 self.proc.start(pythonExecutable, args)
185 procStarted = self.proc.waitForStarted() 190 procStarted = self.proc.waitForStarted()
186 if not procStarted: 191 if not procStarted:
187 self.buttonBox.setFocus() 192 self.buttonBox.setFocus()
188 EricMessageBox.critical( 193 EricMessageBox.critical(
189 self, 194 self,
190 self.tr('Process Generation Error'), 195 self.tr("Process Generation Error"),
191 self.tr( 196 self.tr(
192 'The process {0} could not be started. ' 197 "The process {0} could not be started. "
193 'Ensure, that it is in the search path.' 198 "Ensure, that it is in the search path."
194 ).format(pythonExecutable)) 199 ).format(pythonExecutable),
200 )
195 return procStarted 201 return procStarted
196 202
197 def __readStdout(self): 203 def __readStdout(self):
198 """ 204 """
199 Private slot to handle the readyReadStdout signal. 205 Private slot to handle the readyReadStdout signal.
200 206
201 It reads the output of the process, formats it and inserts it into 207 It reads the output of the process, formats it and inserts it into
202 the contents pane. 208 the contents pane.
203 """ 209 """
204 while self.proc.canReadLine(): 210 while self.proc.canReadLine():
205 s = str(self.proc.readLine(), self.ioEncoding, 'replace').rstrip() 211 s = str(self.proc.readLine(), self.ioEncoding, "replace").rstrip()
206 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode: 212 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode:
207 self.__createListItem(s) 213 self.__createListItem(s)
208 else: 214 else:
209 self.__createPlanItem(s) 215 self.__createPlanItem(s)
210 216
211 def __createListItem(self, line): 217 def __createListItem(self, line):
212 """ 218 """
213 Private method to create an item for list mode. 219 Private method to create an item for list mode.
214 220
215 @param line line of text 221 @param line line of text
216 @type str 222 @type str
217 """ 223 """
218 if not line.startswith(" "): 224 if not line.startswith(" "):
219 # application name 225 # application name
220 self.__lastTopItem = QTreeWidgetItem( 226 self.__lastTopItem = QTreeWidgetItem(self.migrationsList, [line.strip()])
221 self.migrationsList, [line.strip()])
222 self.__lastTopItem.setExpanded(True) 227 self.__lastTopItem.setExpanded(True)
223 else: 228 else:
224 # migration name 229 # migration name
225 line = line.strip() 230 line = line.strip()
226 if line.startswith("["): 231 if line.startswith("["):
232 itm = QTreeWidgetItem(self.migrationsList, [name]) 237 itm = QTreeWidgetItem(self.migrationsList, [name])
233 if applied[1] == " ": 238 if applied[1] == " ":
234 itm.setCheckState(0, Qt.CheckState.Unchecked) 239 itm.setCheckState(0, Qt.CheckState.Unchecked)
235 else: 240 else:
236 itm.setCheckState(0, Qt.CheckState.Checked) 241 itm.setCheckState(0, Qt.CheckState.Checked)
237 242
238 def __createPlanItem(self, line): 243 def __createPlanItem(self, line):
239 """ 244 """
240 Private method to create an item for plan mode. 245 Private method to create an item for plan mode.
241 246
242 @param line line of text 247 @param line line of text
243 @type str 248 @type str
244 """ 249 """
245 line = line.strip() 250 line = line.strip()
246 applied = line[:3] 251 applied = line[:3]
247 parts = line[3:].strip().split(None, 2) 252 parts = line[3:].strip().split(None, 2)
248 if len(parts) == 3: 253 if len(parts) == 3:
249 dependencies = "\n".join([ 254 dependencies = "\n".join(
250 d.strip() for d in parts[2].strip()[1:-1].split(",") 255 [d.strip() for d in parts[2].strip()[1:-1].split(",")]
251 ]) 256 )
252 itm = QTreeWidgetItem(self.migrationsList, [ 257 itm = QTreeWidgetItem(
253 parts[0].strip(), 258 self.migrationsList,
254 dependencies, 259 [
255 ]) 260 parts[0].strip(),
256 else: 261 dependencies,
257 itm = QTreeWidgetItem(self.migrationsList, [ 262 ],
258 parts[0].strip(), 263 )
259 "", 264 else:
260 ]) 265 itm = QTreeWidgetItem(
266 self.migrationsList,
267 [
268 parts[0].strip(),
269 "",
270 ],
271 )
261 if applied[1] != " ": 272 if applied[1] != " ":
262 itm.setCheckState(0, Qt.CheckState.Checked) 273 itm.setCheckState(0, Qt.CheckState.Checked)
263 274
264 def __readStderr(self): 275 def __readStderr(self):
265 """ 276 """
266 Private slot to handle the readyReadStderr signal. 277 Private slot to handle the readyReadStderr signal.
267 278
268 It reads the error output of the process and inserts it into the 279 It reads the error output of the process and inserts it into the
269 error pane. 280 error pane.
270 """ 281 """
271 if self.proc is not None: 282 if self.proc is not None:
272 self.errorGroup.show() 283 self.errorGroup.show()
273 s = str(self.proc.readAllStandardError(), self.ioEncoding, 284 s = str(self.proc.readAllStandardError(), self.ioEncoding, "replace")
274 'replace')
275 self.errors.insertPlainText(s) 285 self.errors.insertPlainText(s)
276 self.errors.ensureCursorVisible() 286 self.errors.ensureCursorVisible()
277 287
278 @pyqtSlot() 288 @pyqtSlot()
279 def on_refreshButton_clicked(self): 289 def on_refreshButton_clicked(self):
280 """ 290 """
281 Private slot to refresh the log. 291 Private slot to refresh the log.
282 """ 292 """
283 self.buttonBox.button( 293 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
284 QDialogButtonBox.StandardButton.Close).setEnabled(False) 294 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
285 self.buttonBox.button( 295 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
286 QDialogButtonBox.StandardButton.Cancel).setEnabled(True) 296
287 self.buttonBox.button(
288 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
289
290 self.refreshButton.setEnabled(False) 297 self.refreshButton.setEnabled(False)
291 298
292 self.start(self.__pyExe, self.__sitePath) 299 self.start(self.__pyExe, self.__sitePath)
293 300
294 @pyqtSlot(QPoint) 301 @pyqtSlot(QPoint)
295 def on_migrationsList_customContextMenuRequested(self, pos): 302 def on_migrationsList_customContextMenuRequested(self, pos):
296 """ 303 """
297 Private slot to show the context menu. 304 Private slot to show the context menu.
298 305
299 @param pos position the context menu was requested at 306 @param pos position the context menu was requested at
300 @type QPoint 307 @type QPoint
301 """ 308 """
302 menu = QMenu(self.migrationsList) 309 menu = QMenu(self.migrationsList)
303 menu.addAction(self.tr("Apply All Migrations"), 310 menu.addAction(self.tr("Apply All Migrations"), self.__applyAllMigrations)
304 self.__applyAllMigrations) 311
305
306 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode: 312 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode:
307 selItems = self.migrationsList.selectedItems() 313 selItems = self.migrationsList.selectedItems()
308 if len(selItems) > 0: 314 if len(selItems) > 0:
309 selApps = [] 315 selApps = []
310 for itm in selItems: 316 for itm in selItems:
311 if itm.parent() is None: 317 if itm.parent() is None:
312 selApps.append(itm) 318 selApps.append(itm)
313 319
314 menu.addAction( 320 menu.addAction(
315 self.tr("Apply Selected Migrations"), 321 self.tr("Apply Selected Migrations"), self.__applyMigration
316 self.__applyMigration).setEnabled(len(selItems) == 1) 322 ).setEnabled(len(selItems) == 1)
317 menu.addAction( 323 menu.addAction(
318 self.tr("Unapply Migrations"), 324 self.tr("Unapply Migrations"), self.__unapplyMigration
319 self.__unapplyMigration).setEnabled(len(selApps) == 1) 325 ).setEnabled(len(selApps) == 1)
320 menu.addSeparator() 326 menu.addSeparator()
321 menu.addAction( 327 menu.addAction(
322 self.tr("Make Migrations"), 328 self.tr("Make Migrations"), self.__makeMigrations
323 self.__makeMigrations).setEnabled(len(selApps) > 0) 329 ).setEnabled(len(selApps) > 0)
324 act = menu.addAction( 330 act = menu.addAction(
325 self.tr("Make Empty Migrations"), 331 self.tr("Make Empty Migrations"),
326 lambda: self.__makeMigrations(empty=True)) 332 lambda: self.__makeMigrations(empty=True),
333 )
327 act.setEnabled(len(selApps) > 0) 334 act.setEnabled(len(selApps) > 0)
328 act = menu.addAction( 335 act = menu.addAction(
329 self.tr("Make Migrations (dry-run)"), 336 self.tr("Make Migrations (dry-run)"),
330 lambda: self.__makeMigrations(dryRun=True)) 337 lambda: self.__makeMigrations(dryRun=True),
338 )
331 act.setEnabled(len(selApps) > 0) 339 act.setEnabled(len(selApps) > 0)
332 else: 340 else:
333 menu.addAction(self.tr("Apply Selected Migrations"), 341 menu.addAction(self.tr("Apply Selected Migrations"), self.__applyMigration)
334 self.__applyMigration) 342
335
336 menu.popup(self.migrationsList.mapToGlobal(pos)) 343 menu.popup(self.migrationsList.mapToGlobal(pos))
337 344
338 def __applyAllMigrations(self): 345 def __applyAllMigrations(self):
339 """ 346 """
340 Private slot to apply all migrations. 347 Private slot to apply all migrations.
341 """ 348 """
342 self.__django.applyMigrations() 349 self.__django.applyMigrations()
343 self.on_refreshButton_clicked() 350 self.on_refreshButton_clicked()
344 351
345 def __applyMigration(self): 352 def __applyMigration(self):
346 """ 353 """
347 Private slot to apply the selected migrations. 354 Private slot to apply the selected migrations.
348 """ 355 """
349 itm = self.migrationsList.selectedItems()[0] 356 itm = self.migrationsList.selectedItems()[0]
355 else: 362 else:
356 migration = itm.text(0) 363 migration = itm.text(0)
357 app = itm.parent().text(0) 364 app = itm.parent().text(0)
358 else: 365 else:
359 app, migration = itm.text(0).split(".", 1) 366 app, migration = itm.text(0).split(".", 1)
360 367
361 self.__django.applyMigrations(app=app, migration=migration) 368 self.__django.applyMigrations(app=app, migration=migration)
362 369
363 self.on_refreshButton_clicked() 370 self.on_refreshButton_clicked()
364 371
365 def __unapplyMigration(self): 372 def __unapplyMigration(self):
366 """ 373 """
367 Private slot to unapply the selected migrations. 374 Private slot to unapply the selected migrations.
368 """ 375 """
369 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode: 376 if self.__mode == DjangoMigrationsListDialog.MigrationsListMode:
370 itm = self.migrationsList.selectedItems()[0] 377 itm = self.migrationsList.selectedItems()[0]
371 if itm.parent() is None: 378 if itm.parent() is None:
372 # only valid for app entries 379 # only valid for app entries
373 app = itm.text(0) 380 app = itm.text(0)
374 self.__django.applyMigrations(app=app, migration="zero") 381 self.__django.applyMigrations(app=app, migration="zero")
375 382
376 self.on_refreshButton_clicked() 383 self.on_refreshButton_clicked()
377 384
378 def __makeMigrations(self, dryRun=False, empty=False): 385 def __makeMigrations(self, dryRun=False, empty=False):
379 """ 386 """
380 Private slot to make migrations for the selected apps. 387 Private slot to make migrations for the selected apps.
381 388
382 @param dryRun flag indicating a dry-run 389 @param dryRun flag indicating a dry-run
383 @type bool 390 @type bool
384 @param empty flag indicating an empty migration 391 @param empty flag indicating an empty migration
385 @type bool 392 @type bool
386 """ 393 """
387 apps = [] 394 apps = []
388 for itm in self.migrationsList.selectedItems(): 395 for itm in self.migrationsList.selectedItems():
389 if itm.parent() is None: 396 if itm.parent() is None:
390 apps.append(itm.text(0)) 397 apps.append(itm.text(0))
391 398
392 if apps: 399 if apps:
393 migration, ok = QInputDialog.getText( 400 migration, ok = QInputDialog.getText(
394 self, 401 self,
395 self.tr("Make Migrations"), 402 self.tr("Make Migrations"),
396 self.tr("Enter a name for the migrations (leave empty to" 403 self.tr(
397 " use system supplied name):"), 404 "Enter a name for the migrations (leave empty to"
398 QLineEdit.EchoMode.Normal) 405 " use system supplied name):"
399 406 ),
407 QLineEdit.EchoMode.Normal,
408 )
409
400 if ok: 410 if ok:
401 self.__django.makeMigrations(apps, migration, dryRun, empty, 411 self.__django.makeMigrations(apps, migration, dryRun, empty, True)
402 True) 412
403
404 self.on_refreshButton_clicked() 413 self.on_refreshButton_clicked()

eric ide

mercurial