diff --git a/.prospector.yml b/.prospector.yml deleted file mode 100644 index 43862bb..0000000 --- a/.prospector.yml +++ /dev/null @@ -1,54 +0,0 @@ -strictness: high -autodetect: false -doc-warnings: true -test-warnings: true -member-warnings: true - -bandit: - run: true - options: - config: pyproject.toml - -pep257: - run: true - disable: - - D210 - - D212 - - D213 - - D413 - - D407 - - D406 - - D203 - - D401 - -pycodestyle: - disable: - - E741 - - N815 - - N816 - - N802 - - N806 - -pep8: - disable: - - N802 - -pylint: - run: true - options: - config: pyproject.toml - disable: - - R1729 - -pyroma: - run: true - -pyflakes: - run: true - disable: - - F401 - -mccabe: - run: true - disable: - - MC0001 diff --git a/CHANGELOG.md b/CHANGELOG.md index b456971..5c1f563 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # TorrentFileQt +## Version 0.3.6 + + - Edits throughout the full source code. + - Added the style manager class for qss + - included two menu options that control font size + - made changing themes and adding new themese easier + - changed the torrent file creator to run in a Qthread. + - added a status bar to show runtime messages + - adjusted the widget sizes on the recheck tab + - changed the table widgets to be QToolBars in the editor tab + - fixed all of the issues with unit tests + - switched from prospector to tox for CI and DevOps + - added `__main__.py` and the entry point. + - updated manifest + - updated packaging information and switched to pyproject.toml + - other minor bug fixes + +* * * + ## Version 0.3.0 - Added more fields the to "Edit" tab. @@ -11,7 +30,7 @@ - improved updated Icons and readme information. - other bug fixes. ----------- +* * * ## Version 0.2.0 @@ -23,7 +42,7 @@ - docstrings - screenshots for reame ----------- +* * * ## Version 0.1.0 diff --git a/MANIFEST.in b/MANIFEST.in index 281ffb4..08faba9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,13 +1,9 @@ include CHANGELOG.md -include LICENSE include Makefile include requirements.txt - graft torrentfileQt - recursive-include torrentfileQt * recursive-include torrentfileQt/assets * global-exclude *.py[cod] -prune **/__pycache__ diff --git a/README.md b/README.md index fb5ac36..c84259d 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ ![torrentfileQt.png](./assets/torrentfileQt.png) ---------- -[![Codacy Badge](https://app.codacy.com/project/badge/Grade/065ca999772a434ba1aadae05f8b6bc7)](https://www.codacy.com/gh/alexpdev/torrentfileQt/dashboard?utm_source=github.com&utm_medium=referral&utm_content=alexpdev/torrentfileQt&utm_campaign=Badge_Grade) +* * * + +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/065ca999772a434ba1aadae05f8b6bc7)](https://www.codacy.com/gh/alexpdev/torrentfileQt/dashboard?utm_source=github.com&utm_medium=referral&utm_content=alexpdev/torrentfileQt&utm_campaign=Badge_Grade) [![codecov](https://codecov.io/gh/alexpdev/torrentfileQt/branch/main/graph/badge.svg?token=S5Q9CRD6C2)](https://codecov.io/gh/alexpdev/torrentfileQt) ![PyPI - License](https://img.shields.io/pypi/l/torrentfileQt?color=orange&style=plastic) ![PyPI - Downloads](https://img.shields.io/pypi/dw/torrentfileQt?style=plastic) @@ -15,39 +16,39 @@ TorrentFileQt is a GUI Frontend for [TorrentFile CLI](https://github.com/alexpde ## Features -- Create .torrent files -- Display detailed information for a .torrent file -- Bittorrent v1, v2 and hybrid .torrent files supported -- Check if a .torrent file contents are in filesystem -- Check progress or percentage complete for .torrent file -- Edit torrent files. +- Create .torrent files +- Display detailed information for a .torrent file +- Bittorrent v1, v2 and hybrid .torrent files supported +- Check if a .torrent file contents are in filesystem +- Check progress or percentage complete for .torrent file +- Edit torrent files. ## Requirements -- Pyside6 -- torrentfile +- Pyside6 +- torrentfile ## ScreenShots ![createtorrent.png](./assets/screenshots/create-tab.png) ---------- +* * * ![checktorrent.png](./assets/screenshots/recheck-tab.png) ---------- +* * * ![edittorrent.png](./assets/screenshots/edit-tab.png) ---------- +* * * ![torrentinfo.png](./assets/screenshots/info-tab.png) ---------- +* * * ## Install -- From git: +- From git: ```bash git clone https://github.com/alexpdev/torrentfileQt.git @@ -57,7 +58,7 @@ pip install . torrentfileQt ``` -- From PyPi +- From PyPi ```bash pip install torrentfileQt diff --git a/coverage.xml b/coverage.xml index e191fb8..8046566 100644 --- a/coverage.xml +++ b/coverage.xml @@ -1,12 +1,12 @@ - + C:\Users\asp\Documents\Code\repos\torrentfileQt - + @@ -15,13 +15,13 @@ - - + + - - - - + + + + @@ -37,13 +37,13 @@ - - + + - + @@ -52,60 +52,60 @@ - - + + - - + + - - + + - - - + + - - + - + + + - - - + + + - - + + @@ -131,16 +131,16 @@ - - - + + + @@ -162,15 +162,6 @@ - - - - - - - - - @@ -205,8 +196,8 @@ - - + + @@ -215,9 +206,9 @@ - - + + @@ -236,11 +227,11 @@ - - - + + + @@ -250,10 +241,10 @@ - + @@ -262,18 +253,14 @@ - - - + + + - - - - @@ -320,31 +307,31 @@ - - + + - - + + - - + + - - - + + + @@ -362,11 +349,6 @@ - - - - - @@ -378,35 +360,46 @@ - + + + - + + - - - - + + + - - + - - + + - + + - - + + + - - + + + + + + + + + + @@ -416,10 +409,9 @@ - - - - + + + @@ -441,10 +433,10 @@ - - + + - + @@ -458,10 +450,10 @@ - - + + @@ -473,41 +465,34 @@ - - + + - - - + + + - - - + + - - + - + + - - - - - - @@ -536,8 +521,8 @@ - - + + @@ -545,40 +530,34 @@ - - + + - - + + - - - + + + - - - + + - - - - - - + @@ -608,21 +587,21 @@ - - - - + + + + - - + + - - + + @@ -630,8 +609,8 @@ - - + + @@ -642,8 +621,8 @@ - - + + @@ -653,12 +632,12 @@ - - + + - + @@ -667,11 +646,9 @@ - - - + @@ -749,61 +726,60 @@ - + - - + + - - - + + + - - - - - - - + + + + + + + - - - - - - - - - - + + + + + + + + + + - + - - - - + + + + - - - - - - - + + + + + + + - - + @@ -820,7 +796,16 @@ - + + + + + + + + + + @@ -833,9 +818,8 @@ - - - + + @@ -843,24 +827,24 @@ - + - + - + - + - + @@ -872,7 +856,7 @@ - + @@ -884,16 +868,16 @@ - - - - + + + + - - + + @@ -905,185 +889,200 @@ - - - + + + - - - + + + + + - - - + + + + + - - - - + + + + + + + + - - - - - + + + + - - - + - - - - - + + + + + + + + + + + + + - + + - - - + + - + - - - + + - - + + + + - - + - + - + + - - + + - - + + - - - - - - - - + - + + + + + + + + + + + + + + - - + + - - - - - - - - + + + + + + + + - + + - - - - - - @@ -1091,19 +1090,19 @@ - + - - - + - + + + @@ -1112,38 +1111,18 @@ - + + - - + + - - - - - - - - - - - - - - - - - - - - - - + @@ -1344,62 +1323,56 @@ + + + + + + + + - - - - - + + + - - - - + + + + + + + + + - - + + + - - - - - - - - - - - - - - - - - - @@ -1408,14 +1381,13 @@ - + - - - - + + + @@ -1441,22 +1413,22 @@ - - + + - - + + - - + + @@ -1464,13 +1436,13 @@ - - - + + + - - + + @@ -1486,7 +1458,7 @@ - + @@ -1494,50 +1466,56 @@ - - - - + + + + - - + + + + + + - - + + + + - - + + - - - - + + + + - - - + - - + + + + @@ -1546,18 +1524,18 @@ - - + - + - - - + + + + @@ -1568,37 +1546,37 @@ - - - - - + + + + + - - - - + + + + - - - - - + + + + + @@ -1607,18 +1585,13 @@ - - - + + - - - - @@ -1634,10 +1607,11 @@ - - - - + + + + + @@ -1645,15 +1619,15 @@ - + - - + + @@ -1669,9 +1643,9 @@ - + - + @@ -1679,25 +1653,25 @@ - - - + + + - - + + - - - + + + - + @@ -1778,164 +1752,162 @@ - - - - + + + + - - + + - - + + - - + + - - + + - + - + - + - + - + - + - - - - + + + + - - + + - + + + - - - + + + + + - - + + - + + - - + - - - + + - + + - - + + + - + - + - - + - + - + + + - - + + + - - - - + + - - - - - - - - + @@ -1943,9 +1915,9 @@ - + - + @@ -2016,10 +1988,11 @@ - + + - + @@ -2069,21 +2042,21 @@ - - + + + - - - - - - - - - - + + + + + + + + + @@ -2096,16 +2069,16 @@ + - + + + + - - - - - - - + + + @@ -2113,57 +2086,57 @@ + + - - + + - - + + - - - - - + + + - + + - - - - - + + + + + + - - - - + + + + - - @@ -2171,14 +2144,19 @@ + - + + + + + @@ -2193,133 +2171,156 @@ - + + - - - + + - + - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + - - + + - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2329,7 +2330,7 @@ - + @@ -2344,11 +2345,10 @@ + - - - - + + @@ -2358,20 +2358,20 @@ + - + - + + - - - + @@ -2386,20 +2386,22 @@ + + - - - + + + - - - + + + + - - + diff --git a/pyproject.toml b/pyproject.toml index 1f5d52d..44e2c47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=40.8.0", "wheel", "PySide6", "torrentfile"] +requires = ["setuptools>=40.8.0", "wheel"] [project] name = "torrentfileQt" @@ -20,10 +20,10 @@ classifiers=[ "Programming Language :: Python :: 3.10", "License :: OSI Approved :: Apache Software License", ] -dependencies = ["torrentfile", "PySide6", "pyben"] +dependencies = ["torrentfile", "PySide6"] [project.scripts] -torrentfileqt = "torrentfileQt.window:start" +torrentfileqt = "torrentfileQt.__main__:main" [tools.setuptools] packages = ["torrentfileQt"] diff --git a/tests/__init__.py b/tests/__init__.py index 0ddb35d..cfc9bb4 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -30,9 +30,9 @@ import pytest from torrentfile.torrent import TorrentFile, TorrentFileHybrid, TorrentFileV2 -from torrentfileQt import alt_start +from torrentfileQt import Application -WINDOW, APP = alt_start() +APP = Application([]) def exception_hook(exctype, value, traceback): # pragma: no cover @@ -206,8 +206,7 @@ def wind(): `tuple` information to pass to test function. """ - window, app = WINDOW, APP - return window, app + return APP.window @pytest.fixture(params=[TorrentFile, TorrentFileHybrid, TorrentFileV2]) diff --git a/tests/test_checktab.py b/tests/test_checktab.py index c8c8bff..26bc7ef 100644 --- a/tests/test_checktab.py +++ b/tests/test_checktab.py @@ -21,6 +21,7 @@ import os from pathlib import Path +import PySide6 import pytest from tests import (MockQFileDialog, dir1, dir2, proc_time, rmpath, tempfile, @@ -36,9 +37,8 @@ def test_fixture(): def test_missing_files_check(dir2, ttorrent, wind): """Test missing files checker proceduire.""" - window, _ = wind - checktab = window.central.checkWidget - window.central.setCurrentWidget(checktab) + checktab = wind.central.checkWidget + wind.central.setCurrentWidget(checktab) dirpath = Path(dir2) for item in dirpath.iterdir(): if item.is_file(): @@ -52,10 +52,9 @@ def test_missing_files_check(dir2, ttorrent, wind): def test_shorter_files_check(wind, ttorrent, dir2): """Test missing files checker proceduire.""" - window, _ = wind - checktab = window.central.checkWidget + checktab = wind.central.checkWidget dirpath = Path(dir2) - window.central.setCurrentWidget(checktab) + wind.central.setCurrentWidget(checktab) def shortenfile(item): """Shave some data off the end of file.""" @@ -78,9 +77,8 @@ def shortenfile(item): def test_check_tab(wind, ttorrent, dir1): """Test checker procedure.""" - window, _ = wind - checktab = window.central.checkWidget - window.central.setCurrentWidget(checktab) + checktab = wind.central.checkWidget + wind.central.setCurrentWidget(checktab) checktab.fileInput.setText(ttorrent) checktab.searchInput.setText(dir1) checktab.checkButton.click() @@ -90,40 +88,36 @@ def test_check_tab(wind, ttorrent, dir1): def test_check_tab_input1(wind, dir1): """Test checker procedure.""" - window, _ = wind - checktab = window.central.checkWidget + checktab = wind.central.checkWidget MockQFileDialog.Out = dir1 - checkTab.QFileDialog = MockQFileDialog - window.central.setCurrentWidget(checktab) - checktab.browseButton2.browse_folders() + PySide6.QtWidgets.QFileDialog = MockQFileDialog + wind.central.setCurrentWidget(checktab) + checktab.browseButton2.browse_folders(dir1) assert checktab.searchInput.text() != "" def test_check_tab_input_2(wind, dir1): """Test checker procedure.""" - window, _ = wind - checktab = window.central.checkWidget + checktab = wind.central.checkWidget MockQFileDialog.Out = dir1 - checkTab.QFileDialog = MockQFileDialog - window.central.setCurrentWidget(checktab) - checktab.browseButton1.browse(dir1) + PySide6.QtWidgets.QFileDialog = MockQFileDialog + wind.central.setCurrentWidget(checktab) + checktab.browseButton1.browse((dir1, None)) assert checktab.fileInput.text() != "" def test_check_tab4(wind): """Test checker procedure again.""" - window, _ = wind - checktab = window.central.checkWidget - window.central.setCurrentWidget(checktab) + checktab = wind.central.checkWidget + wind.central.setCurrentWidget(checktab) tree_widget = checktab.treeWidget assert tree_widget.invisibleRootItem() is not None def test_clear_logtext(wind): """Test checker logTextEdit widget function.""" - window, _ = wind - checktab = window.central.checkWidget - window.central.setCurrentWidget(checktab) + checktab = wind.central.checkWidget + wind.central.setCurrentWidget(checktab) text_edit = checktab.textEdit text_edit.insertPlainText("sometext") text_edit.clear_data() @@ -132,9 +126,8 @@ def test_clear_logtext(wind): def test_checktab_tree(wind): """Check tree item counting functionality.""" - window, _ = wind - checktab = window.central.checkWidget - window.central.setCurrentWidget(checktab) + checktab = wind.central.checkWidget + wind.central.setCurrentWidget(checktab) tree = TreeWidget(parent=checktab) item = TreePieceItem(type=0, tree=tree) item.progbar = ProgressBar(parent=tree, size=1000000) @@ -148,10 +141,9 @@ def test_checktab_tree(wind): @pytest.mark.parametrize("ext", [".mkv", ".rar", ".r00", ".mp3"]) def test_singlefile(size, ext, index, version, wind): """Test the singlefile for create and check tabs.""" - window, _ = wind - createtab = window.central.createWidget - checktab = window.central.checkWidget - window.central.setCurrentWidget(checktab) + createtab = wind.central.createWidget + checktab = wind.central.checkWidget + wind.central.setCurrentWidget(checktab) testfile = str(tempfile(exp=size)) tfile = testfile + ext os.rename(testfile, tfile) @@ -159,7 +151,7 @@ def test_singlefile(size, ext, index, version, wind): metafile = tfile + ".torrent" createtab.path_input.clear() createtab.output_input.clear() - createtab.browse_file_button.browse(tfile) + createtab.browse_file_button.browse((tfile, None)) createtab.output_input.setText(metafile) createtab.piece_length.setCurrentIndex(index) proc_time() @@ -170,7 +162,7 @@ def test_singlefile(size, ext, index, version, wind): break createtab.submit_button.click() while proc_time(0.3): - if window.statusBar().currentMessage() != "Processing": + if wind.statusBar().currentMessage() != "Processing": break checktab.fileInput.clear() checktab.searchInput.clear() @@ -186,17 +178,16 @@ def test_singlefile(size, ext, index, version, wind): @pytest.mark.parametrize("version", [1, 2, 3]) def test_singlefile_large(version, wind): """Test the singlefile with large size for create and check tabs.""" - window, _ = wind - createtab = window.central.createWidget - checktab = window.central.checkWidget - window.central.setCurrentWidget(checktab) + createtab = wind.central.createWidget + checktab = wind.central.checkWidget + wind.central.setCurrentWidget(checktab) testfile = str(tempfile(exp=28)) tfile = testfile + ".dat" os.rename(testfile, tfile) metafile = tfile + ".torrent" createtab.path_input.clear() createtab.output_input.clear() - createtab.browse_file_button.browse(tfile) + createtab.browse_file_button.browse((tfile, None)) createtab.output_input.setText(metafile) btns = [createtab.v1button, createtab.v2button, createtab.hybridbutton] for i, btn in enumerate(btns): @@ -205,7 +196,7 @@ def test_singlefile_large(version, wind): break createtab.submit_button.click() while proc_time(0.3): - if window.statusBar().currentMessage() != "Processing": + if wind.statusBar().currentMessage() != "Processing": break checktab.fileInput.clear() checktab.searchInput.clear() diff --git a/tests/test_createTab.py b/tests/test_createTab.py index 675cd57..788f16d 100644 --- a/tests/test_createTab.py +++ b/tests/test_createTab.py @@ -38,9 +38,8 @@ def test_fixtures(): def test_create_with_hasher1(dir2, wind): """Test the radio buttons on create tab v1 hasher.""" - window, _ = wind metafile = dir2 + ".torrent" - creator = window.central.createWidget + creator = wind.central.createWidget creator.window.central.setCurrentWidget(creator) creator.path_input.clear() creator.path_input.setText(dir2) @@ -52,7 +51,7 @@ def test_create_with_hasher1(dir2, wind): creator.piece_length.setCurrentIndex(2) creator.submit_button.click() while proc_time(0.4): - if window.statusBar().currentMessage() != "Processing": + if wind.statusBar().currentMessage() != "Processing": break assert os.path.exists(metafile) rmpath(metafile) @@ -60,11 +59,10 @@ def test_create_with_hasher1(dir2, wind): def test_create_tab_browse(dir2, wind): """Test Info tab select1.""" - window, app = wind path = dir2 - createtab = window.central.createWidget + createtab = wind.central.createWidget createtab.window.central.setCurrentWidget(createtab) - app.processEvents() + proc_time() button = createtab.browse_file_button button.browse(path=path) createtab.comment_input.setText("Some Text") @@ -74,12 +72,11 @@ def test_create_tab_browse(dir2, wind): def test_create_tab_dir(dir2, wind): """Test create tab with folder.""" - window, _ = wind path = dir2 root = path - createtab = window.central.createWidget + createtab = wind.central.createWidget button = createtab.browse_dir_button - window.central.setCurrentWidget(createtab) + wind.central.setCurrentWidget(createtab) proc_time() button.browse(path=root) torfile = root + ".test.torrent" @@ -91,7 +88,7 @@ def test_create_tab_dir(dir2, wind): submit = createtab.submit_button submit.click() while proc_time(0.4): - if window.statusBar().currentMessage() != "Processing": + if wind.statusBar().currentMessage() != "Processing": break assert os.path.exists(torfile) rmpath(torfile) @@ -110,10 +107,9 @@ def test_create_tab_dir(dir2, wind): ) def test_create_tab_fields(dir2, field, wind): """Test create tab with folder.""" - window, _ = wind path = dir2 root = path - createtab = window.central.createWidget + createtab = wind.central.createWidget button = createtab.browse_dir_button button.browse(path=root) createtab.window.central.setCurrentWidget(createtab) @@ -131,7 +127,7 @@ def test_create_tab_fields(dir2, field, wind): submit.click() proc_time(0.5) while proc_time(0.3): - if window.statusBar().currentMessage() != "Processing": + if wind.statusBar().currentMessage() != "Processing": break result = pyben.load(torfile) assert field in result or field in result["info"] @@ -140,10 +136,10 @@ def test_create_tab_fields(dir2, field, wind): def test_sized_create(wind): """Test browse file button on create tab.""" - window, _ = wind path = str(tempfile(exp=28)) - createtab = window.central.createWidget + createtab = wind.central.createWidget button = createtab.browse_file_button - button.browse(path=path) + param = (path, None) + button.browse(param) proc_time() assert createtab.path_input.text() == path diff --git a/tests/test_edittab.py b/tests/test_edittab.py index 6486f1b..c22c721 100644 --- a/tests/test_edittab.py +++ b/tests/test_edittab.py @@ -32,10 +32,10 @@ def test_fixtures(): @pytest.mark.parametrize("field", ["announce", "name", "private", "comment"]) def test_editor_torrent_loading(field, wind, ttorrent): """Testing editor widget functionality.""" - window, _ = wind - editor = window.central.editorWidget + editor = wind.central.editorWidget editor.window.central.setCurrentWidget(editor) - editor.fileButton.browse(ttorrent) + param = (ttorrent, None) + editor.fileButton.browse(param) proc_time() fields = [] for i in range(editor.table.rowCount()): @@ -45,11 +45,11 @@ def test_editor_torrent_loading(field, wind, ttorrent): def test_editor_torrent_saving(wind, ttorrent): """Testing editor widget saving functionality.""" - window, _ = wind - editor = window.central.editorWidget + editor = wind.central.editorWidget editor.window.central.setCurrentWidget(editor) proc_time() - editor.fileButton.browse(ttorrent) + param = ttorrent, None + editor.fileButton.browse(param) for i in range(editor.table.rowCount()): item1 = editor.table.item(i, 0) item2 = editor.table.item(i, 1) @@ -64,8 +64,7 @@ def test_editor_torrent_saving(wind, ttorrent): def test_editor_accept_method(wind, ttorrent): """Test drag enter event on editor widget.""" - window, _ = wind - editor = window.central.editorWidget + editor = wind.central.editorWidget editor.window.central.setCurrentWidget(editor) proc_time() event = MockEvent(ttorrent) @@ -76,8 +75,7 @@ def test_editor_accept_method(wind, ttorrent): def test_editor_move_event(wind, ttorrent): """Test move event on editor widget.""" - window, _ = wind - editor = window.central.editorWidget + editor = wind.central.editorWidget editor.window.central.setCurrentWidget(editor) proc_time() event = MockEvent(ttorrent) @@ -88,8 +86,7 @@ def test_editor_move_event(wind, ttorrent): def test_editor_drop_event(wind, ttorrent): """Test drop event on editor widget.""" - window, _ = wind - editor = window.central.editorWidget + editor = wind.central.editorWidget editor.window.central.setCurrentWidget(editor) proc_time() event = MockEvent(ttorrent) @@ -98,8 +95,7 @@ def test_editor_drop_event(wind, ttorrent): def test_editor_drop_false(wind): """Test drop event on editor widget is false.""" - window, _ = wind - editor = window.central.editorWidget + editor = wind.central.editorWidget editor.window.central.setCurrentWidget(editor) proc_time() event = MockEvent(None) @@ -108,8 +104,7 @@ def test_editor_drop_false(wind): def test_editor_table_fields(wind, ttorrent): """Test the edit fields of table widget.""" - window, _ = wind - editor = window.central.editorWidget + editor = wind.central.editorWidget editor.window.central.setCurrentWidget(editor) proc_time() table, found = editor.table, 0 diff --git a/tests/test_gui.py b/tests/test_gui.py index 9aab6bb..058b726 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -17,19 +17,16 @@ # limitations under the License. ############################################################################## """Testing module for most of GUI.""" -from PySide6.QtWidgets import QApplication, QMainWindow +from PySide6.QtWidgets import QMainWindow from tests import wind from torrentfileQt import qss +from torrentfileQt.__main__ import main from torrentfileQt.infoTab import denom +from torrentfileQt.utils import StyleManager from torrentfileQt.window import TabWidget -def test_wind(): - """Test wind fixture.""" - assert wind - - def test_denom(): """Test denom function.""" num = denom(50000000000) @@ -40,30 +37,13 @@ def test_denom_small(): """Test denom function for small number.""" num = denom(357) assert num == "357" + assert wind + assert main -def test_window1(wind): - """Test Main Window Functionality.""" - window, _ = wind - assert window is not None - - -def test_window2(wind): - """Test Window Functionality.""" - window, _ = wind - assert isinstance(window, QMainWindow) - - -def test_app1(wind): +def test_wind(wind): """Test app subclass.""" - _, app = wind - assert isinstance(app, QApplication) - - -def test_app2(wind): - """Test app subclass instance attribute.""" - window, app = wind - assert app is window.app + assert isinstance(wind, QMainWindow) def test_qss(): @@ -73,12 +53,86 @@ def test_qss(): def test_window_menubar1(wind): """Test window Menubar widget.""" - window, _ = wind - assert window.menubar is not None + assert wind.menubar is not None def test_tab_widget(wind): """Test window Tab widget.""" - window, _ = wind - tabwidget = window.central + tabwidget = wind.central assert isinstance(tabwidget, TabWidget) + + +def test_change_theme(wind): + """Test changing the theme from the menubar.""" + wind.menubar.file_menu.actionLightTheme.trigger() + wind.menubar.file_menu.actionDarkTheme.trigger() + assert wind.menubar.file_menu.actionLightTheme.text() == "Light Theme" + assert wind.menubar.file_menu.actionDarkTheme.text() == "Dark Theme" + + +def test_increase_font(wind): + """Test font size plus menu option.""" + fontsize = wind.central.createWidget.path_label.font().pointSize() + wind.menubar.file_menu.actionFontPlus.trigger() + wind.menubar.file_menu.actionFontPlus.trigger() + assert wind.central.createWidget.path_label.font().pointSize() > fontsize + + +def test_decrease_font(wind): + """Test font size minus menu option.""" + fontsize = wind.central.createWidget.path_label.font().pointSize() + wind.menubar.file_menu.actionFontMinus.trigger() + wind.menubar.file_menu.actionFontMinus.trigger() + assert wind.central.createWidget.path_label.font().pointSize() < fontsize + + +def test_styleManager(): + """Test style manager from utils module.""" + themes = { + "test": + """ +QWidget { + background-color: #000; + color: #0AF; + border-color: #F71; + border-width: 3px; + border-style: outset; + border-radius: 8px; +} +QLineEdit, +QLabel { + font-size: 15pt; + + +} +/* this is a comment*/ + + +QCheckBox::indicator { + background-color: red; + margin: ; +} + +/* this is a longer +comment that spans two lines */ + +QPushButton:pressed { + border-width: + 3px; + border-style: + solid; + border-color: + #F71; +} + +QPushButton:hover {color: #080;} +/* some comment +*/ +QComboBox { + border: 12px solid pink; +}""" + } + manager = StyleManager(themes) + manager.current = themes["test"] + collection = manager.parser.parse(themes["test"]) + assert len(collection) > 1 diff --git a/tests/test_infotab.py b/tests/test_infotab.py index 2db6cbf..d5414da 100644 --- a/tests/test_infotab.py +++ b/tests/test_infotab.py @@ -21,7 +21,8 @@ import pytest from torrentfile.torrent import TorrentFile, TorrentFileHybrid, TorrentFileV2 -from tests import MockEvent, dir2, dir3, rmpath, tempfile, ttorrent, wind +from tests import (MockEvent, dir2, dir3, proc_time, rmpath, tempfile, + ttorrent, wind) def test_fixture(): @@ -31,10 +32,9 @@ def test_fixture(): def test_info_tab_select1(wind, ttorrent): """Test Info tab select1.""" - window, app = wind - infotab = window.central.infoWidget - app.processEvents() - window.central.setCurrentWidget(infotab) + infotab = wind.central.infoWidget + proc_time() + wind.central.setCurrentWidget(infotab) button = infotab.selectButton button.selectTorrent(path=ttorrent) assert infotab.nameEdit.text() != "" @@ -44,20 +44,19 @@ def test_info_tab_select1(wind, ttorrent): [TorrentFile, TorrentFileV2, TorrentFileHybrid]) def test_infotab_select2(wind, dir2, creator): """Test getting info for single file torrent.""" - window, app = wind torrent = creator(path=dir2) del torrent.meta["created by"] del torrent.meta["creation date"] del torrent.meta["announce-list"] outfile, _ = torrent.write() - infotab = window.central.infoWidget - app.processEvents() - window.central.setCurrentWidget(infotab) + infotab = wind.central.infoWidget + proc_time() + wind.central.setCurrentWidget(infotab) button = infotab.selectButton button.selectTorrent(path=outfile) name = torrent.meta["info"]["name"] assert infotab.nameEdit.text() == name - rmpath(outfile) + rmpath(outfile, dir2) @pytest.mark.parametrize("creator", @@ -65,36 +64,34 @@ def test_infotab_select2(wind, dir2, creator): @pytest.mark.parametrize("size", list(range(16, 22))) def test_infotab_single(wind, creator, size): """Test getting info for single file torrent.""" - window, app = wind tfile = tempfile(exp=size) torrent = creator(path=tfile) del torrent.meta["created by"] del torrent.meta["creation date"] del torrent.meta["announce-list"] outfile, _ = torrent.write() - infotab = window.central.infoWidget - app.processEvents() - window.central.setCurrentWidget(infotab) + infotab = wind.central.infoWidget + proc_time() + wind.central.setCurrentWidget(infotab) button = infotab.selectButton button.selectTorrent(path=outfile) name = torrent.meta["info"]["name"] assert infotab.nameEdit.text() == name - rmpath(outfile) + rmpath(outfile, tfile) @pytest.mark.parametrize("creator", [TorrentFile, TorrentFileV2, TorrentFileHybrid]) def test_infotab_nested(wind, creator, dir3): """Test getting info for single file torrent.""" - window, app = wind torrent = creator(path=dir3) del torrent.meta["created by"] del torrent.meta["creation date"] del torrent.meta["announce-list"] outfile, _ = torrent.write() - infotab = window.central.infoWidget - app.processEvents() - window.central.setCurrentWidget(infotab) + infotab = wind.central.infoWidget + proc_time() + wind.central.setCurrentWidget(infotab) button = infotab.selectButton button.selectTorrent(path=outfile) name = torrent.meta["info"]["name"] @@ -104,10 +101,9 @@ def test_infotab_nested(wind, creator, dir3): def test_info_accept_method(wind, ttorrent): """Test drag enter event on info widget.""" - window, app = wind - info = window.central.infoWidget + info = wind.central.infoWidget info.window.central.setCurrentWidget(info) - app.processEvents() + proc_time() event = MockEvent(ttorrent) assert info.dragEnterEvent(event) event = MockEvent(None) @@ -116,10 +112,9 @@ def test_info_accept_method(wind, ttorrent): def test_info_move_event(wind, ttorrent): """Test move event on info widget.""" - window, app = wind - info = window.central.infoWidget + info = wind.central.infoWidget info.window.central.setCurrentWidget(info) - app.processEvents() + proc_time() event = MockEvent(ttorrent) assert info.dragMoveEvent(event) event = MockEvent(None) @@ -128,19 +123,17 @@ def test_info_move_event(wind, ttorrent): def test_info_drop_event(wind, ttorrent): """Test drop event on editor widget.""" - window, app = wind - info = window.central.infoWidget + info = wind.central.infoWidget info.window.central.setCurrentWidget(info) - app.processEvents() + proc_time() event = MockEvent(ttorrent) assert info.dropEvent(event) def test_info_drop_false(wind): """Test drop event on editor widget is false.""" - window, app = wind - info = window.central.infoWidget + info = wind.central.infoWidget info.window.central.setCurrentWidget(info) - app.processEvents() + proc_time() event = MockEvent(None) assert not info.dropEvent(event) diff --git a/tests/test_magnettab.py b/tests/test_magnettab.py index 64ae0d7..f89ce08 100644 --- a/tests/test_magnettab.py +++ b/tests/test_magnettab.py @@ -49,10 +49,9 @@ def test_fixture(): def test_create_magnet(wind, torrent): """Test creating Magnet URI from a torrent file path.""" - window, _ = wind outfile, _ = torrent - tab = window.central.magnetWidget - window.central.setCurrentWidget(tab) + tab = wind.central.magnetWidget + wind.central.setCurrentWidget(tab) tab.metafile_input.setText(str(outfile)) tab.submit_button.click() out = tab.output.text() @@ -62,11 +61,10 @@ def test_create_magnet(wind, torrent): def test_create_magnet_method(wind, torrent): """Test creating Magnet URI from a torrent file path.""" - window, _ = wind outfile, _ = torrent - tab = window.central.magnetWidget - window.central.setCurrentWidget(tab) - tab.file_button.select_metafile(name=outfile) + tab = wind.central.magnetWidget + wind.central.setCurrentWidget(tab) + tab.file_button.select_metafile(outfile) tab.submit_button.magnet() out = tab.output.text() proc_time() @@ -75,10 +73,9 @@ def test_create_magnet_method(wind, torrent): def test_magnet_accept_method(wind, ttorrent): """Test drag enter event on editor widget.""" - window, app = wind - magnet = window.central.magnetWidget + magnet = wind.central.magnetWidget magnet.window.central.setCurrentWidget(magnet) - app.processEvents() + proc_time() event = MockEvent(ttorrent) assert magnet.dragEnterEvent(event) event = MockEvent(None) @@ -87,10 +84,9 @@ def test_magnet_accept_method(wind, ttorrent): def test_magnet_move_event(wind, ttorrent): """Test move event on magnet widget.""" - window, app = wind - magnet = window.central.magnetWidget + magnet = wind.central.magnetWidget magnet.window.central.setCurrentWidget(magnet) - app.processEvents() + proc_time() event = MockEvent(ttorrent) assert magnet.dragMoveEvent(event) event = MockEvent(None) @@ -99,19 +95,17 @@ def test_magnet_move_event(wind, ttorrent): def test_magnet_drop_event(wind, ttorrent): """Test drop event on editor widget.""" - window, app = wind - magnet = window.central.magnetWidget + magnet = wind.central.magnetWidget magnet.window.central.setCurrentWidget(magnet) - app.processEvents() + proc_time() event = MockEvent(ttorrent) assert magnet.dropEvent(event) def test_magnet_drop_false(wind): """Test drop event on editor widget returns None.""" - window, app = wind - magnet = window.central.magnetWidget + magnet = wind.central.magnetWidget magnet.window.central.setCurrentWidget(magnet) - app.processEvents() + proc_time() event = MockEvent(None) assert not magnet.dropEvent(event) diff --git a/tests/test_menu.py b/tests/test_menu.py index b0f73b8..21769ee 100644 --- a/tests/test_menu.py +++ b/tests/test_menu.py @@ -52,12 +52,11 @@ def profiles(request): @pytest.fixture def menubar_profiles(wind, profiles): """Pytest fixture for menubar profiles.""" - window, _ = wind - menubar = window.menubar + menubar = wind.menubar menu = menubar.profile_menu menu.home, menu.profiles = profiles menu.add_profile_actions() - return menu, window, profiles + return menu, wind, profiles def test_wind(): @@ -73,19 +72,19 @@ def test_menubar_profiles(menubar_profiles): def test_menubar_profiles_actions(menubar_profiles): """Test menubar profiles actions.""" - menu, window, profiles = menubar_profiles + menu, wind, profiles = menubar_profiles _, profile = profiles profs = json.load(open(profile)) action = [i for i in menu.profile_actions if i.name == "example"][0] action.action.trigger() - tab = window.central.createWidget + tab = wind.central.createWidget assert tab.source_input.text() == profs["example"]["source"] def test_add_profile_with_profiles(menubar_profiles): """Test adding a profile.""" - menu, window, profiles = menubar_profiles - tab = window.central.createWidget + menu, wind, profiles = menubar_profiles + tab = wind.central.createWidget tab.source_input.setText("SOURCE") tab.announce_input.setPlainText("https://announce.net") menu.add_profile(name="test") @@ -96,9 +95,9 @@ def test_add_profile_with_profiles(menubar_profiles): def test_add_profile_meta_v2(menubar_profiles): """Test adding a profile with other meta versions.""" - menu, window, profiles = menubar_profiles - window.menubar.file_menu.light_theme() - tab = window.central.createWidget + menu, wind, profiles = menubar_profiles + wind.menubar.file_menu.light_theme() + tab = wind.central.createWidget tab.v2button.click() tab.source_input.setText("SOURCE") tab.private.click() @@ -111,10 +110,10 @@ def test_add_profile_meta_v2(menubar_profiles): def test_add_profile_meta_hybrid(menubar_profiles): """Test adding a profile with other meta versions.""" - menu, window, profiles = menubar_profiles - tab = window.central.createWidget + menu, wind, profiles = menubar_profiles + tab = wind.central.createWidget tab.v1button.click() - window.menubar.file_menu.light_theme() + wind.menubar.file_menu.light_theme() tab.source_input.setText("SOURCE") tab.announce_input.setPlainText("https://announce.net") menu.add_profile(name="test2") @@ -125,17 +124,16 @@ def test_add_profile_meta_hybrid(menubar_profiles): def test_add_profile_without_profiles(wind): """Test adding a profile.""" - window, _ = wind - path = window.menubar.profile_menu.home + path = wind.menubar.profile_menu.home alt = Path(__file__).parent / "alt" - if os.path.exists(window.menubar.profile_menu.home): + if os.path.exists(wind.menubar.profile_menu.home): os.rename(path, alt) # pragma: nocover - tab = window.central.createWidget + tab = wind.central.createWidget tab.source_input.setText("SOURCE") tab.announce_input.setPlainText("https://announce.net") - window.menubar.profile_menu.add_profile(name="test") - window.menubar.file_menu.dark_theme() - profiles = window.menubar.profile_menu.profiles + wind.menubar.profile_menu.add_profile(name="test") + wind.menubar.file_menu.dark_theme() + profiles = wind.menubar.profile_menu.profiles profs = json.load(open(profiles)) assert "test" in profs rmpath(path) diff --git a/torrentfileQt/__init__.py b/torrentfileQt/__init__.py index ec0917f..7297e8e 100644 --- a/torrentfileQt/__init__.py +++ b/torrentfileQt/__init__.py @@ -22,7 +22,7 @@ import sys from torrentfileQt.version import __version__ -from torrentfileQt.window import Application, Window, alt_start, start +from torrentfileQt.window import Application, Window, execute myappid = f"TorrentfileQt.{__version__}" if sys.platform == "win32": @@ -32,7 +32,6 @@ __all__ = [ "Application", "Window", - "alt_start", - "start", + "execute", "__version__", ] diff --git a/torrentfileQt/__main__.py b/torrentfileQt/__main__.py new file mode 100644 index 0000000..8913bd0 --- /dev/null +++ b/torrentfileQt/__main__.py @@ -0,0 +1,30 @@ +#! /usr/bin/python3 +# -*- coding: utf-8 -*- + +############################################################################## +# Copyright 2020 AlexPDev +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################## +"""Entry point for torrentfileQt.""" + +from torrentfileQt import execute + + +def main(): + """Execute main program.""" + execute() # pragma: nocover + + +if __name__ == "__main__": + main() # pragma: nocover diff --git a/torrentfileQt/checkTab.py b/torrentfileQt/checkTab.py index fab4a07..4d7fc7e 100644 --- a/torrentfileQt/checkTab.py +++ b/torrentfileQt/checkTab.py @@ -25,13 +25,14 @@ from PySide6.QtCore import Qt, Signal from PySide6.QtGui import QIcon, QTextOption -from PySide6.QtWidgets import (QFileDialog, QFormLayout, QHBoxLayout, QLabel, - QLineEdit, QPlainTextEdit, QProgressBar, - QPushButton, QSplitter, QTreeWidget, - QTreeWidgetItem, QVBoxLayout, QWidget) +from PySide6.QtWidgets import (QFormLayout, QHBoxLayout, QLabel, QLineEdit, + QPlainTextEdit, QProgressBar, QPushButton, + QSplitter, QTreeWidget, QTreeWidgetItem, + QVBoxLayout, QWidget) from torrentfile.recheck import Checker -from torrentfileQt.utils import get_icon +from torrentfileQt.utils import (browse_files, browse_folder, browse_torrent, + get_icon) class CheckWidget(QWidget): @@ -163,15 +164,9 @@ def browse(self, path=None): path : str Path to file or folder to include in torrent. """ - caption = "Choose .torrent file." - if not path: # pragma: no cover - path, _ = QFileDialog.getOpenFileName(parent=self, - caption=caption, - filter="*.torrent") - if path: - path = os.path.normpath(path) - self.parent().fileInput.clear() - self.parent().fileInput.setText(path) + path = browse_torrent(self, path) + self.parent().fileInput.clear() + self.parent().fileInput.setText(path) class BrowseFolders(QPushButton): @@ -195,24 +190,13 @@ def __init__(self, parent=None): self.setCursor(Qt.CursorShape.PointingHandCursor) self.clicked.connect(self.browse_folders) - def browse_folders(self): + def browse_folders(self, path=None): """ Browse Action performed when user presses button. - - Returns - ------- - str : - Path to file or folder to include in torrent. """ - path = QFileDialog.getExistingDirectory( - parent=self, - dir=str(Path.home()), - caption="Select Contents Folder...", - ) - if path: - path = os.path.normpath(path) - self.widget.searchInput.clear() - self.widget.searchInput.setText(path) + path = browse_folder(self, path) + self.widget.searchInput.clear() + self.widget.searchInput.setText(path) class BrowseFiles(QPushButton): @@ -232,21 +216,10 @@ def __init__(self, parent=None): def browse_files(self, path=None): """ Browse Action performed when user presses button. - - Returns - ------- - str : - Path to file or folder to include in torrent. """ - out = QFileDialog.getOpenFileName( - parent=self, - dir=str(Path.home()), - caption="Select Contents File...", - ) - if out and out[0]: - path = os.path.normpath(out[0]) - self.widget.searchInput.clear() - self.widget.searchInput.setText(path) + path = browse_files(self, path) + self.widget.searchInput.clear() + self.widget.searchInput.setText(path) class LogTextEdit(QPlainTextEdit): diff --git a/torrentfileQt/createTab.py b/torrentfileQt/createTab.py index 0e6c5d3..d7d20dc 100644 --- a/torrentfileQt/createTab.py +++ b/torrentfileQt/createTab.py @@ -34,7 +34,7 @@ from torrentfile.torrent import TorrentFile, TorrentFileHybrid, TorrentFileV2 from torrentfile.utils import path_piece_length -from torrentfileQt.utils import get_icon +from torrentfileQt.utils import browse_files, browse_folder, get_icon class CreateWidget(QWidget): @@ -333,32 +333,21 @@ def browse(self, path=None): Browse performed when user presses button. Opens File/Folder Dialog. - - Returns - ------- - str : - Path to file or folder to include in torrent. """ - caption = "Select file..." - if not path: # pragma: no cover - path, _ = QFileDialog.getOpenFileName(parent=self, - caption=caption, - dir=str(Path.home())) - if path != "": - path = os.path.normpath(path) - self.window.path_input.clear() - self.window.output_input.clear() - self.window.path_input.setText(path) - self.window.output_input.setText(path + ".torrent") - piece_length = path_piece_length(path) - if piece_length < (2**20): - val = f"{piece_length//(2**10)} KiB" - else: - val = f"{piece_length//(2**20)} MiB" - for i in range(self.window.piece_length.count()): - if self.window.piece_length.itemText(i) == val: - self.window.piece_length.setCurrentIndex(i) - break + path = browse_files(self, path) + self.window.path_input.clear() + self.window.output_input.clear() + self.window.path_input.setText(path) + self.window.output_input.setText(path + ".torrent") + piece_length = path_piece_length(path) + if piece_length < (2**20): + val = f"{piece_length//(2**10)} KiB" + else: + val = f"{piece_length//(2**20)} MiB" + for i in range(self.window.piece_length.count()): + if self.window.piece_length.itemText(i) == val: + self.window.piece_length.setCurrentIndex(i) + break class BrowseDirButton(QPushButton): @@ -379,36 +368,21 @@ def browse(self, path=None): Browse action performed when user presses button. Opens File/Folder Dialog. - - Returns - ------- - str : - Path to file or folder to include in torrent. """ - caption = "Select contents folder..." - if not path: # pragma: no cover - path = QFileDialog.getExistingDirectory(parent=self, - caption=caption, - dir=str(Path.home())) - if path: - path = os.path.realpath(path) - self.window.path_input.clear() - self.window.output_input.clear() - self.window.path_input.setText(path) - self.window.output_input.insert(path + ".torrent") - try: - piece_length = path_piece_length(path) - except PermissionError: # pragma: no cover - return - if piece_length < (2**20): - val = f"{piece_length//(2**10)} KiB" - else: # pragma: no cover - val = f"{piece_length//(2**20)} MiB" - for i in range(self.window.piece_length.count()): - if self.window.piece_length.itemText(i) == val: - self.window.piece_length.setCurrentIndex(i) - break - return + path = browse_folder(self, path) + self.window.path_input.clear() + self.window.output_input.clear() + self.window.path_input.setText(path) + self.window.output_input.insert(path + ".torrent") + piece_length = path_piece_length(path) + if piece_length < (2**20): + val = f"{piece_length//(2**10)} KiB" + else: # pragma: no cover + val = f"{piece_length//(2**20)} MiB" + for i in range(self.window.piece_length.count()): + if self.window.piece_length.itemText(i) == val: + self.window.piece_length.setCurrentIndex(i) + break class ComboBox(QComboBox): diff --git a/torrentfileQt/editorTab.py b/torrentfileQt/editorTab.py index cb6496f..96b2061 100644 --- a/torrentfileQt/editorTab.py +++ b/torrentfileQt/editorTab.py @@ -20,15 +20,16 @@ import os from copy import deepcopy -from pathlib import Path import pyben from PySide6.QtCore import Qt, Signal from PySide6.QtGui import QAction -from PySide6.QtWidgets import (QComboBox, QFileDialog, QHBoxLayout, QLabel, - QLineEdit, QPushButton, QSizePolicy, - QTableWidget, QTableWidgetItem, QToolBar, - QToolButton, QVBoxLayout, QWidget) +from PySide6.QtWidgets import (QComboBox, QHBoxLayout, QLabel, QLineEdit, + QPushButton, QSizePolicy, QTableWidget, + QTableWidgetItem, QToolBar, QToolButton, + QVBoxLayout, QWidget) + +from torrentfileQt.utils import browse_torrent class EditorWidget(QWidget): @@ -153,16 +154,10 @@ def __init__(self, parent=None): def browse(self, path: str = None): """Browse method for finding the .torrent file user wishes to edit.""" - if not path: # pragma: no coverage - path, _ = QFileDialog.getOpenFileName( - dir=str(Path.home()), - caption="Select Torrent File", - filter="*.torrent", - ) - if path: - self.widget.table.clear() - self.widget.line.setText(path) - self.widget.table.handleTorrent.emit(path) + path = browse_torrent(self, path) + self.widget.table.clear() + self.widget.line.setText(path) + self.widget.table.handleTorrent.emit(path) class AddItemButton(QAction): diff --git a/torrentfileQt/infoTab.py b/torrentfileQt/infoTab.py index c6de7d9..837400e 100644 --- a/torrentfileQt/infoTab.py +++ b/torrentfileQt/infoTab.py @@ -27,11 +27,10 @@ import pyben from PySide6.QtCore import Qt, Signal from PySide6.QtGui import QIcon -from PySide6.QtWidgets import (QFileDialog, QGridLayout, QLabel, QLineEdit, - QPushButton, QTreeWidget, QTreeWidgetItem, - QWidget) +from PySide6.QtWidgets import (QGridLayout, QLabel, QLineEdit, QPushButton, + QTreeWidget, QTreeWidgetItem, QWidget) -from torrentfileQt.utils import get_icon +from torrentfileQt.utils import browse_torrent, get_icon class TreeWidget(QTreeWidget): @@ -332,17 +331,9 @@ def __init__(self, text, parent=None): def selectTorrent(self, path=None): """Collect torrent information and send to the screen for display.""" - fullpath = path - if not fullpath: # pragma: no cover - fullpath, _ = QFileDialog.getOpenFileName( - parent=self, - caption="Please Select '.torrent' File", - dir=str(Path.home()), - filter="*.torrent", - ) - if fullpath: - kws = format_data(fullpath) - self.parent().fill(**kws) + path = browse_torrent(self, path) + kws = format_data(path) + self.parent().fill(**kws) class Label(QLabel): diff --git a/torrentfileQt/magnetTab.py b/torrentfileQt/magnetTab.py index 132197f..322310b 100644 --- a/torrentfileQt/magnetTab.py +++ b/torrentfileQt/magnetTab.py @@ -19,14 +19,14 @@ """Magnet Widget containing Testing creation of Magnet URIs.""" import os -from pathlib import Path from PySide6.QtCore import Qt -from PySide6.QtWidgets import (QFileDialog, QHBoxLayout, QLabel, QLineEdit, - QPushButton, QSpacerItem, QToolButton, - QVBoxLayout, QWidget) +from PySide6.QtWidgets import (QHBoxLayout, QLabel, QLineEdit, QPushButton, + QSpacerItem, QToolButton, QVBoxLayout, QWidget) from torrentfile import magnet +from torrentfileQt.utils import browse_torrent + class MagnetWidget(QWidget): """Tab for creating magnet URL's and downloading torrentfiles from them.""" @@ -125,14 +125,7 @@ def __init__(self, parent=None): self.setCursor(Qt.CursorShape.PointingHandCursor) self.pressed.connect(self.select_metafile) - def select_metafile(self, name=None): + def select_metafile(self, path=None): """Find metafile in file browser.""" - if not name: # pragma: nocover - name, _ = QFileDialog.getOpenFileName( - parent=self, - caption="Select '.torrent' file", - dir=str(Path.home()), - filter="*.torrent", - selectedFilter=None, - ) - self.widget.metafile_input.setText(name) + path = browse_torrent(self, path) + self.widget.metafile_input.setText(path) diff --git a/torrentfileQt/menu.py b/torrentfileQt/menu.py index da1f794..6e560ae 100644 --- a/torrentfileQt/menu.py +++ b/torrentfileQt/menu.py @@ -23,7 +23,7 @@ import webbrowser from PySide6.QtGui import QAction -from PySide6.QtWidgets import QApplication, QInputDialog, QMenu, QMenuBar +from PySide6.QtWidgets import QInputDialog, QMenu, QMenuBar class MenuBar(QMenuBar): @@ -31,7 +31,7 @@ class MenuBar(QMenuBar): def __init__(self, parent=None): """ - Construct for top level widgets. + Construct top level widgets. Parameters ---------- @@ -53,7 +53,7 @@ class FileMenu(QMenu): def __init__(self, title, parent): """ - Construct for top level widgets. + Construct top level widgets. Parameters ---------- @@ -75,8 +75,8 @@ def __init__(self, title, parent): self.addAction(self.actionFontMinus) self.addAction(self.actionLightTheme) self.addAction(self.actionDarkTheme) - self.actionFontPlus.setText("Font +") - self.actionFontMinus.setText("Font -") + self.actionFontPlus.setText("Font Size +") + self.actionFontMinus.setText("Font Size -") self.actionDarkTheme.setText("Dark Theme") self.actionLightTheme.setText("Light Theme") self.actionExit.setText("Exit") @@ -93,27 +93,28 @@ def __init__(self, title, parent): def exit_app(self): """Close application.""" - self.parent().app.quit() # pragma: nocover + app = self.parent().window.app + app.quit() # pragma: nocover - @staticmethod - def light_theme(): + def light_theme(self): """Change the GUI theme for the application.""" - QApplication.instance().styleManager.setTheme("light") + app = self.parent().window.app + app.styleManager.set_theme_from_title("light_theme") - @staticmethod - def dark_theme(): + def dark_theme(self): """Change the GUI application to dark theme.""" - QApplication.instance().styleManager.setTheme("dark") + app = self.parent().window.app + app.styleManager.set_theme_from_title("dark_theme") - @staticmethod - def increaseFont(): + def increaseFont(self): """Increase Font Size for all widgets with text.""" - QApplication.instance().styleManager.increase_font_size() + app = self.parent().window.app + app.styleManager.increase_font_size() - @staticmethod - def decreaseFont(): + def decreaseFont(self): """Decrease font size for all widgets with text.""" - QApplication.instance().styleManager.decrease_font_size() + app = self.parent().window.app + app.styleManager.decrease_font_size() class HelpMenu(QMenu): diff --git a/torrentfileQt/utils.py b/torrentfileQt/utils.py index 366916d..83a2002 100644 --- a/torrentfileQt/utils.py +++ b/torrentfileQt/utils.py @@ -20,35 +20,63 @@ import os from copy import deepcopy +from pathlib import Path +from PySide6.QtCore import QObject, Signal +from PySide6.QtWidgets import QFileDialog -class StyleManager: + +class StyleManager(QObject): """Manage QStyleSheets for the app.""" - def __init__(self, themes, current, parent): + themeRequest = Signal([str]) + + def __init__(self, themes): """Initialize styleManager class.""" + super().__init__() self.themes = themes - self.current = current - self.app = parent self.parser = QssParser() - self.setTheme("light") + self.current = None + + def setTheme(self, theme): + """ + Set the current QStyleSheet theme. + + Parameters + ---------- + theme : str + the qss formating string to apply as the theme. + """ + self.themeRequest.emit(theme) + + def set_theme_from_title(self, title): + """ + Set the theme from it's key in the theme dict. - def setTheme(self, title): - """Set the current QStyleSheet theme.""" - self.app.apply_theme(self.themes[title]) + Parameters + ---------- + title : str + The key corresponding the the theme in the dict. + """ + theme = self.themes[title] + self.setTheme(theme) - def _create_ssheet(self, sheets=None) -> dict: + @staticmethod + def _create_ssheet(sheets: list) -> str: """ Update the sheet with data from table. + Parameters + ---------- + sheets : list + list of all of the styles for a theme + Returns ------- dict the changed sheet """ ssheet = "" - if not sheets: - sheets = self.sheets for row in sheets: for k, v in row.items(): if not k or not v: @@ -85,7 +113,7 @@ def _adjust_font(self, amount): if 24 > number + amount > 0: value["font-size"] = f"{number + amount}pt" theme = self._create_ssheet(widgets) - self.app.apply_theme(theme) + self.themeRequest.emit(theme) class QssParser: @@ -237,3 +265,73 @@ def get_icon(name): assets = os.path.join(parent, "assets") path = os.path.join(assets, name + ".png") return path + + +def browse_folder(widget, folder=None): + """ + Browse for folder performed when user presses button. + + Parameters + ---------- + widget : QWidget + The widget making the call. + folder : str + Optional testing path + """ + if not folder: + folder = QFileDialog.getExistingDirectory( # pragma: nocover + parent=widget, + dir=str(Path.home()), + caption="Select Contents Folder...", + ) + if folder: + folder = os.path.normpath(folder) + return folder + + +def browse_files(widget, path=None): + """ + Browse for files action performed when user presses button. + + Parameters + ---------- + widget : QWidget + The widget making the call. + path : str + Optional testing path + """ + if not path: + path = QFileDialog.getOpenFileName( # pragma: nocover + parent=widget, + dir=str(Path.home()), + caption="Select Contents File...", + ) + if isinstance(path, str): + path = (path, None) + if path and path[0]: + path = os.path.normpath(path[0]) + return path + + +def browse_torrent(widget, torrent=None): + """ + Browse for torrent file performed when user presses button. + + Parameters + ---------- + widget : QWidget + The widget making the call. + torrent : str + Optional testing path. + """ + if not torrent: + torrent = QFileDialog.getOpenFileName( # pragma: nocover + parent=widget, + dir=str(Path.home()), + caption="Select *.torrent File...", + ) + if isinstance(torrent, str): + torrent = torrent, None + if torrent and torrent[0]: + torrent = os.path.normpath(torrent[0]) + return torrent diff --git a/torrentfileQt/window.py b/torrentfileQt/window.py index 2a200d1..42a328f 100644 --- a/torrentfileQt/window.py +++ b/torrentfileQt/window.py @@ -33,6 +33,9 @@ from torrentfileQt.qss import dark_theme, light_theme from torrentfileQt.utils import StyleManager, get_icon +THEMES = {"dark_theme": dark_theme, "light_theme": light_theme} +DEFAULT_THEME = "dark_theme" + class Window(QMainWindow): """ @@ -114,7 +117,7 @@ def __init__(self, parent=None): class Application(QApplication): """QApplication Widget.""" - def __init__(self, args=None): + def __init__(self, args): """ Construct for main application backend. @@ -123,31 +126,25 @@ def __init__(self, args=None): args : list argument list passed to window. """ - self.args = args if args else sys.argv - self.themes = {"light": light_theme, "dark": dark_theme} - super().__init__(self.args) - self.styleManager = StyleManager(self.themes, dark_theme, self) + super().__init__(args) + self.styleManager = StyleManager(THEMES) + self.styleManager.themeRequest.connect(self.apply_theme) + self.window = Window(parent=None, app=self) + self.styleManager.set_theme_from_title(DEFAULT_THEME) def apply_theme(self, theme): """Apply the given stylesheet.""" + self.styleManager.current = theme self.setStyleSheet(theme) - -def start(): # pragma: no cover - """Start the program entrypoint.""" - app = Application() - window = Window(parent=None, app=app) - window.show() - sys.exit(app.exec()) - - -def alt_start(): - """Start the program entrypoint alternate.""" - app = Application() - window = Window(parent=None, app=app) - window.show() - return window, app + @classmethod + def start(cls, args=None): # pragma: no cover + """Start the program entrypoint.""" + app = cls(args if args else sys.argv) + app.window.show() + sys.exit(app.exec()) -if __name__ == "__main__": - start() # pragma: no cover +def execute(): + """Run application.""" + Application.start() diff --git a/tox.ini b/tox.ini index 92d27d5..ce83f73 100644 --- a/tox.ini +++ b/tox.ini @@ -31,16 +31,16 @@ commands = pytest --cov=torrentfileQt --cov=tests --ff coverage xml coverage html - black torrentfileQt tests - isort torrentfileQt tests pydocstyle torrentfileQt tests pycodestyle torrentfileQt tests pylint torrentfileQt tests bandit -r -c pyproject.toml torrentfileQt tests pyroma . - autopep8 -r torrentfileQt tests - yapf -r -i torrentfileQt tests + black torrentfileQt tests flake8 torrentfileQt tests + yapf -r -i torrentfileQt tests + autopep8 -r torrentfileQt tests + isort torrentfileQt tests [pydocstyle] ignore = D200, D210, D212, D213, D413, D407, D406, D203