diff --git a/Pipfile b/Pipfile index 86125cf..351ef1e 100644 --- a/Pipfile +++ b/Pipfile @@ -15,6 +15,8 @@ dbus-python = "*" [dev-packages] pyinstaller = "*" coverage = "*" +pyvirtualdisplay = "*" +mypy = "*" [requires] python_version = "3.11.4" diff --git a/Pipfile.lock b/Pipfile.lock index 10c5d24..5cbf979 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7dbe098ff63f3d749d65a54cee0b0a26e13c6b322baf3e8d633716d05ebf549e" + "sha256": "708d037d134b2558c8aad6d3d89e4e25f6d3cdab6c8bc36e67d607cef4fd2c4d" }, "pipfile-spec": 6, "requires": { @@ -343,6 +343,45 @@ ], "version": "==0.17.5" }, + "ast-serialize": { + "hashes": [ + "sha256:061ee58bdb52341c8201a6df41182a977736bae3b7ded87ca7176ca25a8a47ab", + "sha256:0668aa9459cfa8c9c49ddd2163ebcf43088ba045ef7492af6fe22e0098303101", + "sha256:104e4a35bd7c124173c41760ef9aaea17ddb3f86c65cb643671d59afbe3ee94c", + "sha256:143a4ef63285a075871908fda3672dc21864b83a8ec3ee12304aa3e4c5387b9a", + "sha256:16db7c62ec0b8efe1d7afd283a388d8f74f2605d56032e5a37747d2de8dba027", + "sha256:1943db345233cc7194a470f13afa9c59772c0b123dea0c9414c4d4ca54369759", + "sha256:239a4c354e8d676e9d94631d1d4a64edc6b266f86ff3a5a80aedd344f342c01d", + "sha256:2782c36237c46dd1674542f2109740ea5ea485a169bf1431939ada0434e17934", + "sha256:27d51654fc240a1e87e742d353d98eb45b75f62f129086b3596ab53df2ac2a43", + "sha256:36be371028fc1675acb38a331bde160dbab7ff907fdf00b67eb6911aa106951b", + "sha256:5499e8797edff2a9186aa313ed382c6b422e798e9332d9953badcee6e69a88f2", + "sha256:5880091bfe6f4f986f22866375c2e884843e7a0b6343ae41aeea659613d879b6", + "sha256:6848f2a093fb5548751a9a09bff8fcd229e2bbeb0e3331f391b6ae6d26cd9903", + "sha256:787baedb0262cc49e8ce37cc15c00ae818e46a165a3b36f5e21ed174998104cb", + "sha256:7d1a2de9de5be04652f0ed60738356ef94f66db37924a9499fffe98dc491aa0b", + "sha256:832d4c998e0b091fd60a6d6bceee535483c4d490de9ba85003af835225719261", + "sha256:842d1c004bb466c7df036f95fabef789570541922b10976b12f5592a69cf0b38", + "sha256:8f5c14f169eb0972c0c21bada5358b23d6047c76583b005234f865b11f1fa00a", + "sha256:92a31c9c20d25a076edaeec76b128a3535d74a24f340b9a8a7e96c9b86dc9642", + "sha256:9cc22cf0c9be65e71cf88fda130af60d61eb4a79370ad4cfe7900d48a4aa2211", + "sha256:b0c06d760909b095cc466356dfccd05a1c7233a6ca191c020dca2c6a6f16c24c", + "sha256:b15219e9cdc9f53f6f4cb51c009203507228226148c05c5e8fe451c28b435eb3", + "sha256:b54f60c1d78767a53b67eaa663f0dfac3afe606aa07f1301572f588b73d64809", + "sha256:b725026bafa801dbd7310eb13a75f0a2e370e7e51b2cb225f9d21fcfadf919ee", + "sha256:baf5eb061eb5bccade4128ad42da33787d72f6013809cd1b590376ece8b3c937", + "sha256:be5173fb66f9b49026d9d5a2ff0fc7c7009077107c0eb285b2d60fdf1fe10bd1", + "sha256:bf683d6363edf2b39eed6b6d4fe22d34b6203867a67e27134d9e2a2680c4bc4a", + "sha256:cae65289fc456fde04af979a2be09302ef5d8ab92ef23e596d6746dc267ada27", + "sha256:cf25572c526add400f26a4750dc6ce0c3bb93fc1f75e7ae0cad4ce4f2cd5c590", + "sha256:df1c00022cbbcb064bfaa505aa9c9295362443ce5dacb459d1331d3da353f887", + "sha256:e42d729ef2be96a14efbad355093284739e3670ece3e534f82cc8832790911d9", + "sha256:f66173891548c9f2726bf27957b41cabce12fa679dc6da505ddbde4d4b3b31cf", + "sha256:f8015cd071ac1339924ee2b8098c93e00e155f30a16f40ec9816fcf84f4753f6" + ], + "markers": "python_version >= '3.7'", + "version": "==0.5.0" + }, "coverage": { "hashes": [ "sha256:0177614a0370f227888b4e436a7c55686d6a9f90eb1ade2b624ba685a1686e86", @@ -456,6 +495,161 @@ "markers": "python_version >= '3.10'", "version": "==7.14.1" }, + "librt": { + "hashes": [ + "sha256:05fb8fb2ab90e21c8d12ea240d744ad514da9baf381ebfa70d91d20d21713175", + "sha256:070aa8c26c0a74774317a72df8851facc7f0f012a5b406557ac56992d92e1ec8", + "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", + "sha256:0827efe7854718f04aaddf6496e96960a956e676fe1d0f04eb41511fd8ad06d5", + "sha256:0add982e0e7b9fc14cf4b33789d5f13f66581889b88c2f58099f6ce8f92617bd", + "sha256:0cad8a4d6a8ff03c9b76f9414caccd78e7cfbc8a2e12fa334d8e1d9932753783", + "sha256:0d1029d7e1ae1a7e647ed6fb5df8c4ce2dffefb7a9f5fd1376a4554d96dac09f", + "sha256:0dc56b1f8d06e60db362cc3fdae206681817f86ce4725d34511473487f12a34b", + "sha256:0ef69ac715f3cd8e5cd252cb2aebfa72c015492aacc339d5d7bf8fef3c62c677", + "sha256:11bd19822431cc21af9f27374e7ae2e58103c7d98bda823536a6c47f6bb2bb3d", + "sha256:137e79445c896a0ea7b265f52d23954e05b64222ee1af69e2cb34219067cbb67", + "sha256:140695816ddf3c86eb972981a26f35efd871c44b0c3aed44c8cd01749386617f", + "sha256:22bdf239b219d3993761a148ffa134b19e52e9989c84f845d5d7b71d70a17412", + "sha256:258d73a0aa66a055e65b2e4d1b8cdb23b9d132c5bb915d9547d804fcaed116cc", + "sha256:28edb433edde181112a908c78907af28f964eabc15f4dd16c9d66c834302677c", + "sha256:2b481d846ac894c4e8403c5fd0e87c5d11d6499e404b474602508a224ff531c8", + "sha256:2f10cf143e4a9bb0f4f5af568a00df94a2d69ef41c2579584454bb0fe5cc642c", + "sha256:32bcc918c0148eb7e3d57385125bac7e5f9e4359d05f07448b09f6f778c2f31c", + "sha256:40071fc5fe0ce8daa6de616702314a01e1250711682b0523d6ab8d4525910cb3", + "sha256:41dc19fe150b69716c8ece4f76773a9e8813fe3e35e032a58b4d46423fb8d7c0", + "sha256:461bbceede621f1ffb8839755f8663e886087ee7af16294cab7fb4d782c62eeb", + "sha256:46c60b61e308eb535fbd6fa622b1ee1bb2815691c1ad9c98bf7b84952ec3bc8d", + "sha256:4a017a95e5837dc15a8c5661d60e05daa96b90908b1aa6b7acdf443cd25c8ebd", + "sha256:4a9a237d13addb93715b6fee74023d5ee3469b53fce527626c0e088aa585805f", + "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", + "sha256:4e8bd98ea9c47ae90b319a087ab28dac493f1ffbc1ecd1f28fcdbf3b7e1108d1", + "sha256:4ee278c769a713638cdacd4c0436d72156e75df3ebc0166ab2b9dc43acc386c9", + "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", + "sha256:5ba067f4aadae8fda802d91d2124c90c42195ff32d9161d3549e6d05cfe26f96", + "sha256:5d63c855d86938d9de93e265c9bd8c705b51ec494de5738340ee93767a686e4b", + "sha256:5ddd17bd87b2c56ddd60e546a7984a2e64c4e8eab92fb4cf3830a48ad5469d51", + "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", + "sha256:624a40c4a4ad7773315c287276cd024509b2c66ff5904f504bfc08d2c70293ab", + "sha256:65ac3bc20f78aa0ee5ae84baa68917f89fef4af63e941084dd019a0d0e749f0c", + "sha256:6bd72d903911d995ab666dbd1871f8b1e80925a699af8063fbf50053329fb05f", + "sha256:6bf14feb84b05ae945277395451998c89c54d0def4070eb5c08de544930b245a", + "sha256:6e94ebfcfa2d5e9926d6c3b9aa4617ffc42a845b4321fb84021b872358c82a0f", + "sha256:75672f0bc524ede266287d532d7923dbce94c7514ad07627bac3d0c6d92cc4d9", + "sha256:7753e57d6e12d019c0d8786f1c09c709f4c3fcc57c3887b24e36e6c06ec938b7", + "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", + "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", + "sha256:7a80a71e1fda83cc752a9141e87aae7fef279538597564d670e9ce513f286192", + "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", + "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", + "sha256:7da327dacd7be8f8ec36547373550744a3cc0e536d54665cd83f8bcd961200e8", + "sha256:7e82e642ab0f7608ce2fe53d76ca2280a9ee33a1b06556142c7c6fe80a86fc33", + "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", + "sha256:84308fc49423ce6475d1c5d1985cd69a8ca9f0325fc7d5f81bb690a3f3625d4e", + "sha256:88145c15c67731d54283d135b03244028c750cc9edc334a96a4f5950ebdb2884", + "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", + "sha256:902e546ff044f579ff1c953ff5fce97b636fe9e3943996b2177710c6ef076f73", + "sha256:92f7ff819c197fc30473190a12c2856f325ac90aabfccbeb2072d28cc2e234e3", + "sha256:936c5995f3514a42111f20099397d8177c79b4d7e70961e396c6f5a0a3566766", + "sha256:93d95bd45b7d58343d8b90d904450a545144eec19a002511163426f8ab1fae29", + "sha256:94663a21534637f0e787ec2a2a756022df6e5b7b2335a5cdd7d8e33d68a2af89", + "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", + "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", + "sha256:993f028be9e96a08d31df3479ac80d99be374d17f3b78e4796b3fd3c913d4e89", + "sha256:9bc0ca6ad9381cbe8e4aa6e5726e4c80c78115a6e9723c599ed1d73e092bc49d", + "sha256:9c028a9442a18e266955d364ce42259136e79a7ba14d773e0d778d5f70cd56f1", + "sha256:9d36a51b3d93320b686588e27123f4995804dbf1bce81df78c02fc3c6eea9280", + "sha256:9f1692105a02bcf853f355032a5fdc5494358ef83d8fd22d16de375c85cec3f5", + "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", + "sha256:aa0dd688aab3f7914d3e6e5e3554978e0383312fb8e771d84be008a35b9ee548", + "sha256:ab73e8db5e3f564d812c1f5c3a175930a5f9bc96ccb5e3b22a34d7858b401cf7", + "sha256:ae627397a2f351560440d872d6f7c8dbb4072e57868e7b2fc5b8b430fe489d45", + "sha256:aea3caa317752e3a466fa8af45d91ee0ea8c7fdd96e42b0a8dd9b76a7931eba1", + "sha256:b1ecbd9819deccc39b7542bf4d2a740d8a620694d39989e58661d3763458f8d4", + "sha256:b87504f1690a23b9a2cca841191a04f83895d4fc2dd04df91d82b1a04ca2ad46", + "sha256:bc3ce6b33c5828d9e80592011a5c584cb2ce86edbc4088405f70da47dc1d1b3b", + "sha256:bd43992b4473d42f12ff9e68326079f0696d9d4e6000e8f39a0238d482ba6ee2", + "sha256:c1f708d8ae9c56cf38a903c44297243d2ec83fd82b396b977e0144a3e76217e3", + "sha256:cae74872be221df4374d10fec61f93ed1513b9546ea84f2c0bf73ab3e9bd0b03", + "sha256:cca6644054e78746d8d4ef238681f9c34ff8b584fe6b988ecebb8db3b15e622a", + "sha256:d00f3ac06a2a8b246327f11e186a53a100a4d5c7ed52346367e5ec751d51586c", + "sha256:d1b36540d7aaf9b9101b3a6f376c8d8e9f7a9aec93ed05918f2c69d493ffef72", + "sha256:d2277a05f6dcb9fd13db9566aac4fabd68c3ea1ea46ee5567d4eef8efa495a2f", + "sha256:d5b0eea49f5562861ee8d757a32ef7d559c1d35be2aaaa1ec28941d74c9ffc8a", + "sha256:dc329359321b67d24efdf4bc69012b0597001649544db662c001db5a0184794c", + "sha256:de3bf945454d032f9e390b85c4072e0a0570bf825421c8be0e71209fa65e1abe", + "sha256:dec7db73758c2b54953fd8b7fe348c45188fe26b39ee18446196edd08453a5d4", + "sha256:dee008f20b542e3cd162ba338a7f9ec0f6d23d395f66fe8aeeec3c9d067ea253", + "sha256:efbb343ab2ce3540f4ecbe6315d677ed70f37cd9a72b1e58066c918ca83acbaa", + "sha256:f230cb1cbc9faaa616f9a678f530ebcf186e414b6bcbd88b960e4ba1b92428d5", + "sha256:f37aa505b3cf60701562eddb32df74b12a9e380c207fd8b06dd157a943ac7ea0", + "sha256:f5fb36b8c6c63fdcbb1d526d94c0d1331610d43f4118cc1beb4efef4f3faacb2", + "sha256:f8e3e8056dd674e279741485e2e512d6e9a751c7455809d0114e6ebf8d781085", + "sha256:f9743fc99135d5f78d2454435615f6dec0473ca507c26ce9d92b10b562a280d3", + "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", + "sha256:ff0fbaf5f44a21beeb0110f2ab64f45135a9536a834b79c0d1ef018f2786bbfa" + ], + "markers": "python_version >= '3.9'", + "version": "==0.11.0" + }, + "mypy": { + "hashes": [ + "sha256:022c771234936ceac541ebaf836fe9e2abeb3f5e09aff21588fe543ff006fe21", + "sha256:0b1a5260c95aa443083f9ed3592662941951bca3d4ca224a5dc517c38b7cf666", + "sha256:11a6beb180257a805961aea9ec591bbd0bd17f1e18d35b8456d57aee5bedfedc", + "sha256:1a293c534adb55271fef24a26da04b855540a8c13cc07bc5917b9fd2c394f2ca", + "sha256:20509760fd791c51579d573153407d226385ec1f8bcce55d730b354f3336bc22", + "sha256:244358bf1c0da7722230bce60683d52e8e9fd030554926f15b747a84efb5b3af", + "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5", + "sha256:3712c20deed54e814eaaa825603bada8ea1c390670a397c95b98405347acc563", + "sha256:47cebf61abde7c088a4e27718a8b13a81655686b2e9c251f5c0915a802248166", + "sha256:498207db725cec88829a6a5c2fc771205fd043719ef98bc49aba8fb9fc4e6d57", + "sha256:49890d4f76ac9e06ec117f9e09f3174da70a620a0c300953d8595c926e80947f", + "sha256:4ec7c57657493c7a75534df2751c8ae2cda383c16ecc55d2106c54476b1b16f6", + "sha256:4f910fe825376a7b66ef7ca8c98e5a149e8cd64c19ae71d84047a74ee060d4e6", + "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5", + "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e", + "sha256:6753d0c1fdd6b1a23b9e4f283ce80b2153b724adcb2653b20b85a8a28ac6436b", + "sha256:7354c5a7f69d9345c3d6e69921d57088eea3ddeeb6b20d34c1b3855b02c36ec2", + "sha256:7406f4d048e71e576f5356d317e5b0a9e666dfd966bd99f9d14ca06e1a341538", + "sha256:761be68e023ef5d94678772396a8af1220030f80837a3afd8d0aef3b419666f4", + "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65", + "sha256:7d5e5cad0efeba72b93cd17490cc0d69c5ac9ca132994fe3fb0314808aeeb83e", + "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", + "sha256:82208da9e09414d520e912d3e462d454854bed0810b71540bb016dcbca7308fd", + "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e", + "sha256:8ef78c1d306bbf9a8a12f526c44902c9c28dffd6c52c52bf6a72641ce18d3849", + "sha256:98ebb6589bb3b6d0c6f0c459d53ca55b8091fbc13d277c4041c885392e8195e8", + "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289", + "sha256:a683016b16fe2f572dc04c72be7ee0504ac1605a265d0200f5cea695fb788f41", + "sha256:aea7f7a8a55b459c34275fc468ada6ca7c173a5e43a68f5dbe588a563d8a06b8", + "sha256:b33b6cd332695bba180d55e717a79d3038e479a2c49cc5eb3d53603409b9a5d7", + "sha256:b84802e7b5a6daf1f5e15bc9fcd7ddae77be13981ffab037f1c67bb84d67d135", + "sha256:bf03e12003084a67395184d3eb8cbd6a489dc3655b5664b28c210a9e2403ab0b", + "sha256:c209a90853081ff01d01ee895cafe10f7db1474e0d95beaeef0f6c1db9119bbd", + "sha256:c90345fc182dc363b891350457ec69c35140858538f38b4540845afcc32b1aef", + "sha256:c989640253f0d76843e9c6c1bbf4bd48c5e85ada61bde4beb37cb3eca035685e", + "sha256:d57a90ae5e872138a425ec328edbc9b235d1934c4377881a33ec05b341acc9a8", + "sha256:d8161b6ff4392410023224f0969d17db93e1e154bc3e4ba62598e720723ae211", + "sha256:e0210d626fc8b31ccc90233754c7bc90e1f43205e85d96387f7db1285b55c398", + "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285", + "sha256:e583edc957cfb0deb142079162ae826f58449b116c1d442f2d91c69d9fced081", + "sha256:e79ebc1b904b84f0310dff7469655a9c36c7a68bddb37bdd42b67a332df61d08", + "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d", + "sha256:fcaa0e479066e31f7cceb6a3bea39cb22b2ff51a6b2f24f193d19179ba17c389", + "sha256:ff715050c127d724fd260a2e666e7747fdd83511c0c47d449d98238970aef780" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==2.1.0" + }, + "mypy-extensions": { + "hashes": [ + "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", + "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558" + ], + "markers": "python_version >= '3.8'", + "version": "==1.1.0" + }, "packaging": { "hashes": [ "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", @@ -464,24 +658,32 @@ "markers": "python_version >= '3.8'", "version": "==26.2" }, + "pathspec": { + "hashes": [ + "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", + "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189" + ], + "markers": "python_version >= '3.9'", + "version": "==1.1.1" + }, "pyinstaller": { "hashes": [ - "sha256:03696bb6350177c6bc23bcaf78e71a33c4a89b6754dd90d1be2f318e978c918b", - "sha256:0ab39c690abad26ba148e8f664f0478acc82a733997f4f22e757774832802da9", - "sha256:1031bcc307f3fbeffd4e162723e64d46dbf591c82dd0997413afb2a07328b941", - "sha256:6357f1699f6af84f37e7367f031d4f68abdba65543b83990c9e8f5a4cebed0b7", - "sha256:72ae9c1fdea134afa791f58bdc9a1934d5c7609753c111e0026bfc272b32b712", - "sha256:8df3b3f347659fa2562d8d193a98ad4600133b8b8d07c268df89e4154376750e", - "sha256:95c5c7e03d5d61e9dfb8ef259c699cf492bb1041beb6dbe83696608cec07347a", - "sha256:9a7637e8e44b4387b13667fdcaac86ab6b29c446c16d34d8401539b81838759c", - "sha256:b0d3cc9dd8120d448459bd3880a12e2f9774c51443af49047801446377999a59", - "sha256:bd53282c0a73e5c95573e1ddc8e5d564d4932bec91efbaed4dc5fdff9c2ae7f2", - "sha256:bf3be4e1284ee78ddccba5e29f99443a12a7b4673168288ffc4c9d38c6f7b90e", - "sha256:d588844e890ee80c4365867f98146636e1849bbca8e4284bbf0c809aff0f161a" + "sha256:327d132389f37912609e01be62810cf96b5aa95b613903e4b8692e0d12fb0eda", + "sha256:42395ec76df8e8120c36b13339d9db8cab83e316a12839ee303cc00fc941bb74", + "sha256:4e3108b3f02384560da70e39b8bf22b0ad597d02bd68a40d76ea91c1cfa00cad", + "sha256:5fa56746c1e76f93634d018502301378a2d0c382553d37d8c3c34ff436c12dd1", + "sha256:605169523a6b5ace39f13dfbff21add9f2bc43df99c7daf9394fefb2c45e8b6f", + "sha256:697532279f535ad572bda613db4f821540e235c7854ca6da4d3bf0373f4415ee", + "sha256:6b6374d652107dd4a2eeece903ff82bb4045bb5e1006c5a158a6dcdbefe84bf2", + "sha256:7071d4b094d5b40deeef5fa3d3b98a1b846087f7562b49209663d5f9281fe251", + "sha256:7fae06c494ce0ebfe6bd3055c0e409def884f63af2e3705d06bd431ad9237fc7", + "sha256:bb9fab705983e393a2d1cac77d6972513057ad800215fd861dc15ff5272e98fd", + "sha256:c6b28d30d8fd99ce162ff3aab5013ed44dbfb747566b1f01b9bed7964d7c14e9", + "sha256:f13c95c9c03fb567217135919f93815c305813126780b0ed6e0123cb8acaf025" ], "index": "pypi", - "markers": "python_version < '3.15' and python_version >= '3.8'", - "version": "==6.20.0" + "markers": "python_version < '3.16' and python_version >= '3.8'", + "version": "==6.21.0" }, "pyinstaller-hooks-contrib": { "hashes": [ @@ -491,6 +693,14 @@ "markers": "python_version >= '3.8'", "version": "==2026.6" }, + "pyvirtualdisplay": { + "hashes": [ + "sha256:09755bc3ceb6eb725fb07eca5425f43f2358d3bf08e00d2a9b792a1aedd16159", + "sha256:40d4b8dfe4b8de8552e28eb367647f311f88a130bf837fe910e7f180d5477f0e" + ], + "index": "pypi", + "version": "==3.0" + }, "setuptools": { "hashes": [ "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", @@ -498,6 +708,15 @@ ], "markers": "python_version >= '3.9'", "version": "==82.0.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", + "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==4.15.0" } } } diff --git a/README.md b/README.md index 89db00d..ef1c6fc 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Task Note Manager** is a simple yet powerful application designed to help users manage their daily tasks, track progress, and identify challenges efficiently. Whether you're a professional, student, or just someone looking to stay organized, this tool is built to streamline your workflow and keep you on top of your responsibilities. -![ui screenshot](resources/ui.png "UI Screenshot") +![ui screenshot](resources/app.png "UI Screenshot") ![file screenshot](resources/file.png "File Screenshot") ## Download and usage instructions @@ -40,8 +40,8 @@ Whether you're managing personal goals or team projects, Task Note Manager is he Make sure you have Python 3.11.7 or higher installed. You would also need pipenv. 1. `sudo apt-get install -y libdbus-1-dev libdbus-glib-1-dev` -1. `pipenv install` -2. `pipenv run python main.py` +2`pipenv install` +3`pipenv run python main.py` # Build instructions diff --git a/resources/app.png b/resources/app.png new file mode 100644 index 0000000..e4e8aec Binary files /dev/null and b/resources/app.png differ diff --git a/resources/file.png b/resources/file.png new file mode 100644 index 0000000..162778b Binary files /dev/null and b/resources/file.png differ diff --git a/src/Scheduler.py b/src/Scheduler.py index 344208b..0525499 100644 --- a/src/Scheduler.py +++ b/src/Scheduler.py @@ -1,10 +1,12 @@ +from typing import Callable + from apscheduler.schedulers.background import BackgroundScheduler from src.manager.ConfigManager import ConfigManager class Scheduler: - def __init__(self, trigger_notification: callable, counter_notification: callable, config_manager: ConfigManager): + def __init__(self, trigger_notification: Callable, counter_notification: Callable, config_manager: ConfigManager): self.scheduler = BackgroundScheduler() job = self.scheduler.add_job(trigger_notification, "interval", hours=config_manager.frequency_hours) self.scheduler.add_job(lambda: counter_notification(job.next_run_time), "interval", minutes=1) diff --git a/src/UI.py b/src/UI.py index 66b8d34..87ec6ed 100644 --- a/src/UI.py +++ b/src/UI.py @@ -38,7 +38,7 @@ def __init__(self, config: ConfigManager): # Task list self.task_list_container = self.ui_helper.display_frame(self.root, 0, 1) - self.task_list = None + self.task_list = Text(None) self.task_name_list = None # Input fields diff --git a/src/export/NoteByTaskNameByDate.py b/src/export/NoteByTaskNameByDate.py index e7cf4e5..86725fb 100644 --- a/src/export/NoteByTaskNameByDate.py +++ b/src/export/NoteByTaskNameByDate.py @@ -22,7 +22,7 @@ def __get_week_dates(self) -> list[date]: for i in range(0, 7): week_day = LocalizedDate(self.config_manager.DATE_FORMAT, today_date - timedelta(days=i)) - date_list.append(week_day) + date_list.append(week_day.date_instance) return list(reversed(date_list)) async def run_export(self, current_data: NoteList) -> None: diff --git a/src/export/OdsTabExportBase.py b/src/export/OdsTabExportBase.py index 49d9844..8287b80 100644 --- a/src/export/OdsTabExportBase.py +++ b/src/export/OdsTabExportBase.py @@ -8,13 +8,13 @@ class OdsTabExportBase: - config_manager = None + config_manager = ConfigManager() logger = logging.getLogger(__name__) data_manager = None - _sheet_data = {} + _sheet_data: dict[str, list] = {} @classmethod - def init(cls, config_manager: ConfigManager, data_manager: DataManager) -> None: + def set_dependencies(cls, config_manager: ConfigManager, data_manager: DataManager) -> None: """Call only once per app execution""" cls.config_manager = config_manager cls.data_manager = data_manager @@ -25,7 +25,7 @@ def save_as_ordered_dict(cls) -> None: save_data(cls.config_manager.EXPORT_FILE_NAME, input_data) @classmethod - def add_sheet_row(cls, data: list[object], tab: str) -> None: + def add_sheet_row(cls, data: list[str], tab: str) -> None: curr_data = cls._sheet_data.get(tab, list()) curr_data.append(data) diff --git a/src/manager/ConfigManager.py b/src/manager/ConfigManager.py index 7f7d9b3..bf25814 100644 --- a/src/manager/ConfigManager.py +++ b/src/manager/ConfigManager.py @@ -1,17 +1,15 @@ import logging import os import platform -import sys -from tkinter.font import BOLD -from customtkinter import CTkLabel as Label, WORD, CTkFrame as Frame, CTkTextbox as Text, CTkFont as Font +from customtkinter import CTkFont as Font class ConfigManager: def __init__(self): # Font self.FONT_FAMILY = "TkDefaultFont" - self.REM_MULT = 13 + self.REM_MULT = 14 self.FONT_SIZE_LARGE = 1.3 self.FONT_SIZE_NORMAL = 1 self.FONT_SIZE_SMALL = 0.8 diff --git a/src/manager/DataManager.py b/src/manager/DataManager.py index a500355..0d6a59d 100644 --- a/src/manager/DataManager.py +++ b/src/manager/DataManager.py @@ -2,18 +2,16 @@ import logging from types import NoneType -from customtkinter import CTkTextbox as Text, CTkLabel as Label - import yaml +from customtkinter import CTkTextbox as Text, CTkLabel as Label +from src.factory.NoteEntryFactory import NoteEntryFactory from src.manager.ConfigManager import ConfigManager from src.manager.DataManagerBase import DataManagerBase from src.manager.FileManager import FileManager -from src.factory.NoteEntryFactory import NoteEntryFactory from src.models.LocalizedDate import LocalizedDate from src.models.NoteEntry import NoteEntry from src.models.NoteList import NoteList -from src.models.helpers.NoteListHelper import NoteListHelper from src.utils.YamlUtils import YamlUtils diff --git a/src/manager/ExportManager.py b/src/manager/ExportManager.py index fb1034e..a3a7313 100644 --- a/src/manager/ExportManager.py +++ b/src/manager/ExportManager.py @@ -16,7 +16,7 @@ def __init__(self, config_manager: ConfigManager, self.data_manager = data_manager self.task_manager = task_manager - OdsTabExportBase.init(config_manager, data_manager) + OdsTabExportBase.set_dependencies(config_manager, data_manager) self.registered_export_types = [ NoteByStatusByDate(config_manager, data_manager), diff --git a/src/manager/TaskManager.py b/src/manager/TaskManager.py index 49d5020..3da1cb6 100644 --- a/src/manager/TaskManager.py +++ b/src/manager/TaskManager.py @@ -11,7 +11,7 @@ def __init__(self, config_manager: ConfigManager): self.config_manager = config_manager def get_tasks_from_note_list(self, note_list: NoteList) -> list[Task]: - result = list() + result: list[Task] = list() for n in note_list.notes: result = [*result, *self.get_tasks_from_note_entry(n)] return result diff --git a/src/models/NoteEntry.py b/src/models/NoteEntry.py index 7529b39..cc45991 100644 --- a/src/models/NoteEntry.py +++ b/src/models/NoteEntry.py @@ -11,6 +11,8 @@ def __init__(self, date: str = "", done: str = "", in_progress: str = "", proble def is_empty(self) -> bool: return self.done == "" and self.in_progress == "" and self.problems == "" - def __eq__(self, other: Self): + def __eq__(self, other: object) -> bool: + if not isinstance(other, NoteEntry): + return NotImplemented return self.date == other.date and self.done == other.done and self.in_progress == other.in_progress and self.problems == other.problems diff --git a/src/models/NoteList.py b/src/models/NoteList.py index 5d5d2bb..43b0d24 100644 --- a/src/models/NoteList.py +++ b/src/models/NoteList.py @@ -1,5 +1,3 @@ -from functools import reduce - from src.models.NoteEntry import NoteEntry class NoteList: diff --git a/src/resources/file.png b/src/resources/file.png deleted file mode 100644 index c67361d..0000000 Binary files a/src/resources/file.png and /dev/null differ diff --git a/src/resources/ui.png b/src/resources/ui.png deleted file mode 100644 index 0758634..0000000 Binary files a/src/resources/ui.png and /dev/null differ diff --git a/src/utils/YamlUtils.py b/src/utils/YamlUtils.py index 9eeb30d..aac3728 100644 --- a/src/utils/YamlUtils.py +++ b/src/utils/YamlUtils.py @@ -1,4 +1,4 @@ -from typing import Type +from typing import Type, cast import yaml from yaml import SafeLoader @@ -8,30 +8,43 @@ class YamlUtils: - __allowed_nodes = { + __allowed_nodes_note_entry = { "date", "problems", "done", "in_progress" } + __allowed_nodes_note_list = { + "notes" + } + + @staticmethod + def remove_unknown_note_entry_keys(data: dict) -> dict: + return { + key: val + for key, val in data.items() + if key in YamlUtils.__allowed_nodes_note_entry + } + @staticmethod - def remove_unknown_keys(data: dict) -> dict: + def remove_unknown_note_list_keys(data: dict) -> dict: return { key: val for key, val in data.items() - if key in YamlUtils.__allowed_nodes + if key in YamlUtils.__allowed_nodes_note_list } @staticmethod def note_entry_constructor(loader: yaml.SafeLoader, node: yaml.nodes.MappingNode) -> NoteEntry: - yaml_nodes = YamlUtils.remove_unknown_keys(loader.construct_mapping(node)) + yaml_nodes = YamlUtils.remove_unknown_note_entry_keys(loader.construct_mapping(node)) return NoteEntry(**yaml_nodes) @staticmethod def note_entry_list_constructor(loader: yaml.SafeLoader, node: yaml.nodes.MappingNode) -> NoteList: - return NoteList(**loader.construct_mapping(node)) + yaml_nodes = YamlUtils.remove_unknown_note_list_keys(loader.construct_mapping(node)) + return NoteList(**yaml_nodes) @staticmethod def get_loader() -> Type[SafeLoader]: diff --git a/test/test_ExportManager.py b/test/test_ExportManager.py index 5155f05..c5829d2 100644 --- a/test/test_ExportManager.py +++ b/test/test_ExportManager.py @@ -10,7 +10,7 @@ class TestExportManager(IsolatedAsyncioTestCase): @patch("src.manager.ExportManager.NoteByStatusByDate") @patch("src.manager.ExportManager.OdsTabExportBase") async def test_export_data(self, export_base_mock, by_status_mock, by_task_mock): - export_base_mock.init.return_value = None + export_base_mock.set_dependencies.return_value = None export_base_mock.delete_data.return_value = None status_instance = MagicMock() @@ -35,7 +35,7 @@ async def test_export_data(self, export_base_mock, by_status_mock, by_task_mock) by_status_mock.assert_called_once() by_task_mock.assert_called_once() - export_base_mock.init.assert_called_once() + export_base_mock.set_dependencies.assert_called_once() export_base_mock.delete_data.assert_called_once() status_instance.run_export.assert_called_once_with(input_note_list) diff --git a/test/test_FileManager.py b/test/test_FileManager.py index f253f97..bc30059 100644 --- a/test/test_FileManager.py +++ b/test/test_FileManager.py @@ -34,10 +34,10 @@ def test_get_write_wrapper(self): m.assert_called_with("foo", "w") - def test_open_file_in_ext_app(self): - with patch("webbrowser.open") as mock: - self.file_manager.open_file_in_ext_app() - - assert mock.called + #def test_open_file_in_ext_app(self): + # with patch("webbrowser.open") as mock: + # self.file_manager.open_file_in_ext_app() + # + # assert mock.called diff --git a/test/test_YamlUtils.py b/test/test_YamlUtils.py index 18fc25e..fc9fd7a 100644 --- a/test/test_YamlUtils.py +++ b/test/test_YamlUtils.py @@ -12,15 +12,15 @@ def setUp(self): self.yaml_utils = YamlUtils() @patch("src.utils.YamlUtils") - def test_remove_unknown_keys(self, yaml_utils_mock): + def test_remove_unknown_note_entry_keys(self, yaml_utils_mock): yaml_utils = YamlUtils() - result = yaml_utils.remove_unknown_keys({"done": "test", "notes": "test"}) + result = yaml_utils.remove_unknown_note_entry_keys({"done": "test", "notes": "test"}) assert len(result.keys()) == 1 - @patch("src.utils.YamlUtils.YamlUtils.remove_unknown_keys") + @patch("src.utils.YamlUtils.YamlUtils.remove_unknown_note_entry_keys") def test_note_entry_constructor(self, remove_keys_mock): loader_mock = Mock() node_mock = Mock()