pyqttoolkit 0.8.0.dev0__tar.gz → 0.8.0.post1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/PKG-INFO +5 -4
  2. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/_version.py +3 -3
  3. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/application/application.py +2 -11
  4. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/application/garbage_collector.py +14 -14
  5. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/environment.py +8 -1
  6. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/with_signal.py +1 -1
  7. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/with_value_changed.py +3 -3
  8. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/__init__.py +1 -0
  9. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/interval.py +8 -11
  10. pyqttoolkit-0.8.0.post1/pyqttoolkit/data/message.py +29 -0
  11. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/datetime/qdatetime.py +2 -4
  12. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/dependencies/__init__.py +7 -5
  13. pyqttoolkit-0.8.0.post1/pyqttoolkit/exceptions/__init__.py +18 -0
  14. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/logs/__init__.py +29 -0
  15. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/code_text.py +8 -5
  16. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/dataframetable.py +1 -3
  17. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/dictpropertytree.py +1 -3
  18. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/dicttable.py +1 -2
  19. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/json_text.py +1 -3
  20. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/list_model.py +1 -2
  21. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/span.py +36 -32
  22. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/events/rejectable.py +1 -2
  23. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/launcher_config.py +1 -2
  24. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/module.py +3 -2
  25. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/scripting/script_runner.py +14 -11
  26. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/event_registry.py +1 -0
  27. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/file_dialog.py +24 -7
  28. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/hotkey_manager.py +1 -3
  29. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/link_manager.py +2 -2
  30. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/message_board.py +22 -21
  31. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/module_service.py +26 -17
  32. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/project_updater.py +5 -6
  33. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/task_runner.py +11 -14
  34. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/tool_window_service.py +1 -3
  35. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/__init__.py +1 -1
  36. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/bulk_value_selector.py +15 -6
  37. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/check_box.py +2 -2
  38. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/code/code_edit.py +25 -15
  39. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/combo_box.py +1 -4
  40. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/count_selector.py +2 -2
  41. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/datetime.py +9 -8
  42. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/datetime_range_selector.py +56 -14
  43. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/delegates.py +3 -4
  44. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/dtype_edit.py +3 -4
  45. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/file_selector.py +2 -2
  46. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/icon.py +12 -11
  47. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/icon_button.py +3 -3
  48. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/labelled.py +1 -1
  49. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/__init__.py +1 -1
  50. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/collabsible.py +2 -4
  51. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/group_box.py +2 -2
  52. pyqttoolkit-0.8.0.post1/pyqttoolkit/views/layout/group_panel.py +188 -0
  53. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/lines.py +1 -2
  54. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/link.py +1 -1
  55. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/line_edit.py +1 -2
  56. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/linkable.py +1 -2
  57. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/list_view.py +2 -2
  58. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/main_window.py +10 -8
  59. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/metadata_selector.py +2 -2
  60. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/modulewindow.py +12 -4
  61. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/legend_control.py +10 -3
  62. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/__init__.py +23 -23
  63. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/base.py +175 -64
  64. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/plot_options.py +8 -4
  65. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/plot_toolbar_options.py +4 -4
  66. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/toolbar.py +2 -3
  67. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/popout.py +2 -2
  68. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/popup.py +5 -3
  69. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/property_tree.py +1 -2
  70. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/shrunk_push_button.py +1 -2
  71. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/steppable_combo_box.py +2 -3
  72. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/styleable.py +18 -17
  73. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/table.py +3 -3
  74. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/text_edit.py +3 -2
  75. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/tool_window.py +1 -2
  76. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/PKG-INFO +5 -4
  77. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/SOURCES.txt +2 -0
  78. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/requires.txt +3 -1
  79. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/setup.py +5 -5
  80. pyqttoolkit-0.8.0.dev0/pyqttoolkit/views/layout/group_panel.py +0 -114
  81. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/MANIFEST.in +0 -0
  82. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/README.md +0 -0
  83. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/__init__.py +0 -0
  84. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/application/__init__.py +0 -0
  85. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/colors/__init__.py +0 -0
  86. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/__init__.py +0 -0
  87. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/base.py +0 -0
  88. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/composite.py +0 -0
  89. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/default.py +0 -0
  90. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/multi_json_file.py +0 -0
  91. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/bits.py +0 -0
  92. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/cache.py +0 -0
  93. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/names.py +0 -0
  94. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/datetime/__init__.py +0 -0
  95. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/datetime/datetime.py +0 -0
  96. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/errors/__init__.py +0 -0
  97. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/filesystem/__init__.py +0 -0
  98. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/__init__.py +0 -0
  99. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/dataframe_metadata_manager.py +0 -0
  100. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/dict_metadata_manager.py +0 -0
  101. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/id_generator.py +0 -0
  102. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/metadata_manager_base.py +0 -0
  103. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/__init__.py +0 -0
  104. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/module.py +0 -0
  105. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/roles.py +0 -0
  106. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/series_data.py +0 -0
  107. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/validation.py +0 -0
  108. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/__init__.py +0 -0
  109. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/events/__init__.py +0 -0
  110. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/events/add_signal.py +0 -0
  111. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/events/module_opening.py +0 -0
  112. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/properties/__init__.py +0 -0
  113. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/properties/auto.py +0 -0
  114. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/properties/throttled.py +0 -0
  115. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/scripting/__init__.py +0 -0
  116. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/scripting/script_context.py +0 -0
  117. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/scripting/script_template.py +0 -0
  118. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/__init__.py +0 -0
  119. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/autosave.py +0 -0
  120. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/email.py +0 -0
  121. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/object_converter.py +0 -0
  122. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/theme_manager.py +0 -0
  123. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/viewmanagers/__init__.py +0 -0
  124. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/viewmanagers/tool.py +0 -0
  125. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/code/__init__.py +0 -0
  126. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/code/python_syntax.py +0 -0
  127. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/default_text_line_edit.py +0 -0
  128. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/editable_combo_box.py +0 -0
  129. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/json_edit.py +0 -0
  130. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/__init__.py +0 -0
  131. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/colorbar.py +0 -0
  132. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/colormap.py +0 -0
  133. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/font.py +0 -0
  134. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/size.py +0 -0
  135. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/tool_type.py +0 -0
  136. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/dependency_links.txt +0 -0
  137. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/top_level.txt +0 -0
  138. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/setup.cfg +0 -0
  139. {pyqttoolkit-0.8.0.dev0 → pyqttoolkit-0.8.0.post1}/versioneer.py +0 -0
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyqttoolkit
3
- Version: 0.8.0.dev0
3
+ Version: 0.8.0.post1
4
4
  Summary: A toolkit for PyQt 5
5
- Home-page: https://github.com/Simmovation/pyqttoolkit
6
- Author: Simmovation Ltd
7
- Author-email: info@simmovation.tech
5
+ Home-page: https://github.com/BitBloomTech/pyqttoolkit
6
+ Author: Bitbloom Ltd
7
+ Author-email: info@bitbloom.tech
8
8
  License: GPLv3
9
9
  Description: # PyQtToolkit
10
10
 
@@ -13,4 +13,5 @@ Platform: any
13
13
  Requires-Python: >=3.6
14
14
  Description-Content-Type: text/markdown
15
15
  Provides-Extra: publish
16
+ Provides-Extra: ui
16
17
  Provides-Extra: test
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2022-10-05T14:38:52+0100",
11
+ "date": "2025-02-10T10:45:17-0600",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "4768565a6b3943d43446ed9ccf696915f2525c91",
15
- "version": "0.8.0.dev0"
14
+ "full-revisionid": "c01a30f0721570aa53de3b069854c5c25e9ebdb6",
15
+ "version": "0.8.0-1"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -17,9 +17,8 @@
17
17
  import sys
18
18
  import logging
19
19
 
20
- #pylint: disable=no-name-in-module
21
- from PyQt5.Qt import QApplication, QWidget, pyqtSignal
22
- #pyline: enable=no-name-in-module
20
+ from PyQt5.QtCore import pyqtSignal
21
+ from PyQt5.QtWidgets import QApplication, QWidget
23
22
 
24
23
  from pyqttoolkit.services import MessageBoard, TaskRunner, ToolWindowService, EventRegistry, ObjectConverter
25
24
  from pyqttoolkit.dependencies import DependencyContainer
@@ -54,14 +53,6 @@ class Application(QApplication):
54
53
  self.mainWindowLoaded.emit(self._module_service.openModule('Base'))
55
54
  return self.exec_()
56
55
 
57
- def notify(self, receiver, event):
58
- try:
59
- return QApplication.notify(self, receiver, event)
60
- #pylint: disable=broad-except
61
- except Exception as e:
62
- self._handle_exception(type(e), e, e.__traceback__)
63
- return True
64
-
65
56
  def _handle_exception(self, ex_type, ex_value, traceback_obj):
66
57
  LOGGER.error('Application Exception: %s, %s', ex_type, ex_value)
67
58
  if self._handling_exception:
@@ -17,9 +17,7 @@
17
17
  import gc
18
18
  import logging
19
19
 
20
- #pylint: disable=no-name-in-module
21
- from PyQt5.Qt import QObject, QTimer
22
- #pyline: enable=no-name-in-module
20
+ from PyQt5.QtCore import QObject, QTimer
23
21
 
24
22
  from pyqttoolkit.logs import TRACE
25
23
 
@@ -34,27 +32,29 @@ class GarbageCollector(QObject):
34
32
  thread, as otherwise Qt can crash.
35
33
  '''
36
34
 
37
- def __init__(self, parent, interval=10000):
38
- QObject.__init__(self, parent)
35
+ def __init__(self, parent, interval=60000):
36
+ super().__init__(parent)
39
37
  self._interval = interval
40
-
41
- self._timer = QTimer(self)
42
- self._timer.timeout.connect(self.check)
43
-
44
38
  self._threshold = gc.get_threshold()
45
39
  gc.disable()
46
- self._timer.start(self._interval)
47
40
 
48
- def check(self):
41
+ if self._interval:
42
+ self._timer = QTimer(self)
43
+ self._timer.timeout.connect(self.check)
44
+ self._timer.start(self._interval)
45
+ else:
46
+ self._timer = None
47
+
48
+ def check(self, full=False):
49
49
  l0, l1, l2 = gc.get_count()
50
50
  LOGGER.log(TRACE, 'gc_check called: l0=%d, l1=%d, l2=%d', l0, l1, l2)
51
- if l0 > self._threshold[0]:
51
+ if full or l0 > self._threshold[0]:
52
52
  num = gc.collect(0)
53
53
  LOGGER.log(TRACE, 'Collecting gen 0, found: %d unreachable', num)
54
- if l1 > self._threshold[1]:
54
+ if full or l1 > self._threshold[1]:
55
55
  num = gc.collect(1)
56
56
  LOGGER.log(TRACE, 'Collecting gen 1, found: %d unreachable', num)
57
- if l2 > self._threshold[2]:
57
+ if full or l2 > self._threshold[2]:
58
58
  num = gc.collect(2)
59
59
  LOGGER.log(TRACE, 'Collecting gen 2, found: %d unreachable', num)
60
60
 
@@ -15,11 +15,18 @@
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
  import os
18
+ import json
18
19
  from .base import BaseApplicationConfiguration
19
20
 
20
21
  class EnvironmentApplicationConfiguration(BaseApplicationConfiguration):
21
22
  def get_value(self, key):
22
- return os.getenv(self._format_key(key))
23
+ value = os.getenv(self._format_key(key))
24
+ if value is None:
25
+ return value
26
+ try:
27
+ return json.loads(value)
28
+ except json.decoder.JSONDecodeError:
29
+ return value
23
30
 
24
31
  def set_value(self, key, value):
25
32
  os.environ[self._format_key(key)] = str(value)
@@ -14,7 +14,7 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.Qt import pyqtSignal, QObject
17
+ from PyQt5.QtCore import pyqtSignal, QObject
18
18
 
19
19
  class WithValueChangedConfiguration(QObject):
20
20
  def __init__(self, inner):
@@ -14,11 +14,11 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.Qt import pyqtSignal, QObject
17
+ from PyQt5.QtCore import pyqtSignal, QObject
18
18
 
19
19
  class WithValueChangedConfiguration(QObject):
20
- def __init__(self, inner):
21
- super().__init__()
20
+ def __init__(self, parent, inner):
21
+ super().__init__(parent)
22
22
  self._inner = inner
23
23
 
24
24
  onValueChanged = pyqtSignal(str, object)
@@ -18,3 +18,4 @@ from .cache import Cache
18
18
  from .interval import calculate_interval
19
19
  from .bits import get_next_available_bit
20
20
  from .names import get_next_available_name
21
+ from .message import MessageType, MessageResponse
@@ -14,16 +14,13 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ import pandas as pd
18
+
17
19
  def calculate_interval(values, sort=True):
18
- interval = None
19
- last_value = None
20
+ if len(values) < 2:
21
+ return None
22
+ values_series = pd.Series(values)
20
23
  if sort:
21
- values = sorted(values)
22
- for value in values:
23
- if last_value is not None:
24
- next_interval = value - last_value
25
- if next_interval == interval:
26
- return interval
27
- interval = next_interval
28
- last_value = value
29
- return interval
24
+ values_series = values_series.sort_values()
25
+ # We want to ensure that the calculated interval is accurate for 90% of values to avoid mistakenly losing values
26
+ return (values_series - values_series.shift(1)).quantile(0.1)
@@ -0,0 +1,29 @@
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ from enum import Enum, IntEnum
18
+
19
+ class MessageType(Enum):
20
+ validation_error = 0
21
+ confirmation = 1
22
+ application_exception = 2
23
+
24
+ class MessageResponse(IntEnum):
25
+ ok = 1
26
+ cancel = 2
27
+ save = 4
28
+ discard = 8
29
+ ignore = 16
@@ -19,9 +19,7 @@ from .datetime import round_timedelta
19
19
 
20
20
  import pandas as pd
21
21
 
22
- #pylint: disable=no-name-in-module
23
- from PyQt5.Qt import QDateTime, QDate, QTime
24
- #pylint: enable=no-name-in-module
22
+ from PyQt5.QtCore import QDateTime, QDate, QTime
25
23
 
26
24
  def q_datetime_to_datetime(q_datetime: QDateTime):
27
25
  if q_datetime is None or not q_datetime.isValid():
@@ -39,7 +37,7 @@ def pd_timestamp_to_q_datetime(pd_timestamp: datetime):
39
37
  return QDateTime()
40
38
  return QDateTime(
41
39
  QDate(pd_timestamp.year, pd_timestamp.month, pd_timestamp.day),
42
- QTime(pd_timestamp.hour, pd_timestamp.minute, pd_timestamp.second, pd_timestamp.microsecond / 1000)
40
+ QTime(pd_timestamp.hour, pd_timestamp.minute, pd_timestamp.second, pd_timestamp.microsecond // 1000)
43
41
  )
44
42
 
45
43
  def step_qdatetime(control, fraction, interval, range_start, range_end):
@@ -37,12 +37,14 @@ class DependencyContainer:
37
37
  def resolve(self, type_, extras=None, none_for_missing=False):
38
38
  args = self._get_args(type_)
39
39
  all_dependencies = {**self._instances, **(extras or {})}
40
- for a in args:
41
- if a not in all_dependencies.keys():
42
- if none_for_missing:
43
- all_dependencies[a] = None
40
+ for arg_name, arg in args.items():
41
+ if arg_name not in all_dependencies:
42
+ if arg.default != inspect.Parameter.empty:
43
+ all_dependencies[arg_name] = arg.default
44
+ elif none_for_missing:
45
+ all_dependencies[arg_name] = None
44
46
  else:
45
- raise MissingDependency(type_, a)
47
+ raise MissingDependency(type_, arg_name)
46
48
  return type_(**{a: all_dependencies[a] for a in args})
47
49
 
48
50
  def resolve_for(self, type_for, base_type, extras=None):
@@ -0,0 +1,18 @@
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ class TaskCancelled(Exception):
18
+ pass
@@ -14,6 +14,8 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ from typing import Callable
18
+ from io import StringIO
17
19
  import logging
18
20
  from logging import handlers
19
21
  from functools import wraps
@@ -109,3 +111,30 @@ def logf(level, log_args=True):
109
111
  return result
110
112
  return _
111
113
  return logf_decorator
114
+
115
+
116
+ class LogStream:
117
+ def __init__(self, notify_update: Callable = None):
118
+ self._buffer = StringIO()
119
+ self._notify_update = notify_update
120
+
121
+ def __iadd__(self, other):
122
+ self.write(other)
123
+ return self
124
+
125
+ def write(self, message):
126
+ self._buffer.write(message)
127
+ if self._notify_update:
128
+ self._notify_update()
129
+
130
+ def flush(self):
131
+ self._buffer.flush()
132
+
133
+ def getvalue(self):
134
+ return self._buffer.getvalue()
135
+
136
+ def clear(self):
137
+ self._buffer.close()
138
+ self._buffer = StringIO()
139
+ if self._notify_update:
140
+ self._notify_update()
@@ -14,10 +14,10 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.Qt import QObject, pyqtSignal
18
- #pylint: enable=no-name-in-module
17
+ from PyQt5.QtCore import QObject, pyqtSignal
19
18
 
20
19
  from pyqttoolkit.properties import AutoProperty
20
+ from pyqttoolkit.logs import LogStream
21
21
 
22
22
  class CodeTextModel(QObject):
23
23
  def __init__(self, parent, validator):
@@ -25,16 +25,19 @@ class CodeTextModel(QObject):
25
25
  self.textChanged.connect(self._validate)
26
26
  self._validator = validator
27
27
  self.text = ''
28
- self.output = ''
28
+ self.output = LogStream(self._handle_output_buffer_changed)
29
29
 
30
30
  textChanged = pyqtSignal(str)
31
- outputChanged = pyqtSignal(str)
31
+ outputChanged = pyqtSignal(LogStream)
32
32
  validationMessageChanged = pyqtSignal(str)
33
33
 
34
34
  text = AutoProperty(str)
35
- output = AutoProperty(str)
35
+ output = AutoProperty(LogStream)
36
36
  validationMessage = AutoProperty(str)
37
37
 
38
38
  def _validate(self, value):
39
39
  validation_model = self._validator(value)
40
40
  self.validationMessage = validation_model.error if validation_model else ''
41
+
42
+ def _handle_output_buffer_changed(self):
43
+ self.outputChanged.emit(self.output)
@@ -14,9 +14,7 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.QtCore import pyqtSignal
18
- from PyQt5.Qt import QAbstractTableModel, Qt, QVariant, QModelIndex, QItemSelectionModel
19
- #pylint: enable=no-name-in-module
17
+ from PyQt5.QtCore import pyqtSignal, QAbstractTableModel, Qt, QVariant, QModelIndex, QItemSelectionModel
20
18
 
21
19
  class DataFrameTableModel(QAbstractTableModel):
22
20
  def __init__(self, parent, data, display_column=None, editable=False, row_headers=False):
@@ -16,9 +16,7 @@
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
  from enum import Enum
18
18
 
19
- #pylint: disable=no-name-in-module
20
- from PyQt5.Qt import Qt, QAbstractItemModel, pyqtSignal, QModelIndex, QVariant
21
- #pylint: enable=no-name-in-module
19
+ from PyQt5.QtCore import Qt, QAbstractItemModel, pyqtSignal, QModelIndex, QVariant
22
20
 
23
21
  class DictPropertyTreeModel(QAbstractItemModel):
24
22
  def __init__(self, parent, data):
@@ -14,8 +14,7 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.Qt import Qt, QAbstractTableModel, pyqtSignal, QModelIndex
18
- #pylint: enable=no-name-in-module
17
+ from PyQt5.QtCore import Qt, QAbstractTableModel, pyqtSignal, QModelIndex
19
18
 
20
19
  from pyqttoolkit.models.roles import DataRole
21
20
 
@@ -16,9 +16,7 @@
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
  from json import loads, dumps, JSONDecodeError
18
18
 
19
- #pylint: disable=no-name-in-module
20
- from PyQt5.Qt import QObject, pyqtSignal
21
- #pylint: enable=no-name-in-module
19
+ from PyQt5.QtCore import QObject, pyqtSignal
22
20
 
23
21
  from pyqttoolkit.properties import AutoProperty
24
22
 
@@ -14,8 +14,7 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.Qt import Qt, QAbstractListModel, QStringListModel
18
- #pylint: enable=no-name-in-module
17
+ from PyQt5.QtCore import Qt, QAbstractListModel, QStringListModel
19
18
 
20
19
  from pyqttoolkit.models.roles import DataRole
21
20
 
@@ -1,32 +1,36 @@
1
- # pyqttoolkit
2
- # Copyright (C) 2018-2019, Simmovation Ltd.
3
- #
4
- # This program is free software; you can redistribute it and/or modify
5
- # it under the terms of the GNU General Public License as published by
6
- # the Free Software Foundation; either version 3 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with this program; if not, write to the Free Software Foundation,
16
- # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.Qt import QObject
18
- #pylint: enable=no-name-in-module
19
-
20
- class SpanModel(QObject):
21
- def __init__(self, parent, left, right):
22
- QObject.__init__(self, parent)
23
- self._left = left
24
- self._right = right
25
-
26
- @property
27
- def left(self):
28
- return self._left
29
-
30
- @property
31
- def right(self):
32
- return self._right
1
+ # pyqttoolkit
2
+ # Copyright (C) 2018-2019, Simmovation Ltd.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ from PyQt5.QtCore import QObject
18
+
19
+ class SpanModel(QObject):
20
+ def __init__(self, parent, left, right, radians=False):
21
+ QObject.__init__(self, parent)
22
+ self._left = left
23
+ self._right = right
24
+ self._radians = radians
25
+
26
+ @property
27
+ def left(self):
28
+ return self._left
29
+
30
+ @property
31
+ def right(self):
32
+ return self._right
33
+
34
+ @property
35
+ def radians(self):
36
+ return self._radians
@@ -14,8 +14,7 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.Qt import QObject
18
- #pylint: enable=no-name-in-module
17
+ from PyQt5.QtCore import QObject
19
18
 
20
19
  class RejectableEvent(QObject):
21
20
  def __init__(self):
@@ -14,8 +14,7 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.Qt import QObject, pyqtSignal
18
- #pylint: enable=no-name-in-module
17
+ from PyQt5.QtCore import QObject, pyqtSignal
19
18
 
20
19
  from pyqttoolkit.properties import AutoProperty
21
20
 
@@ -14,8 +14,7 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program; if not, write to the Free Software Foundation,
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
- from PyQt5.Qt import QObject, pyqtSignal
18
- #pylint: enable=no-name-in-module
17
+ from PyQt5.QtCore import QObject, pyqtSignal
19
18
 
20
19
  from .events import ModuleOpeningEvent
21
20
 
@@ -24,6 +23,8 @@ class ModuleBase(QObject):
24
23
  QObject.__init__(self)
25
24
  self._id = id_
26
25
  self._launcher_config = launcher_config
26
+ if self._launcher_config:
27
+ self._launcher_config.setParent(self)
27
28
 
28
29
  opening = pyqtSignal(ModuleOpeningEvent)
29
30
  opened = pyqtSignal()
@@ -80,21 +80,24 @@ class ScriptRunner:
80
80
  self._context = None
81
81
 
82
82
  def _globals(self, context):
83
- return {'__builtins__': {**__builtins__, '__import__': self._import, 'exit': self._exit, **{g: self._not_implemented for g in self._disallowed_globals}}}
83
+ return {'__builtins__': {**__builtins__, '__import__': self._import(builtins.__import__), 'exit': self._exit, **{g: self._not_implemented for g in self._disallowed_globals}}}
84
84
 
85
85
  def compile(self, script):
86
86
  return compile(script, 'code', 'exec')
87
87
 
88
- def _import(self, module_name, *args, **kwargs):
89
- if any(re.match(m, module_name) for m in self._disallowed_modules):
90
- raise ImportError('Module not found')
91
- try:
92
-
93
- with add_paths(self._additional_paths):
94
- module = builtins.__import__(module_name, *args, **kwargs)
95
- return module
96
- except KeyError:
97
- raise ImportError('Module not found')
88
+ def _import(self, import_function):
89
+ def _(module_name, *args, **kwargs):
90
+ if any(re.match(m, module_name) for m in self._disallowed_modules):
91
+ raise ImportError('Module not found')
92
+ try:
93
+ with add_paths(self._additional_paths):
94
+ module = import_function(module_name, *args, **kwargs)
95
+ if module_name in 'importlib':
96
+ module.import_module = self._import(importlib.import_module)
97
+ return module
98
+ except KeyError:
99
+ raise ImportError('Module not found')
100
+ return _
98
101
 
99
102
  def _additional_paths(self):
100
103
  return self._additional_paths
@@ -21,6 +21,7 @@ class EventTypes:
21
21
  save_requested = 'save_requested'
22
22
  close_project_requested = 'close_project_requested'
23
23
  project_closed = 'project_closed'
24
+ save_dialog_finished = 'save_dialog_finished'
24
25
 
25
26
  class FutureConnector:
26
27
  def __init__(self):
@@ -16,17 +16,32 @@
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
  from os import path
18
18
 
19
- #pylint: disable=no-name-in-module
20
- from PyQt5.Qt import QStandardPaths, QFileDialog
21
- #pylint: enable=no-name-in-module
19
+ from PyQt5.QtCore import QStandardPaths, QTimer
20
+ from PyQt5.QtWidgets import QFileDialog
21
+
22
+ from .event_registry import EventTypes
22
23
 
23
24
  class FileDialogService:
24
- def __init__(self, project_manager, application_configuration):
25
+ def __init__(self, project_manager, application_configuration, event_registry):
25
26
  self._project_manager = project_manager
26
27
  self._application_configuration = application_configuration
27
-
28
+ self._event_registry = event_registry
29
+
30
+ def _get_dialog(self, parent, filter_, default_directory=None):
31
+ dialog = QFileDialog(
32
+ parent,
33
+ directory=default_directory or self._get_default_directory(),
34
+ filter=filter_
35
+ )
36
+ def _notify_save_dialog_finished(result):
37
+ self._event_registry.event(EventTypes.save_dialog_finished).emit(result)
38
+ dialog.finished.connect(_notify_save_dialog_finished)
39
+ return dialog
40
+
28
41
  def get_save_filename(self, parent, filter_, default_name=None):
29
- dialog = QFileDialog(parent, directory=self._get_default_directory(), filter=filter_)
42
+ default_directory = path.dirname(default_name) if default_name else None
43
+ dialog = self._get_dialog(parent, filter_, default_directory)
44
+
30
45
  if default_name:
31
46
  dialog.selectFile(default_name)
32
47
  dialog.setModal(True)
@@ -36,7 +51,7 @@ class FileDialogService:
36
51
  return dialog.selectedFiles()[0]
37
52
 
38
53
  def get_open_filename(self, parent, filter_, file_mode=None):
39
- dialog = QFileDialog(parent, directory=self._get_default_directory(), filter=filter_)
54
+ dialog = self._get_dialog(parent, filter_)
40
55
  if file_mode:
41
56
  dialog.setFileMode(file_mode)
42
57
  if dialog.exec_():
@@ -50,5 +65,7 @@ class FileDialogService:
50
65
  if default_location and path.isdir(default_location):
51
66
  return default_location
52
67
  return QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
68
+ elif self._project_manager.filename and not path.isdir(path.dirname(self._project_manager.filename)):
69
+ return QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
53
70
  else:
54
71
  return path.dirname(self._project_manager.filename)
@@ -16,9 +16,7 @@
16
16
  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
  from enum import Enum
18
18
 
19
- #pylint: disable=no-name-in-module
20
- from PyQt5.Qt import Qt
21
- #pylint: enable=no-name-in-module
19
+ from PyQt5.QtCore import Qt
22
20
 
23
21
  class HotkeyEvents(Enum):
24
22
  next_instance_y = 0