Status: | Merged |
---|---|
Merged at revision: | 2769 |
Proposed branch: | lp:~phill-ridout/openlp/pathlib6 |
Merge into: | lp:openlp |
Diff against target: |
1335 lines (+392/-213) 20 files modified
openlp/core/common/httputils.py (+0/-1) openlp/core/lib/db.py (+68/-15) openlp/core/ui/advancedtab.py (+14/-11) openlp/core/ui/exceptionform.py (+2/-12) openlp/core/ui/lib/filedialog.py (+8/-8) openlp/core/ui/mainwindow.py (+4/-10) openlp/core/ui/servicemanager.py (+5/-3) openlp/plugins/alerts/forms/alertform.py (+1/-1) openlp/plugins/alerts/lib/alertstab.py (+0/-3) openlp/plugins/custom/lib/customtab.py (+0/-3) openlp/plugins/images/imageplugin.py (+2/-2) openlp/plugins/images/lib/db.py (+3/-4) openlp/plugins/images/lib/imagetab.py (+0/-3) openlp/plugins/images/lib/mediaitem.py (+67/-65) openlp/plugins/images/lib/upgrade.py (+70/-0) openlp/plugins/songusage/forms/songusagedetaildialog.py (+0/-1) openlp/plugins/songusage/forms/songusagedetailform.py (+17/-22) tests/functional/openlp_core_ui/test_exceptionform.py (+28/-29) tests/functional/openlp_plugins/images/test_lib.py (+20/-20) tests/functional/openlp_plugins/images/test_upgrade.py (+83/-0) |
To merge this branch: | bzr merge lp:~phill-ridout/openlp/pathlib6 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tomas Groth | Approve | ||
Tim Bentley | Approve | ||
Phill | Pending | ||
Review via email: mp+331276@code.launchpad.net |
This proposal supersedes a proposal from 2017-09-24.
Commit message
Description of the change
This is ready to go now!
Upgrade the image plugin to use pathlib.
Other minor changes and fixes.
Add this to your merge proposal:
-------
lp:~phill-ridout/openlp/pathlib6 (revision 2774)
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[FAILURE] https:/
Stopping after failure
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal | # |
Phill (phill-ridout) wrote : Posted in a previous version of this proposal | # |
those __init__ methods just call the super method. They don't do anything I
fail to see any reason for keeping them!
On Sun, 24 Sep 2017, 22:01 Tim Bentley <email address hidden> wrote:
> Review: Needs Information
>
> Why have you removed a couple of __init__ methods?
> --
> https:/
> You are the owner of lp:~phill-ridout/openlp/pathlib6.
>
Phill (phill-ridout) wrote : Posted in a previous version of this proposal | # |
Just noticed one minor mistake.
Tim Bentley (trb143) : | # |
Tomas Groth (tomasgroth) wrote : | # |
Just a minor thing, see inline comment.
Tomas Groth (tomasgroth) : | # |
Preview Diff
1 | === modified file 'openlp/core/common/httputils.py' | |||
2 | --- openlp/core/common/httputils.py 2017-09-06 20:18:08 +0000 | |||
3 | +++ openlp/core/common/httputils.py 2017-09-25 17:10:35 +0000 | |||
4 | @@ -24,7 +24,6 @@ | |||
5 | 24 | """ | 24 | """ |
6 | 25 | import hashlib | 25 | import hashlib |
7 | 26 | import logging | 26 | import logging |
8 | 27 | import os | ||
9 | 28 | import platform | 27 | import platform |
10 | 29 | import socket | 28 | import socket |
11 | 30 | import sys | 29 | import sys |
12 | 31 | 30 | ||
13 | === modified file 'openlp/core/lib/db.py' | |||
14 | --- openlp/core/lib/db.py 2017-08-12 17:45:56 +0000 | |||
15 | +++ openlp/core/lib/db.py 2017-09-25 17:10:35 +0000 | |||
16 | @@ -23,12 +23,13 @@ | |||
17 | 23 | """ | 23 | """ |
18 | 24 | The :mod:`db` module provides the core database functionality for OpenLP | 24 | The :mod:`db` module provides the core database functionality for OpenLP |
19 | 25 | """ | 25 | """ |
20 | 26 | import json | ||
21 | 26 | import logging | 27 | import logging |
22 | 27 | import os | 28 | import os |
23 | 28 | from copy import copy | 29 | from copy import copy |
24 | 29 | from urllib.parse import quote_plus as urlquote | 30 | from urllib.parse import quote_plus as urlquote |
25 | 30 | 31 | ||
27 | 31 | from sqlalchemy import Table, MetaData, Column, types, create_engine | 32 | from sqlalchemy import Table, MetaData, Column, types, create_engine, UnicodeText |
28 | 32 | from sqlalchemy.engine.url import make_url | 33 | from sqlalchemy.engine.url import make_url |
29 | 33 | from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError, OperationalError, ProgrammingError | 34 | from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError, OperationalError, ProgrammingError |
30 | 34 | from sqlalchemy.orm import scoped_session, sessionmaker, mapper | 35 | from sqlalchemy.orm import scoped_session, sessionmaker, mapper |
31 | @@ -37,7 +38,8 @@ | |||
32 | 37 | from alembic.migration import MigrationContext | 38 | from alembic.migration import MigrationContext |
33 | 38 | from alembic.operations import Operations | 39 | from alembic.operations import Operations |
34 | 39 | 40 | ||
36 | 40 | from openlp.core.common import AppLocation, Settings, translate, delete_file | 41 | from openlp.core.common import AppLocation, Settings, delete_file, translate |
37 | 42 | from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder | ||
38 | 41 | from openlp.core.lib.ui import critical_error_message_box | 43 | from openlp.core.lib.ui import critical_error_message_box |
39 | 42 | 44 | ||
40 | 43 | log = logging.getLogger(__name__) | 45 | log = logging.getLogger(__name__) |
41 | @@ -133,9 +135,10 @@ | |||
42 | 133 | if db_file_name is None: | 135 | if db_file_name is None: |
43 | 134 | return 'sqlite:///{path}/{plugin}.sqlite'.format(path=AppLocation.get_section_data_path(plugin_name), | 136 | return 'sqlite:///{path}/{plugin}.sqlite'.format(path=AppLocation.get_section_data_path(plugin_name), |
44 | 135 | plugin=plugin_name) | 137 | plugin=plugin_name) |
45 | 138 | elif os.path.isabs(db_file_name): | ||
46 | 139 | return 'sqlite:///{db_file_name}'.format(db_file_name=db_file_name) | ||
47 | 136 | else: | 140 | else: |
50 | 137 | return 'sqlite:///{path}/{name}'.format(path=AppLocation.get_section_data_path(plugin_name), | 141 | return 'sqlite:///{path}/{name}'.format(path=AppLocation.get_section_data_path(plugin_name), name=db_file_name) |
49 | 138 | name=db_file_name) | ||
51 | 139 | 142 | ||
52 | 140 | 143 | ||
53 | 141 | def handle_db_error(plugin_name, db_file_name): | 144 | def handle_db_error(plugin_name, db_file_name): |
54 | @@ -200,6 +203,55 @@ | |||
55 | 200 | return instance | 203 | return instance |
56 | 201 | 204 | ||
57 | 202 | 205 | ||
58 | 206 | class PathType(types.TypeDecorator): | ||
59 | 207 | """ | ||
60 | 208 | Create a PathType for storing Path objects with SQLAlchemy. Behind the scenes we convert the Path object to a JSON | ||
61 | 209 | representation and store it as a Unicode type | ||
62 | 210 | """ | ||
63 | 211 | impl = types.UnicodeText | ||
64 | 212 | |||
65 | 213 | def coerce_compared_value(self, op, value): | ||
66 | 214 | """ | ||
67 | 215 | Some times it make sense to compare a PathType with a string. In the case a string is used coerce the the | ||
68 | 216 | PathType to a UnicodeText type. | ||
69 | 217 | |||
70 | 218 | :param op: The operation being carried out. Not used, as we only care about the type that is being used with the | ||
71 | 219 | operation. | ||
72 | 220 | :param openlp.core.common.path.Path | str value: The value being used for the comparison. Most likely a Path | ||
73 | 221 | Object or str. | ||
74 | 222 | :return: The coerced value stored in the db | ||
75 | 223 | :rtype: PathType or UnicodeText | ||
76 | 224 | """ | ||
77 | 225 | if isinstance(value, str): | ||
78 | 226 | return UnicodeText() | ||
79 | 227 | else: | ||
80 | 228 | return self | ||
81 | 229 | |||
82 | 230 | def process_bind_param(self, value, dialect): | ||
83 | 231 | """ | ||
84 | 232 | Convert the Path object to a JSON representation | ||
85 | 233 | |||
86 | 234 | :param openlp.core.common.path.Path value: The value to convert | ||
87 | 235 | :param dialect: Not used | ||
88 | 236 | :return: The Path object as a JSON string | ||
89 | 237 | :rtype: str | ||
90 | 238 | """ | ||
91 | 239 | data_path = AppLocation.get_data_path() | ||
92 | 240 | return json.dumps(value, cls=OpenLPJsonEncoder, base_path=data_path) | ||
93 | 241 | |||
94 | 242 | def process_result_value(self, value, dialect): | ||
95 | 243 | """ | ||
96 | 244 | Convert the JSON representation back | ||
97 | 245 | |||
98 | 246 | :param types.UnicodeText value: The value to convert | ||
99 | 247 | :param dialect: Not used | ||
100 | 248 | :return: The JSON object converted Python object (in this case it should be a Path object) | ||
101 | 249 | :rtype: openlp.core.common.path.Path | ||
102 | 250 | """ | ||
103 | 251 | data_path = AppLocation.get_data_path() | ||
104 | 252 | return json.loads(value, cls=OpenLPJsonDecoder, base_path=data_path) | ||
105 | 253 | |||
106 | 254 | |||
107 | 203 | def upgrade_db(url, upgrade): | 255 | def upgrade_db(url, upgrade): |
108 | 204 | """ | 256 | """ |
109 | 205 | Upgrade a database. | 257 | Upgrade a database. |
110 | @@ -208,7 +260,7 @@ | |||
111 | 208 | :param upgrade: The python module that contains the upgrade instructions. | 260 | :param upgrade: The python module that contains the upgrade instructions. |
112 | 209 | """ | 261 | """ |
113 | 210 | if not database_exists(url): | 262 | if not database_exists(url): |
115 | 211 | log.warn("Database {db} doesn't exist - skipping upgrade checks".format(db=url)) | 263 | log.warning("Database {db} doesn't exist - skipping upgrade checks".format(db=url)) |
116 | 212 | return (0, 0) | 264 | return (0, 0) |
117 | 213 | 265 | ||
118 | 214 | log.debug('Checking upgrades for DB {db}'.format(db=url)) | 266 | log.debug('Checking upgrades for DB {db}'.format(db=url)) |
119 | @@ -273,10 +325,11 @@ | |||
120 | 273 | :param plugin_name: The name of the plugin to remove the database for | 325 | :param plugin_name: The name of the plugin to remove the database for |
121 | 274 | :param db_file_name: The database file name. Defaults to None resulting in the plugin_name being used. | 326 | :param db_file_name: The database file name. Defaults to None resulting in the plugin_name being used. |
122 | 275 | """ | 327 | """ |
123 | 328 | db_file_path = AppLocation.get_section_data_path(plugin_name) | ||
124 | 276 | if db_file_name: | 329 | if db_file_name: |
126 | 277 | db_file_path = AppLocation.get_section_data_path(plugin_name) / db_file_name | 330 | db_file_path = db_file_path / db_file_name |
127 | 278 | else: | 331 | else: |
129 | 279 | db_file_path = AppLocation.get_section_data_path(plugin_name) / plugin_name | 332 | db_file_path = db_file_path / plugin_name |
130 | 280 | return delete_file(db_file_path) | 333 | return delete_file(db_file_path) |
131 | 281 | 334 | ||
132 | 282 | 335 | ||
133 | @@ -284,30 +337,30 @@ | |||
134 | 284 | """ | 337 | """ |
135 | 285 | Provide generic object persistence management | 338 | Provide generic object persistence management |
136 | 286 | """ | 339 | """ |
138 | 287 | def __init__(self, plugin_name, init_schema, db_file_name=None, upgrade_mod=None, session=None): | 340 | def __init__(self, plugin_name, init_schema, db_file_path=None, upgrade_mod=None, session=None): |
139 | 288 | """ | 341 | """ |
140 | 289 | Runs the initialisation process that includes creating the connection to the database and the tables if they do | 342 | Runs the initialisation process that includes creating the connection to the database and the tables if they do |
141 | 290 | not exist. | 343 | not exist. |
142 | 291 | 344 | ||
143 | 292 | :param plugin_name: The name to setup paths and settings section names | 345 | :param plugin_name: The name to setup paths and settings section names |
144 | 293 | :param init_schema: The init_schema function for this database | 346 | :param init_schema: The init_schema function for this database |
148 | 294 | :param db_file_name: The upgrade_schema function for this database | 347 | :param openlp.core.common.path.Path db_file_path: The file name to use for this database. Defaults to None |
149 | 295 | :param upgrade_mod: The file name to use for this database. Defaults to None resulting in the plugin_name | 348 | resulting in the plugin_name being used. |
150 | 296 | being used. | 349 | :param upgrade_mod: The upgrade_schema function for this database |
151 | 297 | """ | 350 | """ |
152 | 298 | self.is_dirty = False | 351 | self.is_dirty = False |
153 | 299 | self.session = None | 352 | self.session = None |
154 | 300 | self.db_url = None | 353 | self.db_url = None |
156 | 301 | if db_file_name: | 354 | if db_file_path: |
157 | 302 | log.debug('Manager: Creating new DB url') | 355 | log.debug('Manager: Creating new DB url') |
159 | 303 | self.db_url = init_url(plugin_name, db_file_name) | 356 | self.db_url = init_url(plugin_name, str(db_file_path)) |
160 | 304 | else: | 357 | else: |
161 | 305 | self.db_url = init_url(plugin_name) | 358 | self.db_url = init_url(plugin_name) |
162 | 306 | if upgrade_mod: | 359 | if upgrade_mod: |
163 | 307 | try: | 360 | try: |
164 | 308 | db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod) | 361 | db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod) |
165 | 309 | except (SQLAlchemyError, DBAPIError): | 362 | except (SQLAlchemyError, DBAPIError): |
167 | 310 | handle_db_error(plugin_name, db_file_name) | 363 | handle_db_error(plugin_name, str(db_file_path)) |
168 | 311 | return | 364 | return |
169 | 312 | if db_ver > up_ver: | 365 | if db_ver > up_ver: |
170 | 313 | critical_error_message_box( | 366 | critical_error_message_box( |
171 | @@ -322,7 +375,7 @@ | |||
172 | 322 | try: | 375 | try: |
173 | 323 | self.session = init_schema(self.db_url) | 376 | self.session = init_schema(self.db_url) |
174 | 324 | except (SQLAlchemyError, DBAPIError): | 377 | except (SQLAlchemyError, DBAPIError): |
176 | 325 | handle_db_error(plugin_name, db_file_name) | 378 | handle_db_error(plugin_name, str(db_file_path)) |
177 | 326 | else: | 379 | else: |
178 | 327 | self.session = session | 380 | self.session = session |
179 | 328 | 381 | ||
180 | 329 | 382 | ||
181 | === modified file 'openlp/core/ui/advancedtab.py' | |||
182 | --- openlp/core/ui/advancedtab.py 2017-08-23 20:21:11 +0000 | |||
183 | +++ openlp/core/ui/advancedtab.py 2017-09-25 17:10:35 +0000 | |||
184 | @@ -22,9 +22,8 @@ | |||
185 | 22 | """ | 22 | """ |
186 | 23 | The :mod:`advancedtab` provides an advanced settings facility. | 23 | The :mod:`advancedtab` provides an advanced settings facility. |
187 | 24 | """ | 24 | """ |
188 | 25 | import logging | ||
189 | 25 | from datetime import datetime, timedelta | 26 | from datetime import datetime, timedelta |
190 | 26 | import logging | ||
191 | 27 | import os | ||
192 | 28 | 27 | ||
193 | 29 | from PyQt5 import QtCore, QtGui, QtWidgets | 28 | from PyQt5 import QtCore, QtGui, QtWidgets |
194 | 30 | 29 | ||
195 | @@ -492,24 +491,27 @@ | |||
196 | 492 | self.service_name_edit.setText(UiStrings().DefaultServiceName) | 491 | self.service_name_edit.setText(UiStrings().DefaultServiceName) |
197 | 493 | self.service_name_edit.setFocus() | 492 | self.service_name_edit.setFocus() |
198 | 494 | 493 | ||
200 | 495 | def on_data_directory_path_edit_path_changed(self, new_data_path): | 494 | def on_data_directory_path_edit_path_changed(self, new_path): |
201 | 496 | """ | 495 | """ |
203 | 497 | Browse for a new data directory location. | 496 | Handle the `editPathChanged` signal of the data_directory_path_edit |
204 | 497 | |||
205 | 498 | :param openlp.core.common.path.Path new_path: The new path | ||
206 | 499 | :rtype: None | ||
207 | 498 | """ | 500 | """ |
208 | 499 | # Make sure they want to change the data. | 501 | # Make sure they want to change the data. |
209 | 500 | answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'), | 502 | answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'), |
210 | 501 | translate('OpenLP.AdvancedTab', 'Are you sure you want to change the ' | 503 | translate('OpenLP.AdvancedTab', 'Are you sure you want to change the ' |
211 | 502 | 'location of the OpenLP data directory to:\n\n{path}' | 504 | 'location of the OpenLP data directory to:\n\n{path}' |
212 | 503 | '\n\nThe data directory will be changed when OpenLP is ' | 505 | '\n\nThe data directory will be changed when OpenLP is ' |
214 | 504 | 'closed.').format(path=new_data_path), | 506 | 'closed.').format(path=new_path), |
215 | 505 | defaultButton=QtWidgets.QMessageBox.No) | 507 | defaultButton=QtWidgets.QMessageBox.No) |
216 | 506 | if answer != QtWidgets.QMessageBox.Yes: | 508 | if answer != QtWidgets.QMessageBox.Yes: |
217 | 507 | self.data_directory_path_edit.path = AppLocation.get_data_path() | 509 | self.data_directory_path_edit.path = AppLocation.get_data_path() |
218 | 508 | return | 510 | return |
219 | 509 | # Check if data already exists here. | 511 | # Check if data already exists here. |
221 | 510 | self.check_data_overwrite(path_to_str(new_data_path)) | 512 | self.check_data_overwrite(new_path) |
222 | 511 | # Save the new location. | 513 | # Save the new location. |
224 | 512 | self.main_window.set_new_data_path(path_to_str(new_data_path)) | 514 | self.main_window.new_data_path = new_path |
225 | 513 | self.data_directory_cancel_button.show() | 515 | self.data_directory_cancel_button.show() |
226 | 514 | 516 | ||
227 | 515 | def on_data_directory_copy_check_box_toggled(self): | 517 | def on_data_directory_copy_check_box_toggled(self): |
228 | @@ -526,9 +528,10 @@ | |||
229 | 526 | def check_data_overwrite(self, data_path): | 528 | def check_data_overwrite(self, data_path): |
230 | 527 | """ | 529 | """ |
231 | 528 | Check if there's already data in the target directory. | 530 | Check if there's already data in the target directory. |
232 | 531 | |||
233 | 532 | :param openlp.core.common.path.Path data_path: The target directory to check | ||
234 | 529 | """ | 533 | """ |
237 | 530 | test_path = os.path.join(data_path, 'songs') | 534 | if (data_path / 'songs').exists(): |
236 | 531 | if os.path.exists(test_path): | ||
238 | 532 | self.data_exists = True | 535 | self.data_exists = True |
239 | 533 | # Check is they want to replace existing data. | 536 | # Check is they want to replace existing data. |
240 | 534 | answer = QtWidgets.QMessageBox.warning(self, | 537 | answer = QtWidgets.QMessageBox.warning(self, |
241 | @@ -537,7 +540,7 @@ | |||
242 | 537 | 'WARNING: \n\nThe location you have selected \n\n{path}' | 540 | 'WARNING: \n\nThe location you have selected \n\n{path}' |
243 | 538 | '\n\nappears to contain OpenLP data files. Do you wish to ' | 541 | '\n\nappears to contain OpenLP data files. Do you wish to ' |
244 | 539 | 'replace these files with the current data ' | 542 | 'replace these files with the current data ' |
246 | 540 | 'files?').format(path=os.path.abspath(data_path,)), | 543 | 'files?'.format(path=data_path)), |
247 | 541 | QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | | 544 | QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | |
248 | 542 | QtWidgets.QMessageBox.No), | 545 | QtWidgets.QMessageBox.No), |
249 | 543 | QtWidgets.QMessageBox.No) | 546 | QtWidgets.QMessageBox.No) |
250 | @@ -559,7 +562,7 @@ | |||
251 | 559 | """ | 562 | """ |
252 | 560 | self.data_directory_path_edit.path = AppLocation.get_data_path() | 563 | self.data_directory_path_edit.path = AppLocation.get_data_path() |
253 | 561 | self.data_directory_copy_check_box.setChecked(False) | 564 | self.data_directory_copy_check_box.setChecked(False) |
255 | 562 | self.main_window.set_new_data_path(None) | 565 | self.main_window.new_data_path = None |
256 | 563 | self.main_window.set_copy_data(False) | 566 | self.main_window.set_copy_data(False) |
257 | 564 | self.data_directory_copy_check_box.hide() | 567 | self.data_directory_copy_check_box.hide() |
258 | 565 | self.data_directory_cancel_button.hide() | 568 | self.data_directory_cancel_button.hide() |
259 | 566 | 569 | ||
260 | === modified file 'openlp/core/ui/exceptionform.py' | |||
261 | --- openlp/core/ui/exceptionform.py 2017-08-26 15:06:11 +0000 | |||
262 | +++ openlp/core/ui/exceptionform.py 2017-09-25 17:10:35 +0000 | |||
263 | @@ -149,21 +149,11 @@ | |||
264 | 149 | opts = self._create_report() | 149 | opts = self._create_report() |
265 | 150 | report_text = self.report_text.format(version=opts['version'], description=opts['description'], | 150 | report_text = self.report_text.format(version=opts['version'], description=opts['description'], |
266 | 151 | traceback=opts['traceback'], libs=opts['libs'], system=opts['system']) | 151 | traceback=opts['traceback'], libs=opts['libs'], system=opts['system']) |
267 | 152 | filename = str(file_path) | ||
268 | 153 | try: | 152 | try: |
271 | 154 | report_file = open(filename, 'w') | 153 | with file_path.open('w') as report_file: |
270 | 155 | try: | ||
272 | 156 | report_file.write(report_text) | 154 | report_file.write(report_text) |
273 | 157 | except UnicodeError: | ||
274 | 158 | report_file.close() | ||
275 | 159 | report_file = open(filename, 'wb') | ||
276 | 160 | report_file.write(report_text.encode('utf-8')) | ||
277 | 161 | finally: | ||
278 | 162 | report_file.close() | ||
279 | 163 | except IOError: | 155 | except IOError: |
280 | 164 | log.exception('Failed to write crash report') | 156 | log.exception('Failed to write crash report') |
281 | 165 | finally: | ||
282 | 166 | report_file.close() | ||
283 | 167 | 157 | ||
284 | 168 | def on_send_report_button_clicked(self): | 158 | def on_send_report_button_clicked(self): |
285 | 169 | """ | 159 | """ |
286 | @@ -219,7 +209,7 @@ | |||
287 | 219 | translate('ImagePlugin.ExceptionDialog', 'Select Attachment'), | 209 | translate('ImagePlugin.ExceptionDialog', 'Select Attachment'), |
288 | 220 | Settings().value(self.settings_section + '/last directory'), | 210 | Settings().value(self.settings_section + '/last directory'), |
289 | 221 | '{text} (*)'.format(text=UiStrings().AllFiles)) | 211 | '{text} (*)'.format(text=UiStrings().AllFiles)) |
291 | 222 | log.info('New file {file}'.format(file=file_path)) | 212 | log.info('New files {file_path}'.format(file_path=file_path)) |
292 | 223 | if file_path: | 213 | if file_path: |
293 | 224 | self.file_attachment = str(file_path) | 214 | self.file_attachment = str(file_path) |
294 | 225 | 215 | ||
295 | 226 | 216 | ||
296 | === modified file 'openlp/core/ui/lib/filedialog.py' | |||
297 | --- openlp/core/ui/lib/filedialog.py 2017-09-20 20:44:57 +0000 | |||
298 | +++ openlp/core/ui/lib/filedialog.py 2017-09-25 17:10:35 +0000 | |||
299 | @@ -31,11 +31,11 @@ | |||
300 | 31 | """ | 31 | """ |
301 | 32 | Wraps `getExistingDirectory` so that it can be called with, and return Path objects | 32 | Wraps `getExistingDirectory` so that it can be called with, and return Path objects |
302 | 33 | 33 | ||
304 | 34 | :type parent: QtWidgets.QWidget or None | 34 | :type parent: QtWidgets.QWidget | None |
305 | 35 | :type caption: str | 35 | :type caption: str |
306 | 36 | :type directory: openlp.core.common.path.Path | 36 | :type directory: openlp.core.common.path.Path |
307 | 37 | :type options: QtWidgets.QFileDialog.Options | 37 | :type options: QtWidgets.QFileDialog.Options |
309 | 38 | :rtype: tuple[Path, str] | 38 | :rtype: tuple[openlp.core.common.path.Path, str] |
310 | 39 | """ | 39 | """ |
311 | 40 | args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),)) | 40 | args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),)) |
312 | 41 | 41 | ||
313 | @@ -50,13 +50,13 @@ | |||
314 | 50 | """ | 50 | """ |
315 | 51 | Wraps `getOpenFileName` so that it can be called with, and return Path objects | 51 | Wraps `getOpenFileName` so that it can be called with, and return Path objects |
316 | 52 | 52 | ||
318 | 53 | :type parent: QtWidgets.QWidget or None | 53 | :type parent: QtWidgets.QWidget | None |
319 | 54 | :type caption: str | 54 | :type caption: str |
320 | 55 | :type directory: openlp.core.common.path.Path | 55 | :type directory: openlp.core.common.path.Path |
321 | 56 | :type filter: str | 56 | :type filter: str |
322 | 57 | :type initialFilter: str | 57 | :type initialFilter: str |
323 | 58 | :type options: QtWidgets.QFileDialog.Options | 58 | :type options: QtWidgets.QFileDialog.Options |
325 | 59 | :rtype: tuple[Path, str] | 59 | :rtype: tuple[openlp.core.common.path.Path, str] |
326 | 60 | """ | 60 | """ |
327 | 61 | args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),)) | 61 | args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),)) |
328 | 62 | 62 | ||
329 | @@ -71,13 +71,13 @@ | |||
330 | 71 | """ | 71 | """ |
331 | 72 | Wraps `getOpenFileNames` so that it can be called with, and return Path objects | 72 | Wraps `getOpenFileNames` so that it can be called with, and return Path objects |
332 | 73 | 73 | ||
334 | 74 | :type parent: QtWidgets.QWidget or None | 74 | :type parent: QtWidgets.QWidget | None |
335 | 75 | :type caption: str | 75 | :type caption: str |
336 | 76 | :type directory: openlp.core.common.path.Path | 76 | :type directory: openlp.core.common.path.Path |
337 | 77 | :type filter: str | 77 | :type filter: str |
338 | 78 | :type initialFilter: str | 78 | :type initialFilter: str |
339 | 79 | :type options: QtWidgets.QFileDialog.Options | 79 | :type options: QtWidgets.QFileDialog.Options |
341 | 80 | :rtype: tuple[list[Path], str] | 80 | :rtype: tuple[list[openlp.core.common.path.Path], str] |
342 | 81 | """ | 81 | """ |
343 | 82 | args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),)) | 82 | args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),)) |
344 | 83 | 83 | ||
345 | @@ -93,13 +93,13 @@ | |||
346 | 93 | """ | 93 | """ |
347 | 94 | Wraps `getSaveFileName` so that it can be called with, and return Path objects | 94 | Wraps `getSaveFileName` so that it can be called with, and return Path objects |
348 | 95 | 95 | ||
350 | 96 | :type parent: QtWidgets.QWidget or None | 96 | :type parent: QtWidgets.QWidget | None |
351 | 97 | :type caption: str | 97 | :type caption: str |
352 | 98 | :type directory: openlp.core.common.path.Path | 98 | :type directory: openlp.core.common.path.Path |
353 | 99 | :type filter: str | 99 | :type filter: str |
354 | 100 | :type initialFilter: str | 100 | :type initialFilter: str |
355 | 101 | :type options: QtWidgets.QFileDialog.Options | 101 | :type options: QtWidgets.QFileDialog.Options |
357 | 102 | :rtype: tuple[Path or None, str] | 102 | :rtype: tuple[openlp.core.common.path.Path | None, str] |
358 | 103 | """ | 103 | """ |
359 | 104 | args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),)) | 104 | args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),)) |
360 | 105 | 105 | ||
361 | 106 | 106 | ||
362 | === modified file 'openlp/core/ui/mainwindow.py' | |||
363 | --- openlp/core/ui/mainwindow.py 2017-09-20 20:44:57 +0000 | |||
364 | +++ openlp/core/ui/mainwindow.py 2017-09-25 17:10:35 +0000 | |||
365 | @@ -1332,12 +1332,6 @@ | |||
366 | 1332 | if self.application: | 1332 | if self.application: |
367 | 1333 | self.application.process_events() | 1333 | self.application.process_events() |
368 | 1334 | 1334 | ||
369 | 1335 | def set_new_data_path(self, new_data_path): | ||
370 | 1336 | """ | ||
371 | 1337 | Set the new data path | ||
372 | 1338 | """ | ||
373 | 1339 | self.new_data_path = new_data_path | ||
374 | 1340 | |||
375 | 1341 | def set_copy_data(self, copy_data): | 1335 | def set_copy_data(self, copy_data): |
376 | 1342 | """ | 1336 | """ |
377 | 1343 | Set the flag to copy the data | 1337 | Set the flag to copy the data |
378 | @@ -1349,7 +1343,7 @@ | |||
379 | 1349 | Change the data directory. | 1343 | Change the data directory. |
380 | 1350 | """ | 1344 | """ |
381 | 1351 | log.info('Changing data path to {newpath}'.format(newpath=self.new_data_path)) | 1345 | log.info('Changing data path to {newpath}'.format(newpath=self.new_data_path)) |
383 | 1352 | old_data_path = str(AppLocation.get_data_path()) | 1346 | old_data_path = AppLocation.get_data_path() |
384 | 1353 | # Copy OpenLP data to new location if requested. | 1347 | # Copy OpenLP data to new location if requested. |
385 | 1354 | self.application.set_busy_cursor() | 1348 | self.application.set_busy_cursor() |
386 | 1355 | if self.copy_data: | 1349 | if self.copy_data: |
387 | @@ -1358,7 +1352,7 @@ | |||
388 | 1358 | self.show_status_message( | 1352 | self.show_status_message( |
389 | 1359 | translate('OpenLP.MainWindow', 'Copying OpenLP data to new data directory location - {path} ' | 1353 | translate('OpenLP.MainWindow', 'Copying OpenLP data to new data directory location - {path} ' |
390 | 1360 | '- Please wait for copy to finish').format(path=self.new_data_path)) | 1354 | '- Please wait for copy to finish').format(path=self.new_data_path)) |
392 | 1361 | dir_util.copy_tree(old_data_path, self.new_data_path) | 1355 | dir_util.copy_tree(str(old_data_path), str(self.new_data_path)) |
393 | 1362 | log.info('Copy successful') | 1356 | log.info('Copy successful') |
394 | 1363 | except (IOError, os.error, DistutilsFileError) as why: | 1357 | except (IOError, os.error, DistutilsFileError) as why: |
395 | 1364 | self.application.set_normal_cursor() | 1358 | self.application.set_normal_cursor() |
396 | @@ -1373,9 +1367,9 @@ | |||
397 | 1373 | log.info('No data copy requested') | 1367 | log.info('No data copy requested') |
398 | 1374 | # Change the location of data directory in config file. | 1368 | # Change the location of data directory in config file. |
399 | 1375 | settings = QtCore.QSettings() | 1369 | settings = QtCore.QSettings() |
401 | 1376 | settings.setValue('advanced/data path', Path(self.new_data_path)) | 1370 | settings.setValue('advanced/data path', self.new_data_path) |
402 | 1377 | # Check if the new data path is our default. | 1371 | # Check if the new data path is our default. |
404 | 1378 | if self.new_data_path == str(AppLocation.get_directory(AppLocation.DataDir)): | 1372 | if self.new_data_path == AppLocation.get_directory(AppLocation.DataDir): |
405 | 1379 | settings.remove('advanced/data path') | 1373 | settings.remove('advanced/data path') |
406 | 1380 | self.application.set_normal_cursor() | 1374 | self.application.set_normal_cursor() |
407 | 1381 | 1375 | ||
408 | 1382 | 1376 | ||
409 | === modified file 'openlp/core/ui/servicemanager.py' | |||
410 | --- openlp/core/ui/servicemanager.py 2017-09-18 06:20:06 +0000 | |||
411 | +++ openlp/core/ui/servicemanager.py 2017-09-25 17:10:35 +0000 | |||
412 | @@ -376,7 +376,7 @@ | |||
413 | 376 | self._file_name = path_to_str(file_path) | 376 | self._file_name = path_to_str(file_path) |
414 | 377 | self.main_window.set_service_modified(self.is_modified(), self.short_file_name()) | 377 | self.main_window.set_service_modified(self.is_modified(), self.short_file_name()) |
415 | 378 | Settings().setValue('servicemanager/last file', file_path) | 378 | Settings().setValue('servicemanager/last file', file_path) |
417 | 379 | if file_path and file_path.suffix() == '.oszl': | 379 | if file_path and file_path.suffix == '.oszl': |
418 | 380 | self._save_lite = True | 380 | self._save_lite = True |
419 | 381 | else: | 381 | else: |
420 | 382 | self._save_lite = False | 382 | self._save_lite = False |
421 | @@ -699,13 +699,15 @@ | |||
422 | 699 | default_file_name = format_time(default_pattern, local_time) | 699 | default_file_name = format_time(default_pattern, local_time) |
423 | 700 | else: | 700 | else: |
424 | 701 | default_file_name = '' | 701 | default_file_name = '' |
425 | 702 | default_file_path = Path(default_file_name) | ||
426 | 702 | directory_path = Settings().value(self.main_window.service_manager_settings_section + '/last directory') | 703 | directory_path = Settings().value(self.main_window.service_manager_settings_section + '/last directory') |
428 | 703 | file_path = directory_path / default_file_name | 704 | if directory_path: |
429 | 705 | default_file_path = directory_path / default_file_path | ||
430 | 704 | # SaveAs from osz to oszl is not valid as the files will be deleted on exit which is not sensible or usable in | 706 | # SaveAs from osz to oszl is not valid as the files will be deleted on exit which is not sensible or usable in |
431 | 705 | # the long term. | 707 | # the long term. |
432 | 706 | if self._file_name.endswith('oszl') or self.service_has_all_original_files: | 708 | if self._file_name.endswith('oszl') or self.service_has_all_original_files: |
433 | 707 | file_path, filter_used = FileDialog.getSaveFileName( | 709 | file_path, filter_used = FileDialog.getSaveFileName( |
435 | 708 | self.main_window, UiStrings().SaveService, file_path, | 710 | self.main_window, UiStrings().SaveService, default_file_path, |
436 | 709 | translate('OpenLP.ServiceManager', | 711 | translate('OpenLP.ServiceManager', |
437 | 710 | 'OpenLP Service Files (*.osz);; OpenLP Service Files - lite (*.oszl)')) | 712 | 'OpenLP Service Files (*.osz);; OpenLP Service Files - lite (*.oszl)')) |
438 | 711 | else: | 713 | else: |
439 | 712 | 714 | ||
440 | === modified file 'openlp/plugins/alerts/forms/alertform.py' | |||
441 | --- openlp/plugins/alerts/forms/alertform.py 2017-06-09 06:06:49 +0000 | |||
442 | +++ openlp/plugins/alerts/forms/alertform.py 2017-09-25 17:10:35 +0000 | |||
443 | @@ -70,7 +70,7 @@ | |||
444 | 70 | item_name = QtWidgets.QListWidgetItem(alert.text) | 70 | item_name = QtWidgets.QListWidgetItem(alert.text) |
445 | 71 | item_name.setData(QtCore.Qt.UserRole, alert.id) | 71 | item_name.setData(QtCore.Qt.UserRole, alert.id) |
446 | 72 | self.alert_list_widget.addItem(item_name) | 72 | self.alert_list_widget.addItem(item_name) |
448 | 73 | if alert.text == str(self.alert_text_edit.text()): | 73 | if alert.text == self.alert_text_edit.text(): |
449 | 74 | self.item_id = alert.id | 74 | self.item_id = alert.id |
450 | 75 | self.alert_list_widget.setCurrentRow(self.alert_list_widget.row(item_name)) | 75 | self.alert_list_widget.setCurrentRow(self.alert_list_widget.row(item_name)) |
451 | 76 | 76 | ||
452 | 77 | 77 | ||
453 | === modified file 'openlp/plugins/alerts/lib/alertstab.py' | |||
454 | --- openlp/plugins/alerts/lib/alertstab.py 2017-08-03 17:54:40 +0000 | |||
455 | +++ openlp/plugins/alerts/lib/alertstab.py 2017-09-25 17:10:35 +0000 | |||
456 | @@ -32,9 +32,6 @@ | |||
457 | 32 | """ | 32 | """ |
458 | 33 | AlertsTab is the alerts settings tab in the settings dialog. | 33 | AlertsTab is the alerts settings tab in the settings dialog. |
459 | 34 | """ | 34 | """ |
460 | 35 | def __init__(self, parent, name, visible_title, icon_path): | ||
461 | 36 | super(AlertsTab, self).__init__(parent, name, visible_title, icon_path) | ||
462 | 37 | |||
463 | 38 | def setupUi(self): | 35 | def setupUi(self): |
464 | 39 | self.setObjectName('AlertsTab') | 36 | self.setObjectName('AlertsTab') |
465 | 40 | super(AlertsTab, self).setupUi() | 37 | super(AlertsTab, self).setupUi() |
466 | 41 | 38 | ||
467 | === modified file 'openlp/plugins/custom/lib/customtab.py' | |||
468 | --- openlp/plugins/custom/lib/customtab.py 2016-12-31 11:01:36 +0000 | |||
469 | +++ openlp/plugins/custom/lib/customtab.py 2017-09-25 17:10:35 +0000 | |||
470 | @@ -34,9 +34,6 @@ | |||
471 | 34 | """ | 34 | """ |
472 | 35 | CustomTab is the Custom settings tab in the settings dialog. | 35 | CustomTab is the Custom settings tab in the settings dialog. |
473 | 36 | """ | 36 | """ |
474 | 37 | def __init__(self, parent, title, visible_title, icon_path): | ||
475 | 38 | super(CustomTab, self).__init__(parent, title, visible_title, icon_path) | ||
476 | 39 | |||
477 | 40 | def setupUi(self): | 37 | def setupUi(self): |
478 | 41 | self.setObjectName('CustomTab') | 38 | self.setObjectName('CustomTab') |
479 | 42 | super(CustomTab, self).setupUi() | 39 | super(CustomTab, self).setupUi() |
480 | 43 | 40 | ||
481 | === modified file 'openlp/plugins/images/imageplugin.py' | |||
482 | --- openlp/plugins/images/imageplugin.py 2017-09-09 20:00:48 +0000 | |||
483 | +++ openlp/plugins/images/imageplugin.py 2017-09-25 17:10:35 +0000 | |||
484 | @@ -29,7 +29,7 @@ | |||
485 | 29 | from openlp.core.lib import Plugin, StringContent, ImageSource, build_icon | 29 | from openlp.core.lib import Plugin, StringContent, ImageSource, build_icon |
486 | 30 | from openlp.core.lib.db import Manager | 30 | from openlp.core.lib.db import Manager |
487 | 31 | from openlp.plugins.images.endpoint import api_images_endpoint, images_endpoint | 31 | from openlp.plugins.images.endpoint import api_images_endpoint, images_endpoint |
489 | 32 | from openlp.plugins.images.lib import ImageMediaItem, ImageTab | 32 | from openlp.plugins.images.lib import ImageMediaItem, ImageTab, upgrade |
490 | 33 | from openlp.plugins.images.lib.db import init_schema | 33 | from openlp.plugins.images.lib.db import init_schema |
491 | 34 | 34 | ||
492 | 35 | log = logging.getLogger(__name__) | 35 | log = logging.getLogger(__name__) |
493 | @@ -50,7 +50,7 @@ | |||
494 | 50 | 50 | ||
495 | 51 | def __init__(self): | 51 | def __init__(self): |
496 | 52 | super(ImagePlugin, self).__init__('images', __default_settings__, ImageMediaItem, ImageTab) | 52 | super(ImagePlugin, self).__init__('images', __default_settings__, ImageMediaItem, ImageTab) |
498 | 53 | self.manager = Manager('images', init_schema) | 53 | self.manager = Manager('images', init_schema, upgrade_mod=upgrade) |
499 | 54 | self.weight = -7 | 54 | self.weight = -7 |
500 | 55 | self.icon_path = ':/plugins/plugin_images.png' | 55 | self.icon_path = ':/plugins/plugin_images.png' |
501 | 56 | self.icon = build_icon(self.icon_path) | 56 | self.icon = build_icon(self.icon_path) |
502 | 57 | 57 | ||
503 | === modified file 'openlp/plugins/images/lib/db.py' | |||
504 | --- openlp/plugins/images/lib/db.py 2016-12-31 11:01:36 +0000 | |||
505 | +++ openlp/plugins/images/lib/db.py 2017-09-25 17:10:35 +0000 | |||
506 | @@ -22,11 +22,10 @@ | |||
507 | 22 | """ | 22 | """ |
508 | 23 | The :mod:`db` module provides the database and schema that is the backend for the Images plugin. | 23 | The :mod:`db` module provides the database and schema that is the backend for the Images plugin. |
509 | 24 | """ | 24 | """ |
510 | 25 | |||
511 | 26 | from sqlalchemy import Column, ForeignKey, Table, types | 25 | from sqlalchemy import Column, ForeignKey, Table, types |
512 | 27 | from sqlalchemy.orm import mapper | 26 | from sqlalchemy.orm import mapper |
513 | 28 | 27 | ||
515 | 29 | from openlp.core.lib.db import BaseModel, init_db | 28 | from openlp.core.lib.db import BaseModel, PathType, init_db |
516 | 30 | 29 | ||
517 | 31 | 30 | ||
518 | 32 | class ImageGroups(BaseModel): | 31 | class ImageGroups(BaseModel): |
519 | @@ -65,7 +64,7 @@ | |||
520 | 65 | 64 | ||
521 | 66 | * id | 65 | * id |
522 | 67 | * group_id | 66 | * group_id |
524 | 68 | * filename | 67 | * file_path |
525 | 69 | """ | 68 | """ |
526 | 70 | session, metadata = init_db(url) | 69 | session, metadata = init_db(url) |
527 | 71 | 70 | ||
528 | @@ -80,7 +79,7 @@ | |||
529 | 80 | image_filenames_table = Table('image_filenames', metadata, | 79 | image_filenames_table = Table('image_filenames', metadata, |
530 | 81 | Column('id', types.Integer(), primary_key=True), | 80 | Column('id', types.Integer(), primary_key=True), |
531 | 82 | Column('group_id', types.Integer(), ForeignKey('image_groups.id'), default=None), | 81 | Column('group_id', types.Integer(), ForeignKey('image_groups.id'), default=None), |
533 | 83 | Column('filename', types.Unicode(255), nullable=False) | 82 | Column('file_path', PathType(), nullable=False) |
534 | 84 | ) | 83 | ) |
535 | 85 | 84 | ||
536 | 86 | mapper(ImageGroups, image_groups_table) | 85 | mapper(ImageGroups, image_groups_table) |
537 | 87 | 86 | ||
538 | === modified file 'openlp/plugins/images/lib/imagetab.py' | |||
539 | --- openlp/plugins/images/lib/imagetab.py 2016-12-31 11:01:36 +0000 | |||
540 | +++ openlp/plugins/images/lib/imagetab.py 2017-09-25 17:10:35 +0000 | |||
541 | @@ -31,9 +31,6 @@ | |||
542 | 31 | """ | 31 | """ |
543 | 32 | ImageTab is the images settings tab in the settings dialog. | 32 | ImageTab is the images settings tab in the settings dialog. |
544 | 33 | """ | 33 | """ |
545 | 34 | def __init__(self, parent, name, visible_title, icon_path): | ||
546 | 35 | super(ImageTab, self).__init__(parent, name, visible_title, icon_path) | ||
547 | 36 | |||
548 | 37 | def setupUi(self): | 34 | def setupUi(self): |
549 | 38 | self.setObjectName('ImagesTab') | 35 | self.setObjectName('ImagesTab') |
550 | 39 | super(ImageTab, self).setupUi() | 36 | super(ImageTab, self).setupUi() |
551 | 40 | 37 | ||
552 | === modified file 'openlp/plugins/images/lib/mediaitem.py' | |||
553 | --- openlp/plugins/images/lib/mediaitem.py 2017-09-17 19:43:15 +0000 | |||
554 | +++ openlp/plugins/images/lib/mediaitem.py 2017-09-25 17:10:35 +0000 | |||
555 | @@ -21,7 +21,6 @@ | |||
556 | 21 | ############################################################################### | 21 | ############################################################################### |
557 | 22 | 22 | ||
558 | 23 | import logging | 23 | import logging |
559 | 24 | import os | ||
560 | 25 | 24 | ||
561 | 26 | from PyQt5 import QtCore, QtGui, QtWidgets | 25 | from PyQt5 import QtCore, QtGui, QtWidgets |
562 | 27 | 26 | ||
563 | @@ -99,11 +98,11 @@ | |||
564 | 99 | self.list_view.setIconSize(QtCore.QSize(88, 50)) | 98 | self.list_view.setIconSize(QtCore.QSize(88, 50)) |
565 | 100 | self.list_view.setIndentation(self.list_view.default_indentation) | 99 | self.list_view.setIndentation(self.list_view.default_indentation) |
566 | 101 | self.list_view.allow_internal_dnd = True | 100 | self.list_view.allow_internal_dnd = True |
569 | 102 | self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails') | 101 | self.service_path = AppLocation.get_section_data_path(self.settings_section) / 'thumbnails' |
570 | 103 | check_directory_exists(Path(self.service_path)) | 102 | check_directory_exists(self.service_path) |
571 | 104 | # Load images from the database | 103 | # Load images from the database |
572 | 105 | self.load_full_list( | 104 | self.load_full_list( |
574 | 106 | self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), initial_load=True) | 105 | self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.file_path), initial_load=True) |
575 | 107 | 106 | ||
576 | 108 | def add_list_view_to_toolbar(self): | 107 | def add_list_view_to_toolbar(self): |
577 | 109 | """ | 108 | """ |
578 | @@ -211,8 +210,8 @@ | |||
579 | 211 | """ | 210 | """ |
580 | 212 | images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id) | 211 | images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id) |
581 | 213 | for image in images: | 212 | for image in images: |
584 | 214 | delete_file(Path(self.service_path, os.path.split(image.filename)[1])) | 213 | delete_file(self.service_path / image.file_path.name) |
585 | 215 | delete_file(Path(self.generate_thumbnail_path(image))) | 214 | delete_file(self.generate_thumbnail_path(image)) |
586 | 216 | self.manager.delete_object(ImageFilenames, image.id) | 215 | self.manager.delete_object(ImageFilenames, image.id) |
587 | 217 | image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == image_group.id) | 216 | image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == image_group.id) |
588 | 218 | for group in image_groups: | 217 | for group in image_groups: |
589 | @@ -234,8 +233,8 @@ | |||
590 | 234 | if row_item: | 233 | if row_item: |
591 | 235 | item_data = row_item.data(0, QtCore.Qt.UserRole) | 234 | item_data = row_item.data(0, QtCore.Qt.UserRole) |
592 | 236 | if isinstance(item_data, ImageFilenames): | 235 | if isinstance(item_data, ImageFilenames): |
595 | 237 | delete_file(Path(self.service_path, row_item.text(0))) | 236 | delete_file(self.service_path / row_item.text(0)) |
596 | 238 | delete_file(Path(self.generate_thumbnail_path(item_data))) | 237 | delete_file(self.generate_thumbnail_path(item_data)) |
597 | 239 | if item_data.group_id == 0: | 238 | if item_data.group_id == 0: |
598 | 240 | self.list_view.takeTopLevelItem(self.list_view.indexOfTopLevelItem(row_item)) | 239 | self.list_view.takeTopLevelItem(self.list_view.indexOfTopLevelItem(row_item)) |
599 | 241 | else: | 240 | else: |
600 | @@ -326,17 +325,19 @@ | |||
601 | 326 | """ | 325 | """ |
602 | 327 | Generate a path to the thumbnail | 326 | Generate a path to the thumbnail |
603 | 328 | 327 | ||
606 | 329 | :param image: An instance of ImageFileNames | 328 | :param openlp.plugins.images.lib.db.ImageFilenames image: The image to generate the thumbnail path for. |
607 | 330 | :return: A path to the thumbnail of type str | 329 | :return: A path to the thumbnail |
608 | 330 | :rtype: openlp.core.common.path.Path | ||
609 | 331 | """ | 331 | """ |
612 | 332 | ext = os.path.splitext(image.filename)[1].lower() | 332 | ext = image.file_path.suffix.lower() |
613 | 333 | return os.path.join(self.service_path, '{}{}'.format(str(image.id), ext)) | 333 | return self.service_path / '{name:d}{ext}'.format(name=image.id, ext=ext) |
614 | 334 | 334 | ||
615 | 335 | def load_full_list(self, images, initial_load=False, open_group=None): | 335 | def load_full_list(self, images, initial_load=False, open_group=None): |
616 | 336 | """ | 336 | """ |
617 | 337 | Replace the list of images and groups in the interface. | 337 | Replace the list of images and groups in the interface. |
618 | 338 | 338 | ||
620 | 339 | :param images: A List of Image Filenames objects that will be used to reload the mediamanager list. | 339 | :param list[openlp.plugins.images.lib.db.ImageFilenames] images: A List of Image Filenames objects that will be |
621 | 340 | used to reload the mediamanager list. | ||
622 | 340 | :param initial_load: When set to False, the busy cursor and progressbar will be shown while loading images. | 341 | :param initial_load: When set to False, the busy cursor and progressbar will be shown while loading images. |
623 | 341 | :param open_group: ImageGroups object of the group that must be expanded after reloading the list in the | 342 | :param open_group: ImageGroups object of the group that must be expanded after reloading the list in the |
624 | 342 | interface. | 343 | interface. |
625 | @@ -352,34 +353,34 @@ | |||
626 | 352 | self.expand_group(open_group.id) | 353 | self.expand_group(open_group.id) |
627 | 353 | # Sort the images by its filename considering language specific. | 354 | # Sort the images by its filename considering language specific. |
628 | 354 | # characters. | 355 | # characters. |
635 | 355 | images.sort(key=lambda image_object: get_locale_key(os.path.split(str(image_object.filename))[1])) | 356 | images.sort(key=lambda image_object: get_locale_key(image_object.file_path.name)) |
636 | 356 | for image_file in images: | 357 | for image in images: |
637 | 357 | log.debug('Loading image: {name}'.format(name=image_file.filename)) | 358 | log.debug('Loading image: {name}'.format(name=image.file_path)) |
638 | 358 | filename = os.path.split(image_file.filename)[1] | 359 | file_name = image.file_path.name |
639 | 359 | thumb = self.generate_thumbnail_path(image_file) | 360 | thumbnail_path = self.generate_thumbnail_path(image) |
640 | 360 | if not os.path.exists(image_file.filename): | 361 | if not image.file_path.exists(): |
641 | 361 | icon = build_icon(':/general/general_delete.png') | 362 | icon = build_icon(':/general/general_delete.png') |
642 | 362 | else: | 363 | else: |
645 | 363 | if validate_thumb(Path(image_file.filename), Path(thumb)): | 364 | if validate_thumb(image.file_path, thumbnail_path): |
646 | 364 | icon = build_icon(thumb) | 365 | icon = build_icon(thumbnail_path) |
647 | 365 | else: | 366 | else: |
651 | 366 | icon = create_thumb(image_file.filename, thumb) | 367 | icon = create_thumb(image.file_path, thumbnail_path) |
652 | 367 | item_name = QtWidgets.QTreeWidgetItem([filename]) | 368 | item_name = QtWidgets.QTreeWidgetItem([file_name]) |
653 | 368 | item_name.setText(0, filename) | 369 | item_name.setText(0, file_name) |
654 | 369 | item_name.setIcon(0, icon) | 370 | item_name.setIcon(0, icon) |
658 | 370 | item_name.setToolTip(0, image_file.filename) | 371 | item_name.setToolTip(0, str(image.file_path)) |
659 | 371 | item_name.setData(0, QtCore.Qt.UserRole, image_file) | 372 | item_name.setData(0, QtCore.Qt.UserRole, image) |
660 | 372 | if image_file.group_id == 0: | 373 | if image.group_id == 0: |
661 | 373 | self.list_view.addTopLevelItem(item_name) | 374 | self.list_view.addTopLevelItem(item_name) |
662 | 374 | else: | 375 | else: |
664 | 375 | group_items[image_file.group_id].addChild(item_name) | 376 | group_items[image.group_id].addChild(item_name) |
665 | 376 | if not initial_load: | 377 | if not initial_load: |
666 | 377 | self.main_window.increment_progress_bar() | 378 | self.main_window.increment_progress_bar() |
667 | 378 | if not initial_load: | 379 | if not initial_load: |
668 | 379 | self.main_window.finished_progress_bar() | 380 | self.main_window.finished_progress_bar() |
669 | 380 | self.application.set_normal_cursor() | 381 | self.application.set_normal_cursor() |
670 | 381 | 382 | ||
672 | 382 | def validate_and_load(self, files, target_group=None): | 383 | def validate_and_load(self, file_paths, target_group=None): |
673 | 383 | """ | 384 | """ |
674 | 384 | Process a list for files either from the File Dialog or from Drag and Drop. | 385 | Process a list for files either from the File Dialog or from Drag and Drop. |
675 | 385 | This method is overloaded from MediaManagerItem. | 386 | This method is overloaded from MediaManagerItem. |
676 | @@ -388,15 +389,15 @@ | |||
677 | 388 | :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files | 389 | :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files |
678 | 389 | """ | 390 | """ |
679 | 390 | self.application.set_normal_cursor() | 391 | self.application.set_normal_cursor() |
683 | 391 | self.load_list(files, target_group) | 392 | self.load_list(file_paths, target_group) |
684 | 392 | last_dir = os.path.split(files[0])[0] | 393 | last_dir = file_paths[0].parent |
685 | 393 | Settings().setValue(self.settings_section + '/last directory', Path(last_dir)) | 394 | Settings().setValue(self.settings_section + '/last directory', last_dir) |
686 | 394 | 395 | ||
688 | 395 | def load_list(self, images, target_group=None, initial_load=False): | 396 | def load_list(self, image_paths, target_group=None, initial_load=False): |
689 | 396 | """ | 397 | """ |
690 | 397 | Add new images to the database. This method is called when adding images using the Add button or DnD. | 398 | Add new images to the database. This method is called when adding images using the Add button or DnD. |
691 | 398 | 399 | ||
693 | 399 | :param images: A List of strings containing the filenames of the files to be loaded | 400 | :param list[openlp.core.common.Path] image_paths: A list of file paths to the images to be loaded |
694 | 400 | :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files | 401 | :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files |
695 | 401 | :param initial_load: When set to False, the busy cursor and progressbar will be shown while loading images | 402 | :param initial_load: When set to False, the busy cursor and progressbar will be shown while loading images |
696 | 402 | """ | 403 | """ |
697 | @@ -429,7 +430,7 @@ | |||
698 | 429 | else: | 430 | else: |
699 | 430 | self.choose_group_form.existing_radio_button.setDisabled(False) | 431 | self.choose_group_form.existing_radio_button.setDisabled(False) |
700 | 431 | self.choose_group_form.group_combobox.setDisabled(False) | 432 | self.choose_group_form.group_combobox.setDisabled(False) |
702 | 432 | # Ask which group the images should be saved in | 433 | # Ask which group the image_paths should be saved in |
703 | 433 | if self.choose_group_form.exec(selected_group=preselect_group): | 434 | if self.choose_group_form.exec(selected_group=preselect_group): |
704 | 434 | if self.choose_group_form.nogroup_radio_button.isChecked(): | 435 | if self.choose_group_form.nogroup_radio_button.isChecked(): |
705 | 435 | # User chose 'No group' | 436 | # User chose 'No group' |
706 | @@ -461,33 +462,33 @@ | |||
707 | 461 | return | 462 | return |
708 | 462 | # Initialize busy cursor and progress bar | 463 | # Initialize busy cursor and progress bar |
709 | 463 | self.application.set_busy_cursor() | 464 | self.application.set_busy_cursor() |
714 | 464 | self.main_window.display_progress_bar(len(images)) | 465 | self.main_window.display_progress_bar(len(image_paths)) |
715 | 465 | # Save the new images in the database | 466 | # Save the new image_paths in the database |
716 | 466 | self.save_new_images_list(images, group_id=parent_group.id, reload_list=False) | 467 | self.save_new_images_list(image_paths, group_id=parent_group.id, reload_list=False) |
717 | 467 | self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), | 468 | self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.file_path), |
718 | 468 | initial_load=initial_load, open_group=parent_group) | 469 | initial_load=initial_load, open_group=parent_group) |
719 | 469 | self.application.set_normal_cursor() | 470 | self.application.set_normal_cursor() |
720 | 470 | 471 | ||
722 | 471 | def save_new_images_list(self, images_list, group_id=0, reload_list=True): | 472 | def save_new_images_list(self, image_paths, group_id=0, reload_list=True): |
723 | 472 | """ | 473 | """ |
724 | 473 | Convert a list of image filenames to ImageFilenames objects and save them in the database. | 474 | Convert a list of image filenames to ImageFilenames objects and save them in the database. |
725 | 474 | 475 | ||
727 | 475 | :param images_list: A List of strings containing image filenames | 476 | :param list[Path] image_paths: A List of file paths to image |
728 | 476 | :param group_id: The ID of the group to save the images in | 477 | :param group_id: The ID of the group to save the images in |
729 | 477 | :param reload_list: This boolean is set to True when the list in the interface should be reloaded after saving | 478 | :param reload_list: This boolean is set to True when the list in the interface should be reloaded after saving |
730 | 478 | the new images | 479 | the new images |
731 | 479 | """ | 480 | """ |
734 | 480 | for filename in images_list: | 481 | for image_path in image_paths: |
735 | 481 | if not isinstance(filename, str): | 482 | if not isinstance(image_path, Path): |
736 | 482 | continue | 483 | continue |
738 | 483 | log.debug('Adding new image: {name}'.format(name=filename)) | 484 | log.debug('Adding new image: {name}'.format(name=image_path)) |
739 | 484 | image_file = ImageFilenames() | 485 | image_file = ImageFilenames() |
740 | 485 | image_file.group_id = group_id | 486 | image_file.group_id = group_id |
742 | 486 | image_file.filename = str(filename) | 487 | image_file.file_path = image_path |
743 | 487 | self.manager.save_object(image_file) | 488 | self.manager.save_object(image_file) |
744 | 488 | self.main_window.increment_progress_bar() | 489 | self.main_window.increment_progress_bar() |
747 | 489 | if reload_list and images_list: | 490 | if reload_list and image_paths: |
748 | 490 | self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename)) | 491 | self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.file_path)) |
749 | 491 | 492 | ||
750 | 492 | def dnd_move_internal(self, target): | 493 | def dnd_move_internal(self, target): |
751 | 493 | """ | 494 | """ |
752 | @@ -581,8 +582,8 @@ | |||
753 | 581 | return False | 582 | return False |
754 | 582 | # Find missing files | 583 | # Find missing files |
755 | 583 | for image in images: | 584 | for image in images: |
758 | 584 | if not os.path.exists(image.filename): | 585 | if not image.file_path.exists(): |
759 | 585 | missing_items_file_names.append(image.filename) | 586 | missing_items_file_names.append(str(image.file_path)) |
760 | 586 | # We cannot continue, as all images do not exist. | 587 | # We cannot continue, as all images do not exist. |
761 | 587 | if not images: | 588 | if not images: |
762 | 588 | if not remote: | 589 | if not remote: |
763 | @@ -601,9 +602,9 @@ | |||
764 | 601 | return False | 602 | return False |
765 | 602 | # Continue with the existing images. | 603 | # Continue with the existing images. |
766 | 603 | for image in images: | 604 | for image in images: |
770 | 604 | name = os.path.split(image.filename)[1] | 605 | name = image.file_path.name |
771 | 605 | thumbnail = self.generate_thumbnail_path(image) | 606 | thumbnail_path = self.generate_thumbnail_path(image) |
772 | 606 | service_item.add_from_image(image.filename, name, background, thumbnail) | 607 | service_item.add_from_image(str(image.file_path), name, background, str(thumbnail_path)) |
773 | 607 | return True | 608 | return True |
774 | 608 | 609 | ||
775 | 609 | def check_group_exists(self, new_group): | 610 | def check_group_exists(self, new_group): |
776 | @@ -640,7 +641,7 @@ | |||
777 | 640 | if not self.check_group_exists(new_group): | 641 | if not self.check_group_exists(new_group): |
778 | 641 | if self.manager.save_object(new_group): | 642 | if self.manager.save_object(new_group): |
779 | 642 | self.load_full_list(self.manager.get_all_objects( | 643 | self.load_full_list(self.manager.get_all_objects( |
781 | 643 | ImageFilenames, order_by_ref=ImageFilenames.filename)) | 644 | ImageFilenames, order_by_ref=ImageFilenames.file_path)) |
782 | 644 | self.expand_group(new_group.id) | 645 | self.expand_group(new_group.id) |
783 | 645 | self.fill_groups_combobox(self.choose_group_form.group_combobox) | 646 | self.fill_groups_combobox(self.choose_group_form.group_combobox) |
784 | 646 | self.fill_groups_combobox(self.add_group_form.parent_group_combobox) | 647 | self.fill_groups_combobox(self.add_group_form.parent_group_combobox) |
785 | @@ -675,9 +676,9 @@ | |||
786 | 675 | if not isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames): | 676 | if not isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames): |
787 | 676 | # Only continue when an image is selected. | 677 | # Only continue when an image is selected. |
788 | 677 | return | 678 | return |
792 | 678 | filename = bitem.data(0, QtCore.Qt.UserRole).filename | 679 | file_path = bitem.data(0, QtCore.Qt.UserRole).file_path |
793 | 679 | if os.path.exists(filename): | 680 | if file_path.exists(): |
794 | 680 | if self.live_controller.display.direct_image(filename, background): | 681 | if self.live_controller.display.direct_image(str(file_path), background): |
795 | 681 | self.reset_action.setVisible(True) | 682 | self.reset_action.setVisible(True) |
796 | 682 | else: | 683 | else: |
797 | 683 | critical_error_message_box( | 684 | critical_error_message_box( |
798 | @@ -687,22 +688,22 @@ | |||
799 | 687 | critical_error_message_box( | 688 | critical_error_message_box( |
800 | 688 | UiStrings().LiveBGError, | 689 | UiStrings().LiveBGError, |
801 | 689 | translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, ' | 690 | translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, ' |
803 | 690 | 'the image file "{name}" no longer exists.').format(name=filename)) | 691 | 'the image file "{name}" no longer exists.').format(name=file_path)) |
804 | 691 | 692 | ||
805 | 692 | def search(self, string, show_error=True): | 693 | def search(self, string, show_error=True): |
806 | 693 | """ | 694 | """ |
807 | 694 | Perform a search on the image file names. | 695 | Perform a search on the image file names. |
808 | 695 | 696 | ||
811 | 696 | :param string: The glob to search for | 697 | :param str string: The glob to search for |
812 | 697 | :param show_error: Unused. | 698 | :param bool show_error: Unused. |
813 | 698 | """ | 699 | """ |
814 | 699 | files = self.manager.get_all_objects( | 700 | files = self.manager.get_all_objects( |
817 | 700 | ImageFilenames, filter_clause=ImageFilenames.filename.contains(string), | 701 | ImageFilenames, filter_clause=ImageFilenames.file_path.contains(string), |
818 | 701 | order_by_ref=ImageFilenames.filename) | 702 | order_by_ref=ImageFilenames.file_path) |
819 | 702 | results = [] | 703 | results = [] |
820 | 703 | for file_object in files: | 704 | for file_object in files: |
823 | 704 | filename = os.path.split(str(file_object.filename))[1] | 705 | file_name = file_object.file_path.name |
824 | 705 | results.append([file_object.filename, filename]) | 706 | results.append([str(file_object.file_path), file_name]) |
825 | 706 | return results | 707 | return results |
826 | 707 | 708 | ||
827 | 708 | def create_item_from_id(self, item_id): | 709 | def create_item_from_id(self, item_id): |
828 | @@ -711,8 +712,9 @@ | |||
829 | 711 | 712 | ||
830 | 712 | :param item_id: Id to make live | 713 | :param item_id: Id to make live |
831 | 713 | """ | 714 | """ |
832 | 715 | item_id = Path(item_id) | ||
833 | 714 | item = QtWidgets.QTreeWidgetItem() | 716 | item = QtWidgets.QTreeWidgetItem() |
836 | 715 | item_data = self.manager.get_object_filtered(ImageFilenames, ImageFilenames.filename == item_id) | 717 | item_data = self.manager.get_object_filtered(ImageFilenames, ImageFilenames.file_path == item_id) |
837 | 716 | item.setText(0, os.path.basename(item_data.filename)) | 718 | item.setText(0, item_data.file_path.name) |
838 | 717 | item.setData(0, QtCore.Qt.UserRole, item_data) | 719 | item.setData(0, QtCore.Qt.UserRole, item_data) |
839 | 718 | return item | 720 | return item |
840 | 719 | 721 | ||
841 | === added file 'openlp/plugins/images/lib/upgrade.py' | |||
842 | --- openlp/plugins/images/lib/upgrade.py 1970-01-01 00:00:00 +0000 | |||
843 | +++ openlp/plugins/images/lib/upgrade.py 2017-09-25 17:10:35 +0000 | |||
844 | @@ -0,0 +1,70 @@ | |||
845 | 1 | # -*- coding: utf-8 -*- | ||
846 | 2 | # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 | ||
847 | 3 | |||
848 | 4 | ############################################################################### | ||
849 | 5 | # OpenLP - Open Source Lyrics Projection # | ||
850 | 6 | # --------------------------------------------------------------------------- # | ||
851 | 7 | # Copyright (c) 2008-2017 OpenLP Developers # | ||
852 | 8 | # --------------------------------------------------------------------------- # | ||
853 | 9 | # This program is free software; you can redistribute it and/or modify it # | ||
854 | 10 | # under the terms of the GNU General Public License as published by the Free # | ||
855 | 11 | # Software Foundation; version 2 of the License. # | ||
856 | 12 | # # | ||
857 | 13 | # This program is distributed in the hope that it will be useful, but WITHOUT # | ||
858 | 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # | ||
859 | 15 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # | ||
860 | 16 | # more details. # | ||
861 | 17 | # # | ||
862 | 18 | # You should have received a copy of the GNU General Public License along # | ||
863 | 19 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # | ||
864 | 20 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # | ||
865 | 21 | ############################################################################### | ||
866 | 22 | """ | ||
867 | 23 | The :mod:`upgrade` module provides the migration path for the OLP Paths database | ||
868 | 24 | """ | ||
869 | 25 | import json | ||
870 | 26 | import logging | ||
871 | 27 | |||
872 | 28 | from sqlalchemy import Column, Table | ||
873 | 29 | |||
874 | 30 | from openlp.core.common import AppLocation | ||
875 | 31 | from openlp.core.common.db import drop_columns | ||
876 | 32 | from openlp.core.common.json import OpenLPJsonEncoder | ||
877 | 33 | from openlp.core.common.path import Path | ||
878 | 34 | from openlp.core.lib.db import PathType, get_upgrade_op | ||
879 | 35 | |||
880 | 36 | log = logging.getLogger(__name__) | ||
881 | 37 | __version__ = 2 | ||
882 | 38 | |||
883 | 39 | |||
884 | 40 | def upgrade_1(session, metadata): | ||
885 | 41 | """ | ||
886 | 42 | Version 1 upgrade - old db might/might not be versioned. | ||
887 | 43 | """ | ||
888 | 44 | log.debug('Skipping upgrade_1 of files DB - not used') | ||
889 | 45 | |||
890 | 46 | |||
891 | 47 | def upgrade_2(session, metadata): | ||
892 | 48 | """ | ||
893 | 49 | Version 2 upgrade - Move file path from old db to JSON encoded path to new db. Added during 2.5 dev | ||
894 | 50 | """ | ||
895 | 51 | # TODO: Update tests | ||
896 | 52 | log.debug('Starting upgrade_2 for file_path to JSON') | ||
897 | 53 | old_table = Table('image_filenames', metadata, autoload=True) | ||
898 | 54 | if 'file_path' not in [col.name for col in old_table.c.values()]: | ||
899 | 55 | op = get_upgrade_op(session) | ||
900 | 56 | op.add_column('image_filenames', Column('file_path', PathType())) | ||
901 | 57 | conn = op.get_bind() | ||
902 | 58 | results = conn.execute('SELECT * FROM image_filenames') | ||
903 | 59 | data_path = AppLocation.get_data_path() | ||
904 | 60 | for row in results.fetchall(): | ||
905 | 61 | file_path_json = json.dumps(Path(row.filename), cls=OpenLPJsonEncoder, base_path=data_path) | ||
906 | 62 | sql = 'UPDATE image_filenames SET file_path = \'{file_path_json}\' WHERE id = {id}'.format( | ||
907 | 63 | file_path_json=file_path_json, id=row.id) | ||
908 | 64 | conn.execute(sql) | ||
909 | 65 | # Drop old columns | ||
910 | 66 | if metadata.bind.url.get_dialect().name == 'sqlite': | ||
911 | 67 | drop_columns(op, 'image_filenames', ['filename', ]) | ||
912 | 68 | else: | ||
913 | 69 | op.drop_constraint('image_filenames', 'foreignkey') | ||
914 | 70 | op.drop_column('image_filenames', 'filenames') | ||
915 | 0 | 71 | ||
916 | === modified file 'openlp/plugins/songusage/forms/songusagedetaildialog.py' | |||
917 | --- openlp/plugins/songusage/forms/songusagedetaildialog.py 2017-06-09 06:06:49 +0000 | |||
918 | +++ openlp/plugins/songusage/forms/songusagedetaildialog.py 2017-09-25 17:10:35 +0000 | |||
919 | @@ -19,7 +19,6 @@ | |||
920 | 19 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # | 19 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # |
921 | 20 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # | 20 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
922 | 21 | ############################################################################### | 21 | ############################################################################### |
923 | 22 | |||
924 | 23 | from PyQt5 import QtCore, QtWidgets | 22 | from PyQt5 import QtCore, QtWidgets |
925 | 24 | 23 | ||
926 | 25 | from openlp.core.common import translate | 24 | from openlp.core.common import translate |
927 | 26 | 25 | ||
928 | === modified file 'openlp/plugins/songusage/forms/songusagedetailform.py' | |||
929 | --- openlp/plugins/songusage/forms/songusagedetailform.py 2017-08-26 15:06:11 +0000 | |||
930 | +++ openlp/plugins/songusage/forms/songusagedetailform.py 2017-09-25 17:10:35 +0000 | |||
931 | @@ -19,7 +19,6 @@ | |||
932 | 19 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # | 19 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # |
933 | 20 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # | 20 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
934 | 21 | ############################################################################### | 21 | ############################################################################### |
935 | 22 | |||
936 | 23 | import logging | 22 | import logging |
937 | 24 | import os | 23 | import os |
938 | 25 | 24 | ||
939 | @@ -60,7 +59,7 @@ | |||
940 | 60 | 59 | ||
941 | 61 | def on_report_path_edit_path_changed(self, file_path): | 60 | def on_report_path_edit_path_changed(self, file_path): |
942 | 62 | """ | 61 | """ |
944 | 63 | Called when the path in the `PathEdit` has changed | 62 | Handle the `pathEditChanged` signal from report_path_edit |
945 | 64 | 63 | ||
946 | 65 | :param openlp.core.common.path.Path file_path: The new path. | 64 | :param openlp.core.common.path.Path file_path: The new path. |
947 | 66 | :rtype: None | 65 | :rtype: None |
948 | @@ -72,7 +71,7 @@ | |||
949 | 72 | Ok was triggered so lets save the data and run the report | 71 | Ok was triggered so lets save the data and run the report |
950 | 73 | """ | 72 | """ |
951 | 74 | log.debug('accept') | 73 | log.debug('accept') |
953 | 75 | path = path_to_str(self.report_path_edit.path) | 74 | path = self.report_path_edit.path |
954 | 76 | if not path: | 75 | if not path: |
955 | 77 | self.main_window.error_message( | 76 | self.main_window.error_message( |
956 | 78 | translate('SongUsagePlugin.SongUsageDetailForm', 'Output Path Not Selected'), | 77 | translate('SongUsagePlugin.SongUsageDetailForm', 'Output Path Not Selected'), |
957 | @@ -80,7 +79,7 @@ | |||
958 | 80 | ' song usage report. \nPlease select an existing path on your computer.') | 79 | ' song usage report. \nPlease select an existing path on your computer.') |
959 | 81 | ) | 80 | ) |
960 | 82 | return | 81 | return |
962 | 83 | check_directory_exists(Path(path)) | 82 | check_directory_exists(path) |
963 | 84 | file_name = translate('SongUsagePlugin.SongUsageDetailForm', | 83 | file_name = translate('SongUsagePlugin.SongUsageDetailForm', |
964 | 85 | 'usage_detail_{old}_{new}.txt' | 84 | 'usage_detail_{old}_{new}.txt' |
965 | 86 | ).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'), | 85 | ).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'), |
966 | @@ -91,29 +90,25 @@ | |||
967 | 91 | SongUsageItem, and_(SongUsageItem.usagedate >= self.from_date_calendar.selectedDate().toPyDate(), | 90 | SongUsageItem, and_(SongUsageItem.usagedate >= self.from_date_calendar.selectedDate().toPyDate(), |
968 | 92 | SongUsageItem.usagedate < self.to_date_calendar.selectedDate().toPyDate()), | 91 | SongUsageItem.usagedate < self.to_date_calendar.selectedDate().toPyDate()), |
969 | 93 | [SongUsageItem.usagedate, SongUsageItem.usagetime]) | 92 | [SongUsageItem.usagedate, SongUsageItem.usagetime]) |
972 | 94 | report_file_name = os.path.join(path, file_name) | 93 | report_file_name = path / file_name |
971 | 95 | file_handle = None | ||
973 | 96 | try: | 94 | try: |
987 | 97 | file_handle = open(report_file_name, 'wb') | 95 | with report_file_name.open('wb') as file_handle: |
988 | 98 | for instance in usage: | 96 | for instance in usage: |
989 | 99 | record = ('\"{date}\",\"{time}\",\"{title}\",\"{copyright}\",\"{ccli}\",\"{authors}\",' | 97 | record = ('\"{date}\",\"{time}\",\"{title}\",\"{copyright}\",\"{ccli}\",\"{authors}\",' |
990 | 100 | '\"{name}\",\"{source}\"\n').format(date=instance.usagedate, time=instance.usagetime, | 98 | '\"{name}\",\"{source}\"\n').format(date=instance.usagedate, time=instance.usagetime, |
991 | 101 | title=instance.title, copyright=instance.copyright, | 99 | title=instance.title, copyright=instance.copyright, |
992 | 102 | ccli=instance.ccl_number, authors=instance.authors, | 100 | ccli=instance.ccl_number, authors=instance.authors, |
993 | 103 | name=instance.plugin_name, source=instance.source) | 101 | name=instance.plugin_name, source=instance.source) |
994 | 104 | file_handle.write(record.encode('utf-8')) | 102 | file_handle.write(record.encode('utf-8')) |
995 | 105 | self.main_window.information_message( | 103 | self.main_window.information_message( |
996 | 106 | translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation'), | 104 | translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation'), |
997 | 107 | translate('SongUsagePlugin.SongUsageDetailForm', | 105 | translate('SongUsagePlugin.SongUsageDetailForm', |
998 | 108 | 'Report \n{name} \nhas been successfully created. ').format(name=report_file_name) | 106 | 'Report \n{name} \nhas been successfully created. ').format(name=report_file_name) |
999 | 109 | ) | 107 | ) |
1000 | 110 | except OSError as ose: | 108 | except OSError as ose: |
1001 | 111 | log.exception('Failed to write out song usage records') | 109 | log.exception('Failed to write out song usage records') |
1002 | 112 | critical_error_message_box(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation Failed'), | 110 | critical_error_message_box(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation Failed'), |
1003 | 113 | translate('SongUsagePlugin.SongUsageDetailForm', | 111 | translate('SongUsagePlugin.SongUsageDetailForm', |
1004 | 114 | 'An error occurred while creating the report: {error}' | 112 | 'An error occurred while creating the report: {error}' |
1005 | 115 | ).format(error=ose.strerror)) | 113 | ).format(error=ose.strerror)) |
1006 | 116 | finally: | ||
1007 | 117 | if file_handle: | ||
1008 | 118 | file_handle.close() | ||
1009 | 119 | self.close() | 114 | self.close() |
1010 | 120 | 115 | ||
1011 | === modified file 'tests/functional/openlp_core_ui/test_exceptionform.py' | |||
1012 | --- tests/functional/openlp_core_ui/test_exceptionform.py 2017-09-07 21:52:39 +0000 | |||
1013 | +++ tests/functional/openlp_core_ui/test_exceptionform.py 2017-09-25 17:10:35 +0000 | |||
1014 | @@ -22,11 +22,11 @@ | |||
1015 | 22 | """ | 22 | """ |
1016 | 23 | Package to test the openlp.core.ui.exeptionform package. | 23 | Package to test the openlp.core.ui.exeptionform package. |
1017 | 24 | """ | 24 | """ |
1018 | 25 | |||
1019 | 26 | import os | 25 | import os |
1020 | 27 | import tempfile | 26 | import tempfile |
1021 | 27 | |||
1022 | 28 | from unittest import TestCase | 28 | from unittest import TestCase |
1024 | 29 | from unittest.mock import mock_open, patch | 29 | from unittest.mock import call, patch |
1025 | 30 | 30 | ||
1026 | 31 | from openlp.core.common import Registry | 31 | from openlp.core.common import Registry |
1027 | 32 | from openlp.core.common.path import Path | 32 | from openlp.core.common.path import Path |
1028 | @@ -142,15 +142,15 @@ | |||
1029 | 142 | test_form = exceptionform.ExceptionForm() | 142 | test_form = exceptionform.ExceptionForm() |
1030 | 143 | test_form.file_attachment = None | 143 | test_form.file_attachment = None |
1031 | 144 | 144 | ||
1038 | 145 | with patch.object(test_form, '_pyuno_import') as mock_pyuno: | 145 | with patch.object(test_form, '_pyuno_import') as mock_pyuno, \ |
1039 | 146 | with patch.object(test_form.exception_text_edit, 'toPlainText') as mock_traceback: | 146 | patch.object(test_form.exception_text_edit, 'toPlainText') as mock_traceback, \ |
1040 | 147 | with patch.object(test_form.description_text_edit, 'toPlainText') as mock_description: | 147 | patch.object(test_form.description_text_edit, 'toPlainText') as mock_description: |
1041 | 148 | mock_pyuno.return_value = 'UNO Bridge Test' | 148 | mock_pyuno.return_value = 'UNO Bridge Test' |
1042 | 149 | mock_traceback.return_value = 'openlp: Traceback Test' | 149 | mock_traceback.return_value = 'openlp: Traceback Test' |
1043 | 150 | mock_description.return_value = 'Description Test' | 150 | mock_description.return_value = 'Description Test' |
1044 | 151 | 151 | ||
1047 | 152 | # WHEN: on_save_report_button_clicked called | 152 | # WHEN: on_save_report_button_clicked called |
1048 | 153 | test_form.on_send_report_button_clicked() | 153 | test_form.on_send_report_button_clicked() |
1049 | 154 | 154 | ||
1050 | 155 | # THEN: Verify strings were formatted properly | 155 | # THEN: Verify strings were formatted properly |
1051 | 156 | mocked_add_query_item.assert_called_with('body', MAIL_ITEM_TEXT) | 156 | mocked_add_query_item.assert_called_with('body', MAIL_ITEM_TEXT) |
1052 | @@ -182,25 +182,24 @@ | |||
1053 | 182 | mocked_qt.PYQT_VERSION_STR = 'PyQt5 Test' | 182 | mocked_qt.PYQT_VERSION_STR = 'PyQt5 Test' |
1054 | 183 | mocked_is_linux.return_value = False | 183 | mocked_is_linux.return_value = False |
1055 | 184 | mocked_application_version.return_value = 'Trunk Test' | 184 | mocked_application_version.return_value = 'Trunk Test' |
1071 | 185 | mocked_save_filename.return_value = (Path('testfile.txt'), 'filter') | 185 | |
1072 | 186 | 186 | with patch.object(Path, 'open') as mocked_path_open: | |
1073 | 187 | test_form = exceptionform.ExceptionForm() | 187 | test_path = Path('testfile.txt') |
1074 | 188 | test_form.file_attachment = None | 188 | mocked_save_filename.return_value = test_path, 'ext' |
1075 | 189 | 189 | ||
1076 | 190 | with patch.object(test_form, '_pyuno_import') as mock_pyuno: | 190 | test_form = exceptionform.ExceptionForm() |
1077 | 191 | with patch.object(test_form.exception_text_edit, 'toPlainText') as mock_traceback: | 191 | test_form.file_attachment = None |
1078 | 192 | with patch.object(test_form.description_text_edit, 'toPlainText') as mock_description: | 192 | |
1079 | 193 | with patch("openlp.core.ui.exceptionform.open", mock_open(), create=True) as mocked_open: | 193 | with patch.object(test_form, '_pyuno_import') as mock_pyuno, \ |
1080 | 194 | mock_pyuno.return_value = 'UNO Bridge Test' | 194 | patch.object(test_form.exception_text_edit, 'toPlainText') as mock_traceback, \ |
1081 | 195 | mock_traceback.return_value = 'openlp: Traceback Test' | 195 | patch.object(test_form.description_text_edit, 'toPlainText') as mock_description: |
1082 | 196 | mock_description.return_value = 'Description Test' | 196 | mock_pyuno.return_value = 'UNO Bridge Test' |
1083 | 197 | 197 | mock_traceback.return_value = 'openlp: Traceback Test' | |
1084 | 198 | # WHEN: on_save_report_button_clicked called | 198 | mock_description.return_value = 'Description Test' |
1085 | 199 | test_form.on_save_report_button_clicked() | 199 | |
1086 | 200 | # WHEN: on_save_report_button_clicked called | ||
1087 | 201 | test_form.on_save_report_button_clicked() | ||
1088 | 200 | 202 | ||
1089 | 201 | # THEN: Verify proper calls to save file | 203 | # THEN: Verify proper calls to save file |
1090 | 202 | # self.maxDiff = None | 204 | # self.maxDiff = None |
1095 | 203 | check_text = "call().write({text})".format(text=MAIL_ITEM_TEXT.__repr__()) | 205 | mocked_path_open.assert_has_calls([call().__enter__().write(MAIL_ITEM_TEXT)]) |
1092 | 204 | write_text = "{text}".format(text=mocked_open.mock_calls[1]) | ||
1093 | 205 | mocked_open.assert_called_with('testfile.txt', 'w') | ||
1094 | 206 | self.assertEquals(check_text, write_text, "Saved information should match test text") | ||
1096 | 207 | 206 | ||
1097 | === modified file 'tests/functional/openlp_plugins/images/test_lib.py' | |||
1098 | --- tests/functional/openlp_plugins/images/test_lib.py 2017-08-26 15:06:11 +0000 | |||
1099 | +++ tests/functional/openlp_plugins/images/test_lib.py 2017-09-25 17:10:35 +0000 | |||
1100 | @@ -58,7 +58,7 @@ | |||
1101 | 58 | Test that the validate_and_load_test() method when called without a group | 58 | Test that the validate_and_load_test() method when called without a group |
1102 | 59 | """ | 59 | """ |
1103 | 60 | # GIVEN: A list of files | 60 | # GIVEN: A list of files |
1105 | 61 | file_list = ['/path1/image1.jpg', '/path2/image2.jpg'] | 61 | file_list = [Path('path1', 'image1.jpg'), Path('path2', 'image2.jpg')] |
1106 | 62 | 62 | ||
1107 | 63 | # WHEN: Calling validate_and_load with the list of files | 63 | # WHEN: Calling validate_and_load with the list of files |
1108 | 64 | self.media_item.validate_and_load(file_list) | 64 | self.media_item.validate_and_load(file_list) |
1109 | @@ -66,7 +66,7 @@ | |||
1110 | 66 | # THEN: load_list should have been called with the file list and None, | 66 | # THEN: load_list should have been called with the file list and None, |
1111 | 67 | # the directory should have been saved to the settings | 67 | # the directory should have been saved to the settings |
1112 | 68 | mocked_load_list.assert_called_once_with(file_list, None) | 68 | mocked_load_list.assert_called_once_with(file_list, None) |
1114 | 69 | mocked_settings().setValue.assert_called_once_with(ANY, Path('/', 'path1')) | 69 | mocked_settings().setValue.assert_called_once_with(ANY, Path('path1')) |
1115 | 70 | 70 | ||
1116 | 71 | @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_list') | 71 | @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_list') |
1117 | 72 | @patch('openlp.plugins.images.lib.mediaitem.Settings') | 72 | @patch('openlp.plugins.images.lib.mediaitem.Settings') |
1118 | @@ -75,7 +75,7 @@ | |||
1119 | 75 | Test that the validate_and_load_test() method when called with a group | 75 | Test that the validate_and_load_test() method when called with a group |
1120 | 76 | """ | 76 | """ |
1121 | 77 | # GIVEN: A list of files | 77 | # GIVEN: A list of files |
1123 | 78 | file_list = ['/path1/image1.jpg', '/path2/image2.jpg'] | 78 | file_list = [Path('path1', 'image1.jpg'), Path('path2', 'image2.jpg')] |
1124 | 79 | 79 | ||
1125 | 80 | # WHEN: Calling validate_and_load with the list of files and a group | 80 | # WHEN: Calling validate_and_load with the list of files and a group |
1126 | 81 | self.media_item.validate_and_load(file_list, 'group') | 81 | self.media_item.validate_and_load(file_list, 'group') |
1127 | @@ -83,7 +83,7 @@ | |||
1128 | 83 | # THEN: load_list should have been called with the file list and the group name, | 83 | # THEN: load_list should have been called with the file list and the group name, |
1129 | 84 | # the directory should have been saved to the settings | 84 | # the directory should have been saved to the settings |
1130 | 85 | mocked_load_list.assert_called_once_with(file_list, 'group') | 85 | mocked_load_list.assert_called_once_with(file_list, 'group') |
1132 | 86 | mocked_settings().setValue.assert_called_once_with(ANY, Path('/', 'path1')) | 86 | mocked_settings().setValue.assert_called_once_with(ANY, Path('path1')) |
1133 | 87 | 87 | ||
1134 | 88 | @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') | 88 | @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') |
1135 | 89 | def test_save_new_images_list_empty_list(self, mocked_load_full_list): | 89 | def test_save_new_images_list_empty_list(self, mocked_load_full_list): |
1136 | @@ -107,8 +107,8 @@ | |||
1137 | 107 | Test that the save_new_images_list() calls load_full_list() when reload_list is set to True | 107 | Test that the save_new_images_list() calls load_full_list() when reload_list is set to True |
1138 | 108 | """ | 108 | """ |
1139 | 109 | # GIVEN: A list with 1 image and a mocked out manager | 109 | # GIVEN: A list with 1 image and a mocked out manager |
1142 | 110 | image_list = ['test_image.jpg'] | 110 | image_list = [Path('test_image.jpg')] |
1143 | 111 | ImageFilenames.filename = '' | 111 | ImageFilenames.file_path = None |
1144 | 112 | self.media_item.manager = MagicMock() | 112 | self.media_item.manager = MagicMock() |
1145 | 113 | 113 | ||
1146 | 114 | # WHEN: We run save_new_images_list with reload_list=True | 114 | # WHEN: We run save_new_images_list with reload_list=True |
1147 | @@ -118,7 +118,7 @@ | |||
1148 | 118 | self.assertEquals(mocked_load_full_list.call_count, 1, 'load_full_list() should have been called') | 118 | self.assertEquals(mocked_load_full_list.call_count, 1, 'load_full_list() should have been called') |
1149 | 119 | 119 | ||
1150 | 120 | # CLEANUP: Remove added attribute from ImageFilenames | 120 | # CLEANUP: Remove added attribute from ImageFilenames |
1152 | 121 | delattr(ImageFilenames, 'filename') | 121 | delattr(ImageFilenames, 'file_path') |
1153 | 122 | 122 | ||
1154 | 123 | @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') | 123 | @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') |
1155 | 124 | def test_save_new_images_list_single_image_without_reload(self, mocked_load_full_list): | 124 | def test_save_new_images_list_single_image_without_reload(self, mocked_load_full_list): |
1156 | @@ -126,7 +126,7 @@ | |||
1157 | 126 | Test that the save_new_images_list() doesn't call load_full_list() when reload_list is set to False | 126 | Test that the save_new_images_list() doesn't call load_full_list() when reload_list is set to False |
1158 | 127 | """ | 127 | """ |
1159 | 128 | # GIVEN: A list with 1 image and a mocked out manager | 128 | # GIVEN: A list with 1 image and a mocked out manager |
1161 | 129 | image_list = ['test_image.jpg'] | 129 | image_list = [Path('test_image.jpg')] |
1162 | 130 | self.media_item.manager = MagicMock() | 130 | self.media_item.manager = MagicMock() |
1163 | 131 | 131 | ||
1164 | 132 | # WHEN: We run save_new_images_list with reload_list=False | 132 | # WHEN: We run save_new_images_list with reload_list=False |
1165 | @@ -141,7 +141,7 @@ | |||
1166 | 141 | Test that the save_new_images_list() saves all images in the list | 141 | Test that the save_new_images_list() saves all images in the list |
1167 | 142 | """ | 142 | """ |
1168 | 143 | # GIVEN: A list with 3 images | 143 | # GIVEN: A list with 3 images |
1170 | 144 | image_list = ['test_image_1.jpg', 'test_image_2.jpg', 'test_image_3.jpg'] | 144 | image_list = [Path('test_image_1.jpg'), Path('test_image_2.jpg'), Path('test_image_3.jpg')] |
1171 | 145 | self.media_item.manager = MagicMock() | 145 | self.media_item.manager = MagicMock() |
1172 | 146 | 146 | ||
1173 | 147 | # WHEN: We run save_new_images_list with the list of 3 images | 147 | # WHEN: We run save_new_images_list with the list of 3 images |
1174 | @@ -157,7 +157,7 @@ | |||
1175 | 157 | Test that the save_new_images_list() ignores everything in the provided list except strings | 157 | Test that the save_new_images_list() ignores everything in the provided list except strings |
1176 | 158 | """ | 158 | """ |
1177 | 159 | # GIVEN: A list with images and objects | 159 | # GIVEN: A list with images and objects |
1179 | 160 | image_list = ['test_image_1.jpg', None, True, ImageFilenames(), 'test_image_2.jpg'] | 160 | image_list = [Path('test_image_1.jpg'), None, True, ImageFilenames(), Path('test_image_2.jpg')] |
1180 | 161 | self.media_item.manager = MagicMock() | 161 | self.media_item.manager = MagicMock() |
1181 | 162 | 162 | ||
1182 | 163 | # WHEN: We run save_new_images_list with the list of images and objects | 163 | # WHEN: We run save_new_images_list with the list of images and objects |
1183 | @@ -191,7 +191,7 @@ | |||
1184 | 191 | ImageGroups.parent_id = 1 | 191 | ImageGroups.parent_id = 1 |
1185 | 192 | self.media_item.manager = MagicMock() | 192 | self.media_item.manager = MagicMock() |
1186 | 193 | self.media_item.manager.get_all_objects.side_effect = self._recursively_delete_group_side_effect | 193 | self.media_item.manager.get_all_objects.side_effect = self._recursively_delete_group_side_effect |
1188 | 194 | self.media_item.service_path = '' | 194 | self.media_item.service_path = Path() |
1189 | 195 | test_group = ImageGroups() | 195 | test_group = ImageGroups() |
1190 | 196 | test_group.id = 1 | 196 | test_group.id = 1 |
1191 | 197 | 197 | ||
1192 | @@ -215,13 +215,13 @@ | |||
1193 | 215 | # Create some fake objects that should be removed | 215 | # Create some fake objects that should be removed |
1194 | 216 | returned_object1 = ImageFilenames() | 216 | returned_object1 = ImageFilenames() |
1195 | 217 | returned_object1.id = 1 | 217 | returned_object1.id = 1 |
1197 | 218 | returned_object1.filename = '/tmp/test_file_1.jpg' | 218 | returned_object1.file_path = Path('/', 'tmp', 'test_file_1.jpg') |
1198 | 219 | returned_object2 = ImageFilenames() | 219 | returned_object2 = ImageFilenames() |
1199 | 220 | returned_object2.id = 2 | 220 | returned_object2.id = 2 |
1201 | 221 | returned_object2.filename = '/tmp/test_file_2.jpg' | 221 | returned_object2.file_path = Path('/', 'tmp', 'test_file_2.jpg') |
1202 | 222 | returned_object3 = ImageFilenames() | 222 | returned_object3 = ImageFilenames() |
1203 | 223 | returned_object3.id = 3 | 223 | returned_object3.id = 3 |
1205 | 224 | returned_object3.filename = '/tmp/test_file_3.jpg' | 224 | returned_object3.file_path = Path('/', 'tmp', 'test_file_3.jpg') |
1206 | 225 | return [returned_object1, returned_object2, returned_object3] | 225 | return [returned_object1, returned_object2, returned_object3] |
1207 | 226 | if args[1] == ImageGroups and args[2]: | 226 | if args[1] == ImageGroups and args[2]: |
1208 | 227 | # Change the parent_id that is matched so we don't get into an endless loop | 227 | # Change the parent_id that is matched so we don't get into an endless loop |
1209 | @@ -243,9 +243,9 @@ | |||
1210 | 243 | test_image = ImageFilenames() | 243 | test_image = ImageFilenames() |
1211 | 244 | test_image.id = 1 | 244 | test_image.id = 1 |
1212 | 245 | test_image.group_id = 1 | 245 | test_image.group_id = 1 |
1214 | 246 | test_image.filename = 'imagefile.png' | 246 | test_image.file_path = Path('imagefile.png') |
1215 | 247 | self.media_item.manager = MagicMock() | 247 | self.media_item.manager = MagicMock() |
1217 | 248 | self.media_item.service_path = '' | 248 | self.media_item.service_path = Path() |
1218 | 249 | self.media_item.list_view = MagicMock() | 249 | self.media_item.list_view = MagicMock() |
1219 | 250 | mocked_row_item = MagicMock() | 250 | mocked_row_item = MagicMock() |
1220 | 251 | mocked_row_item.data.return_value = test_image | 251 | mocked_row_item.data.return_value = test_image |
1221 | @@ -265,13 +265,13 @@ | |||
1222 | 265 | # GIVEN: An ImageFilenames that already exists in the database | 265 | # GIVEN: An ImageFilenames that already exists in the database |
1223 | 266 | image_file = ImageFilenames() | 266 | image_file = ImageFilenames() |
1224 | 267 | image_file.id = 1 | 267 | image_file.id = 1 |
1226 | 268 | image_file.filename = '/tmp/test_file_1.jpg' | 268 | image_file.file_path = Path('/', 'tmp', 'test_file_1.jpg') |
1227 | 269 | self.media_item.manager = MagicMock() | 269 | self.media_item.manager = MagicMock() |
1228 | 270 | self.media_item.manager.get_object_filtered.return_value = image_file | 270 | self.media_item.manager.get_object_filtered.return_value = image_file |
1230 | 271 | ImageFilenames.filename = '' | 271 | ImageFilenames.file_path = None |
1231 | 272 | 272 | ||
1232 | 273 | # WHEN: create_item_from_id() is called | 273 | # WHEN: create_item_from_id() is called |
1234 | 274 | item = self.media_item.create_item_from_id(1) | 274 | item = self.media_item.create_item_from_id('1') |
1235 | 275 | 275 | ||
1236 | 276 | # THEN: A QTreeWidgetItem should be created with the above model object as it's data | 276 | # THEN: A QTreeWidgetItem should be created with the above model object as it's data |
1237 | 277 | self.assertIsInstance(item, QtWidgets.QTreeWidgetItem) | 277 | self.assertIsInstance(item, QtWidgets.QTreeWidgetItem) |
1238 | @@ -279,4 +279,4 @@ | |||
1239 | 279 | item_data = item.data(0, QtCore.Qt.UserRole) | 279 | item_data = item.data(0, QtCore.Qt.UserRole) |
1240 | 280 | self.assertIsInstance(item_data, ImageFilenames) | 280 | self.assertIsInstance(item_data, ImageFilenames) |
1241 | 281 | self.assertEqual(1, item_data.id) | 281 | self.assertEqual(1, item_data.id) |
1243 | 282 | self.assertEqual('/tmp/test_file_1.jpg', item_data.filename) | 282 | self.assertEqual(Path('/', 'tmp', 'test_file_1.jpg'), item_data.file_path) |
1244 | 283 | 283 | ||
1245 | === added file 'tests/functional/openlp_plugins/images/test_upgrade.py' | |||
1246 | --- tests/functional/openlp_plugins/images/test_upgrade.py 1970-01-01 00:00:00 +0000 | |||
1247 | +++ tests/functional/openlp_plugins/images/test_upgrade.py 2017-09-25 17:10:35 +0000 | |||
1248 | @@ -0,0 +1,83 @@ | |||
1249 | 1 | # -*- coding: utf-8 -*- | ||
1250 | 2 | # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 | ||
1251 | 3 | |||
1252 | 4 | ############################################################################### | ||
1253 | 5 | # OpenLP - Open Source Lyrics Projection # | ||
1254 | 6 | # --------------------------------------------------------------------------- # | ||
1255 | 7 | # Copyright (c) 2008-2017 OpenLP Developers # | ||
1256 | 8 | # --------------------------------------------------------------------------- # | ||
1257 | 9 | # This program is free software; you can redistribute it and/or modify it # | ||
1258 | 10 | # under the terms of the GNU General Public License as published by the Free # | ||
1259 | 11 | # Software Foundation; version 2 of the License. # | ||
1260 | 12 | # # | ||
1261 | 13 | # This program is distributed in the hope that it will be useful, but WITHOUT # | ||
1262 | 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # | ||
1263 | 15 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # | ||
1264 | 16 | # more details. # | ||
1265 | 17 | # # | ||
1266 | 18 | # You should have received a copy of the GNU General Public License along # | ||
1267 | 19 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # | ||
1268 | 20 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # | ||
1269 | 21 | ############################################################################### | ||
1270 | 22 | """ | ||
1271 | 23 | This module contains tests for the lib submodule of the Images plugin. | ||
1272 | 24 | """ | ||
1273 | 25 | import os | ||
1274 | 26 | import shutil | ||
1275 | 27 | from tempfile import mkdtemp | ||
1276 | 28 | from unittest import TestCase | ||
1277 | 29 | from unittest.mock import patch | ||
1278 | 30 | |||
1279 | 31 | from openlp.core.common import AppLocation, Settings | ||
1280 | 32 | from openlp.core.common.path import Path | ||
1281 | 33 | from openlp.core.lib.db import Manager | ||
1282 | 34 | from openlp.plugins.images.lib import upgrade | ||
1283 | 35 | from openlp.plugins.images.lib.db import ImageFilenames, init_schema | ||
1284 | 36 | |||
1285 | 37 | from tests.helpers.testmixin import TestMixin | ||
1286 | 38 | from tests.utils.constants import TEST_RESOURCES_PATH | ||
1287 | 39 | |||
1288 | 40 | __default_settings__ = { | ||
1289 | 41 | 'images/db type': 'sqlite', | ||
1290 | 42 | 'images/background color': '#000000', | ||
1291 | 43 | } | ||
1292 | 44 | |||
1293 | 45 | |||
1294 | 46 | class TestImageDBUpgrade(TestCase, TestMixin): | ||
1295 | 47 | """ | ||
1296 | 48 | Test that the image database is upgraded correctly | ||
1297 | 49 | """ | ||
1298 | 50 | def setUp(self): | ||
1299 | 51 | self.build_settings() | ||
1300 | 52 | Settings().extend_default_settings(__default_settings__) | ||
1301 | 53 | self.tmp_folder = mkdtemp() | ||
1302 | 54 | |||
1303 | 55 | def tearDown(self): | ||
1304 | 56 | """ | ||
1305 | 57 | Delete all the C++ objects at the end so that we don't have a segfault | ||
1306 | 58 | """ | ||
1307 | 59 | self.destroy_settings() | ||
1308 | 60 | # Ignore errors since windows can have problems with locked files | ||
1309 | 61 | shutil.rmtree(self.tmp_folder, ignore_errors=True) | ||
1310 | 62 | |||
1311 | 63 | def test_image_filenames_table(self): | ||
1312 | 64 | """ | ||
1313 | 65 | Test that the ImageFilenames table is correctly upgraded to the latest version | ||
1314 | 66 | """ | ||
1315 | 67 | # GIVEN: An unversioned image database | ||
1316 | 68 | temp_db_name = os.path.join(self.tmp_folder, 'image-v0.sqlite') | ||
1317 | 69 | shutil.copyfile(os.path.join(TEST_RESOURCES_PATH, 'images', 'image-v0.sqlite'), temp_db_name) | ||
1318 | 70 | |||
1319 | 71 | with patch.object(AppLocation, 'get_data_path', return_value=Path('/', 'test', 'dir')): | ||
1320 | 72 | # WHEN: Initalising the database manager | ||
1321 | 73 | manager = Manager('images', init_schema, db_file_path=temp_db_name, upgrade_mod=upgrade) | ||
1322 | 74 | |||
1323 | 75 | # THEN: The database should have been upgraded and image_filenames.file_path should return Path objects | ||
1324 | 76 | upgraded_results = manager.get_all_objects(ImageFilenames) | ||
1325 | 77 | |||
1326 | 78 | expected_result_data = {1: Path('/', 'test', 'image1.jpg'), | ||
1327 | 79 | 2: Path('/', 'test', 'dir', 'image2.jpg'), | ||
1328 | 80 | 3: Path('/', 'test', 'dir', 'subdir', 'image3.jpg')} | ||
1329 | 81 | |||
1330 | 82 | for result in upgraded_results: | ||
1331 | 83 | self.assertEqual(expected_result_data[result.id], result.file_path) | ||
1332 | 0 | 84 | ||
1333 | === added directory 'tests/resources/images' | |||
1334 | === added file 'tests/resources/images/image-v0.sqlite' | |||
1335 | 1 | Binary files tests/resources/images/image-v0.sqlite 1970-01-01 00:00:00 +0000 and tests/resources/images/image-v0.sqlite 2017-09-25 17:10:35 +0000 differ | 85 | Binary files tests/resources/images/image-v0.sqlite 1970-01-01 00:00:00 +0000 and tests/resources/images/image-v0.sqlite 2017-09-25 17:10:35 +0000 differ |
Why have you removed a couple of __init__ methods?