pysfi 0.1.11__tar.gz → 0.1.13__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 (151) hide show
  1. {pysfi-0.1.11 → pysfi-0.1.13}/PKG-INFO +3 -1
  2. {pysfi-0.1.11 → pysfi-0.1.13}/pyproject.toml +175 -169
  3. pysfi-0.1.13/sfi/__init__.py +5 -0
  4. pysfi-0.1.13/sfi/alarmclock/README.md +117 -0
  5. pysfi-0.1.13/sfi/alarmclock/__init__.py +3 -0
  6. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/alarmclock/alarmclock.py +23 -40
  7. pysfi-0.1.13/sfi/bumpversion/__init__.py +5 -0
  8. pysfi-0.1.13/sfi/cleanbuild/__init__.py +3 -0
  9. pysfi-0.1.13/sfi/cli.py +21 -0
  10. pysfi-0.1.13/sfi/condasetup/__init__.py +1 -0
  11. pysfi-0.1.13/sfi/docdiff/README.md +108 -0
  12. pysfi-0.1.13/sfi/docdiff/__init__.py +1 -0
  13. pysfi-0.1.13/sfi/docdiff/docdiff.py +238 -0
  14. pysfi-0.1.13/sfi/docdiff/tests/test_benchmark.py +98 -0
  15. pysfi-0.1.13/sfi/docdiff/tests/test_docdiff.py +188 -0
  16. pysfi-0.1.13/sfi/docdiff/tests/test_enhanced.py +150 -0
  17. pysfi-0.1.13/sfi/docdiff/tests/test_functional.py +186 -0
  18. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/__init__.py +3 -3
  19. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/docscan_gui.py +150 -46
  20. pysfi-0.1.13/sfi/filedate/tests/__init__.py +1 -0
  21. pysfi-0.1.13/sfi/img2pdf/img2pdf.py +453 -0
  22. pysfi-0.1.13/sfi/img2pdf/tests/test_benchmark.py +88 -0
  23. pysfi-0.1.13/sfi/img2pdf/tests/test_img2pdf.py +435 -0
  24. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/llmclient/llmclient.py +31 -8
  25. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/llmquantize/llmquantize.py +39 -11
  26. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/llmquantize/tests/test_llmquantize.py +0 -30
  27. pysfi-0.1.13/sfi/llmserver/__init__.py +1 -0
  28. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/llmserver/llmserver.py +63 -13
  29. pysfi-0.1.13/sfi/makepython/README.md +188 -0
  30. pysfi-0.1.13/sfi/makepython/makepython.py +710 -0
  31. pysfi-0.1.13/sfi/makepython/tests/test_benchmark.py +289 -0
  32. pysfi-0.1.13/sfi/makepython/tests/test_makepython.py +320 -0
  33. pysfi-0.1.13/sfi/pyarchive/README.md +270 -0
  34. pysfi-0.1.13/sfi/pyarchive/__init__.py +1 -0
  35. pysfi-0.1.13/sfi/pyarchive/pyarchive.py +1048 -0
  36. pysfi-0.1.13/sfi/pyarchive/tests/__init__.py +1 -0
  37. pysfi-0.1.13/sfi/pyarchive/tests/test_benchmark.py +444 -0
  38. pysfi-0.1.13/sfi/pyarchive/tests/test_pyarchive.py +234 -0
  39. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pyembedinstall/pyembedinstall.py +88 -89
  40. pysfi-0.1.13/sfi/pyembedinstall/tests/__init__.py +1 -0
  41. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pyembedinstall/tests/test_pyembedinstall.py +846 -413
  42. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pylibpack/pylibpack.py +571 -465
  43. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pylibpack/tests/test_benchmark.py +51 -20
  44. pysfi-0.1.13/sfi/pylibpack/tests/test_pylibpack.py +1508 -0
  45. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pyloadergen/pyloadergen.py +372 -218
  46. pysfi-0.1.13/sfi/pyloadergen/tests/test_benchmark.py +67 -0
  47. pysfi-0.1.13/sfi/pyloadergen/tests/test_pyloadergen.py +1048 -0
  48. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pypack/README.md +11 -0
  49. pysfi-0.1.13/sfi/pypack/pypack.py +671 -0
  50. pysfi-0.1.13/sfi/pypack/tests/test_benchmark.py +106 -0
  51. pysfi-0.1.13/sfi/pypack/tests/test_pack.py +145 -0
  52. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pyprojectparse/pyprojectparse.py +328 -28
  53. pysfi-0.1.13/sfi/pyprojectparse/tests/__init__.py +1 -0
  54. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pyprojectparse/tests/test_benchmark.py +13 -13
  55. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pyprojectparse/tests/test_projectparse.py +211 -9
  56. pysfi-0.1.13/sfi/pysourcepack/__init__.py +1 -0
  57. pysfi-0.1.13/sfi/pysourcepack/pysourcepack.py +387 -0
  58. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/quizbase/quizbase_gui.py +2 -2
  59. pysfi-0.1.13/sfi/taskkill/README.md +198 -0
  60. pysfi-0.1.13/sfi/taskkill/taskkill.py +343 -0
  61. pysfi-0.1.13/sfi/taskkill/tests/__init__.py +1 -0
  62. pysfi-0.1.13/sfi/taskkill/tests/test_benchmark.py +232 -0
  63. pysfi-0.1.13/sfi/taskkill/tests/test_smoke.py +41 -0
  64. pysfi-0.1.13/sfi/taskkill/tests/test_taskkill.py +339 -0
  65. pysfi-0.1.13/sfi/which/__init__.py +0 -0
  66. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/which/which.py +11 -3
  67. pysfi-0.1.13/sfi/workflowengine/README.md +0 -0
  68. pysfi-0.1.13/sfi/workflowengine/__init__.py +0 -0
  69. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/workflowengine/workflowengine.py +225 -122
  70. pysfi-0.1.11/sfi/__init__.py +0 -3
  71. pysfi-0.1.11/sfi/alarmclock/README.md +0 -64
  72. pysfi-0.1.11/sfi/bumpversion/__init__.py +0 -3
  73. pysfi-0.1.11/sfi/cli.py +0 -11
  74. pysfi-0.1.11/sfi/makepython/makepython.py +0 -327
  75. pysfi-0.1.11/sfi/pyarchive/pyarchive.py +0 -418
  76. pysfi-0.1.11/sfi/pylibpack/tests/test_pylibpack.py +0 -774
  77. pysfi-0.1.11/sfi/pyloadergen/tests/test_benchmark.py +0 -235
  78. pysfi-0.1.11/sfi/pyloadergen/tests/test_pyloadergen.py +0 -325
  79. pysfi-0.1.11/sfi/pypack/pypack.py +0 -1142
  80. pysfi-0.1.11/sfi/pypack/tests/test_pack.py +0 -124
  81. pysfi-0.1.11/sfi/pysourcepack/pysourcepack.py +0 -308
  82. pysfi-0.1.11/sfi/taskkill/taskkill.py +0 -234
  83. {pysfi-0.1.11 → pysfi-0.1.13}/.gitignore +0 -0
  84. {pysfi-0.1.11 → pysfi-0.1.13}/README.md +0 -0
  85. {pysfi-0.1.11 → pysfi-0.1.13}/examples/pack_demo/README.md +0 -0
  86. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/bumpversion/README.md +0 -0
  87. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/bumpversion/bumpversion.py +0 -0
  88. {pysfi-0.1.11/sfi/alarmclock → pysfi-0.1.13/sfi/bumpversion/tests}/__init__.py +0 -0
  89. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/bumpversion/tests/test_bumpversion.py +0 -0
  90. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/cleanbuild/README.md +0 -0
  91. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/cleanbuild/cleanbuild.py +0 -0
  92. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/condasetup/README.md +0 -0
  93. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/condasetup/condasetup.py +0 -0
  94. {pysfi-0.1.11/sfi/bumpversion → pysfi-0.1.13/sfi/docdiff}/tests/__init__.py +0 -0
  95. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/README.md +0 -0
  96. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/docscan.py +0 -0
  97. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/lang/__init__.py +0 -0
  98. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/lang/eng.py +0 -0
  99. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/lang/zhcn.py +0 -0
  100. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/tests/__init__.py +0 -0
  101. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/tests/test_benchmark.py +0 -0
  102. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/tests/test_docscan.py +0 -0
  103. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/docscan/tests/test_enhanced.py +0 -0
  104. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/filedate/README.md +0 -0
  105. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/filedate/__init__.py +0 -0
  106. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/filedate/filedate.py +0 -0
  107. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/filedate/tests/test_filedate.py +0 -0
  108. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/gittool/README.md +0 -0
  109. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/gittool/__init__.py +0 -0
  110. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/gittool/gittool.py +0 -0
  111. {pysfi-0.1.11/sfi/llmclient → pysfi-0.1.13/sfi/img2pdf}/README.md +0 -0
  112. {pysfi-0.1.11/sfi/llmquantize → pysfi-0.1.13/sfi/img2pdf}/__init__.py +0 -0
  113. {pysfi-0.1.11/sfi/makepython → pysfi-0.1.13/sfi/img2pdf/tests}/__init__.py +0 -0
  114. {pysfi-0.1.11/sfi/llmquantize → pysfi-0.1.13/sfi/llmclient}/README.md +0 -0
  115. {pysfi-0.1.11/sfi/pdfsplit → pysfi-0.1.13/sfi/llmclient}/__init__.py +0 -0
  116. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/llmclient/tests/__init__.py +0 -0
  117. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/llmclient/tests/test_benchmark.py +0 -0
  118. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/llmclient/tests/test_llmclient.py +0 -0
  119. {pysfi-0.1.11/sfi/llmserver → pysfi-0.1.13/sfi/llmquantize}/README.md +0 -0
  120. {pysfi-0.1.11/sfi/pdfsplit/tests → pysfi-0.1.13/sfi/llmquantize}/__init__.py +0 -0
  121. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/llmquantize/tests/__init__.py +0 -0
  122. {pysfi-0.1.11/sfi/pyarchive → pysfi-0.1.13/sfi/llmserver}/README.md +0 -0
  123. {pysfi-0.1.11/sfi/pyembedinstall → pysfi-0.1.13/sfi/makepython}/__init__.py +0 -0
  124. {pysfi-0.1.11/sfi/pylibpack → pysfi-0.1.13/sfi/pdfsplit}/__init__.py +0 -0
  125. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pdfsplit/pdfsplit.py +0 -0
  126. {pysfi-0.1.11/sfi/pylibpack → pysfi-0.1.13/sfi/pdfsplit}/tests/__init__.py +0 -0
  127. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pdfsplit/tests/test_pdfsplit.py +0 -0
  128. {pysfi-0.1.11/sfi/pyloadergen → pysfi-0.1.13/sfi/pyembedinstall}/__init__.py +0 -0
  129. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pylibpack/README.md +0 -0
  130. {pysfi-0.1.11/sfi/pyloadergen/tests → pysfi-0.1.13/sfi/pylibpack}/__init__.py +0 -0
  131. {pysfi-0.1.11/sfi/pypack → pysfi-0.1.13/sfi/pylibpack/tests}/__init__.py +0 -0
  132. {pysfi-0.1.11/sfi/pypack/tests → pysfi-0.1.13/sfi/pyloadergen}/__init__.py +0 -0
  133. {pysfi-0.1.11/sfi/pyprojectparse → pysfi-0.1.13/sfi/pyloadergen/tests}/__init__.py +0 -0
  134. {pysfi-0.1.11/sfi/quizbase → pysfi-0.1.13/sfi/pypack}/__init__.py +0 -0
  135. {pysfi-0.1.11/sfi/regexvalidate → pysfi-0.1.13/sfi/pypack/tests}/__init__.py +0 -0
  136. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pyprojectparse/README.md +0 -0
  137. {pysfi-0.1.11/sfi/taskkill → pysfi-0.1.13/sfi/pyprojectparse}/__init__.py +0 -0
  138. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/pysourcepack/README.md +0 -0
  139. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/quizbase/README.md +0 -0
  140. {pysfi-0.1.11/sfi/which → pysfi-0.1.13/sfi/quizbase}/__init__.py +0 -0
  141. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/quizbase/quizbase.py +0 -0
  142. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/quizbase/tests/__init__.py +0 -0
  143. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/quizbase/tests/test_quizbase.py +0 -0
  144. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/quizbase/tests/test_quizbase_gui.py +0 -0
  145. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/regexvalidate/README.md +0 -0
  146. {pysfi-0.1.11/sfi/workflowengine → pysfi-0.1.13/sfi/regexvalidate}/__init__.py +0 -0
  147. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/regexvalidate/regexvalidate.py +0 -0
  148. /pysfi-0.1.11/sfi/workflowengine/README.md → /pysfi-0.1.13/sfi/taskkill/__init__.py +0 -0
  149. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/workflowengine/tests/__init__.py +0 -0
  150. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/workflowengine/tests/test_benchmark.py +0 -0
  151. {pysfi-0.1.11 → pysfi-0.1.13}/sfi/workflowengine/tests/test_workflowengine.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pysfi
3
- Version: 0.1.11
3
+ Version: 0.1.13
4
4
  Summary: Single File commands for Interactive python.
5
5
  Requires-Python: >=3.8
6
6
  Requires-Dist: tomli>=2.4.0; python_version < '3.11'
@@ -17,6 +17,7 @@ Requires-Dist: pyside2>=5.15.2.1; extra == 'all'
17
17
  Requires-Dist: pytesseract>=0.3.10; extra == 'all'
18
18
  Requires-Dist: python-docx>=1.1.0; extra == 'all'
19
19
  Requires-Dist: python-pptx>=0.6.21; extra == 'all'
20
+ Requires-Dist: pywin32>=311; (sys_platform == 'win32') and extra == 'all'
20
21
  Provides-Extra: extra
21
22
  Requires-Dist: ebooklib>=0.18; extra == 'extra'
22
23
  Requires-Dist: markdown>=3.5; extra == 'extra'
@@ -33,6 +34,7 @@ Requires-Dist: openpyxl>=3.1.0; extra == 'office'
33
34
  Requires-Dist: pymupdf>=1.24.11; extra == 'office'
34
35
  Requires-Dist: python-docx>=1.1.0; extra == 'office'
35
36
  Requires-Dist: python-pptx>=0.6.21; extra == 'office'
37
+ Requires-Dist: pywin32>=311; (sys_platform == 'win32') and extra == 'office'
36
38
  Description-Content-Type: text/markdown
37
39
 
38
40
  # pysfi
@@ -1,169 +1,175 @@
1
- [build-system]
2
- build-backend = "hatchling.build"
3
- requires = ["hatchling"]
4
-
5
- [project]
6
- dependencies = ["tomli>=2.4.0; python_version<'3.11'"]
7
- description = "Single File commands for Interactive python."
8
- name = "pysfi"
9
- readme = "README.md"
10
- requires-python = ">=3.8"
11
- version = "0.1.11"
12
-
13
- [project.scripts]
14
- alarmclk = "sfi.alarmclock.alarmclock:main"
15
- bumpversion = "sfi.bumpversion.bumpversion:main"
16
- cleanbuild = "sfi.cleanbuild.cleanbuild:main"
17
- condasetup = "sfi.condasetup.condasetup:main"
18
- docscan = "sfi.docscan.docscan:main"
19
- docscan-gui = "sfi.docscan.docscan_gui:main"
20
- filedate = "sfi.filedate.filedate:main"
21
- gitt = "sfi.gittool.gittool:main"
22
- llmcli = "sfi.llmclient.llmclient:main"
23
- llmqnt = "sfi.llmquantize.llmquantize:main"
24
- llmsvr = "sfi.llmserver.llmserver:main"
25
- mkp = "sfi.makepython.makepython:main"
26
- pdfsplit = "sfi.pdfsplit.pdfsplit:main"
27
- pyarchive = "sfi.pyarchive.pyarchive:main"
28
- pyembedinstall = "sfi.pyembedinstall.pyembedinstall:main"
29
- pylibpack = "sfi.pylibpack.pylibpack:main"
30
- pyloadergen = "sfi.pyloadergen.pyloadergen:main"
31
- pyp = "sfi.pypack.pypack:main"
32
- pypack = "sfi.pypack.pypack:main"
33
- pyprojectparse = "sfi.pyprojectparse.pyprojectparse:main"
34
- pysourcepack = "sfi.pysourcepack.pysourcepack:main"
35
- quizbase = "sfi.quizbase.quizbase:main"
36
- quizbase-gui = "sfi.quizbase.quizbase_gui:main"
37
- regval = "sfi.regexvalidate.regexvalidate:main"
38
- sfi = "sfi.cli:main"
39
- taskk = "sfi.taskkill.taskkill:main"
40
- wch = "sfi.which.which:main"
41
-
42
- [project.optional-dependencies]
43
- all = ["pysfi[gui,office,ocr,extra]"]
44
- extra = ["ebooklib>=0.18", "markdown>=3.5", "odfpy>=1.4.1", "pypdf>=3.0.0"]
45
- gui = ["PySide2>=5.15.2.1", "pyside2-stubs>=5.15.2.1.2"]
46
- ocr = ["Pillow>=10.0.0", "pytesseract>=0.3.10"]
47
- office = [
48
- "openpyxl>=3.1.0",
49
- "pymupdf>=1.24.11",
50
- "python-docx>=1.1.0",
51
- "python-pptx>=0.6.21",
52
- ]
53
-
54
- [tool.hatch.build.targets.wheel]
55
- exclude = [
56
- "sfi/*/README.md",
57
- "sfi/*/dist",
58
- "sfi/*/pyproject.toml",
59
- "sfi/*/tests",
60
- ]
61
- packages = ["sfi"]
62
-
63
- # Only include necessary source files to minimize package size
64
- [tool.hatch.build]
65
- include = ["README.md", "sfi/**/*.py", "sfi/pyproject.toml"]
66
-
67
- [tool.ruff]
68
- line-length = 88
69
- target-version = "py38"
70
-
71
- # Exclude files and directories
72
- exclude = [
73
- ".bzr",
74
- ".direnv",
75
- ".eggs",
76
- ".git",
77
- ".git-rewrite",
78
- ".hg",
79
- ".mypy_cache",
80
- ".nox",
81
- ".pants.d",
82
- ".pytype",
83
- ".ruff_cache",
84
- ".svn",
85
- ".tox",
86
- ".venv",
87
- "__pypackages__",
88
- "_build",
89
- "buck-out",
90
- "build",
91
- "dist",
92
- "node_modules",
93
- "venv",
94
- ]
95
-
96
- [tool.ruff.lint]
97
- dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
98
- fixable = ["ALL"]
99
- ignore = [
100
- "B008", # Do not perform function calls in function arguments
101
- "E501", # Line too long (handled by formatter)
102
- "RUF001", # Language specific rules
103
- "RUF002", # Language specific rules
104
- "RUF003", # Language specific rules
105
- ]
106
- select = [
107
- "B", # flake8-bugbear
108
- "C4", # flake8-comprehensions
109
- "E", # pycodestyle errors
110
- "F", # Pyflakes
111
- "I", # isort
112
- "N", # pep8-naming
113
- "RUF", # Ruff-specific rules
114
- "SIM", # flake8-simplify
115
- "UP", # pyupgrade
116
- "W", # pycodestyle warnings
117
- ]
118
- unfixable = []
119
-
120
- [tool.ruff.lint.isort]
121
- known-first-party = ["sfi"]
122
-
123
- [tool.ruff.lint.per-file-ignores]
124
- "__init__.py" = ["F401"] # Allow unused imports
125
-
126
- [tool.uv.workspace]
127
- members = [
128
- "sfi/alarmclock",
129
- "sfi/bumpversion",
130
- "sfi/cleanbuild",
131
- "sfi/condasetup",
132
- "sfi/docscan",
133
- "sfi/filedate",
134
- "sfi/gittool",
135
- "sfi/llmclient",
136
- "sfi/llmquantize",
137
- "sfi/llmserver",
138
- "sfi/makepython",
139
- "sfi/pdfsplit",
140
- "sfi/pyarchive",
141
- "sfi/pyembedinstall",
142
- "sfi/pylibpack",
143
- "sfi/pyloadergen",
144
- "sfi/pypack",
145
- "sfi/pyprojectparse",
146
- "sfi/pysourcepack",
147
- "sfi/quizbase",
148
- "sfi/regexvalidate",
149
- "sfi/taskkill",
150
- "sfi/which",
151
- "sfi/workflowengine",
152
- ]
153
-
154
- [dependency-groups]
155
- dev = [
156
- "hatch>=1.14.2",
157
- "hypothesis>=6.113.0",
158
- "pysfi[all]",
159
- "pyside2>=5.15.2.1",
160
- "pytest-asyncio>=0.24.0",
161
- "pytest-benchmark>=4.0.0",
162
- "pytest-cov>=5.0.0",
163
- "pytest-mock>=3.14.0",
164
- "pytest-qt>=4.4.0",
165
- "pytest>=8.3.5",
166
- "qdarkstyle>=3.2.3",
167
- "ruff>=0.14.11",
168
- "tomli>=2.4.0",
169
- ]
1
+ [build-system]
2
+ build-backend = "hatchling.build"
3
+ requires = ["hatchling"]
4
+
5
+ [project]
6
+ dependencies = ["tomli>=2.4.0; python_version<'3.11'"]
7
+ description = "Single File commands for Interactive python."
8
+ name = "pysfi"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ version = "0.1.13"
12
+
13
+ [project.scripts]
14
+ alarmclk = "sfi.alarmclock.alarmclock:main"
15
+ bumpversion = "sfi.bumpversion.bumpversion:main"
16
+ cleanbuild = "sfi.cleanbuild.cleanbuild:main"
17
+ condasetup = "sfi.condasetup.condasetup:main"
18
+ docdiff = "sfi.docdiff.docdiff:main"
19
+ docscan = "sfi.docscan.docscan:main"
20
+ docscan-gui = "sfi.docscan.docscan_gui:main"
21
+ filedate = "sfi.filedate.filedate:main"
22
+ gitt = "sfi.gittool.gittool:main"
23
+ img2pdf = "sfi.img2pdf.img2pdf:main"
24
+ llmcli = "sfi.llmclient.llmclient:main"
25
+ llmqnt = "sfi.llmquantize.llmquantize:main"
26
+ llmsvr = "sfi.llmserver.llmserver:main"
27
+ mkp = "sfi.makepython.makepython:main"
28
+ pdfsplit = "sfi.pdfsplit.pdfsplit:main"
29
+ pyarchive = "sfi.pyarchive.pyarchive:main"
30
+ pyembedinstall = "sfi.pyembedinstall.pyembedinstall:main"
31
+ pylibpack = "sfi.pylibpack.pylibpack:main"
32
+ pyloadergen = "sfi.pyloadergen.pyloadergen:main"
33
+ pyp = "sfi.pypack.pypack:main"
34
+ pypack = "sfi.pypack.pypack:main"
35
+ pypp = "sfi.pyprojectparse.pyprojectparse:main"
36
+ pyprojectparse = "sfi.pyprojectparse.pyprojectparse:main"
37
+ pysourcepack = "sfi.pysourcepack.pysourcepack:main"
38
+ quizbase = "sfi.quizbase.quizbase:main"
39
+ quizbase-gui = "sfi.quizbase.quizbase_gui:main"
40
+ regval = "sfi.regexvalidate.regexvalidate:main"
41
+ sfi = "sfi.cli:main"
42
+ taskk = "sfi.taskkill.taskkill:main"
43
+ wch = "sfi.which.which:main"
44
+
45
+ [project.optional-dependencies]
46
+ all = ["pysfi[gui,office,ocr,extra]"]
47
+ extra = ["ebooklib>=0.18", "markdown>=3.5", "odfpy>=1.4.1", "pypdf>=3.0.0"]
48
+ gui = ["PySide2>=5.15.2.1", "pyside2-stubs>=5.15.2.1.2"]
49
+ ocr = ["Pillow>=10.0.0", "pytesseract>=0.3.10"]
50
+ office = [
51
+ "openpyxl>=3.1.0",
52
+ "pymupdf>=1.24.11",
53
+ "python-docx>=1.1.0",
54
+ "python-pptx>=0.6.21",
55
+ "pywin32>=311; sys.platform=='win32'",
56
+ ]
57
+
58
+ [tool.hatch.build.targets.wheel]
59
+ exclude = [
60
+ "sfi/*/README.md",
61
+ "sfi/*/dist",
62
+ "sfi/*/pyproject.toml",
63
+ "sfi/*/tests",
64
+ ]
65
+ packages = ["sfi"]
66
+
67
+ # Only include necessary source files to minimize package size
68
+ [tool.hatch.build]
69
+ include = ["README.md", "sfi/**/*.py", "sfi/pyproject.toml"]
70
+
71
+ [tool.ruff]
72
+ line-length = 88
73
+ target-version = "py38"
74
+
75
+ # Exclude files and directories
76
+ exclude = [
77
+ ".bzr",
78
+ ".direnv",
79
+ ".eggs",
80
+ ".git",
81
+ ".git-rewrite",
82
+ ".hg",
83
+ ".mypy_cache",
84
+ ".nox",
85
+ ".pants.d",
86
+ ".pytype",
87
+ ".ruff_cache",
88
+ ".svn",
89
+ ".tox",
90
+ ".venv",
91
+ "__pypackages__",
92
+ "_build",
93
+ "buck-out",
94
+ "build",
95
+ "dist",
96
+ "node_modules",
97
+ "venv",
98
+ ]
99
+
100
+ [tool.ruff.lint]
101
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
102
+ fixable = ["ALL"]
103
+ ignore = [
104
+ "B008", # Do not perform function calls in function arguments
105
+ "E501", # Line too long (handled by formatter)
106
+ "RUF001", # Language specific rules
107
+ "RUF002", # Language specific rules
108
+ "RUF003", # Language specific rules
109
+ ]
110
+ select = [
111
+ "B", # flake8-bugbear
112
+ "C4", # flake8-comprehensions
113
+ "E", # pycodestyle errors
114
+ "F", # Pyflakes
115
+ "I", # isort
116
+ "N", # pep8-naming
117
+ "RUF", # Ruff-specific rules
118
+ "SIM", # flake8-simplify
119
+ "UP", # pyupgrade
120
+ "W", # pycodestyle warnings
121
+ ]
122
+ unfixable = []
123
+
124
+ [tool.ruff.lint.isort]
125
+ known-first-party = ["sfi"]
126
+
127
+ [tool.ruff.lint.per-file-ignores]
128
+ "__init__.py" = ["F401"] # Allow unused imports
129
+
130
+ [tool.uv.workspace]
131
+ members = [
132
+ "sfi/alarmclock",
133
+ "sfi/bumpversion",
134
+ "sfi/cleanbuild",
135
+ "sfi/condasetup",
136
+ "sfi/docdiff",
137
+ "sfi/docscan",
138
+ "sfi/filedate",
139
+ "sfi/gittool",
140
+ "sfi/img2pdf",
141
+ "sfi/llmclient",
142
+ "sfi/llmquantize",
143
+ "sfi/llmserver",
144
+ "sfi/makepython",
145
+ "sfi/pdfsplit",
146
+ "sfi/pyarchive",
147
+ "sfi/pyembedinstall",
148
+ "sfi/pylibpack",
149
+ "sfi/pyloadergen",
150
+ "sfi/pypack",
151
+ "sfi/pyprojectparse",
152
+ "sfi/pysourcepack",
153
+ "sfi/quizbase",
154
+ "sfi/regexvalidate",
155
+ "sfi/taskkill",
156
+ "sfi/which",
157
+ "sfi/workflowengine",
158
+ ]
159
+
160
+ [dependency-groups]
161
+ dev = [
162
+ "hatch>=1.14.2",
163
+ "hypothesis>=6.113.0",
164
+ "pysfi[all]",
165
+ "pyside2>=5.15.2.1",
166
+ "pytest-asyncio>=0.24.0",
167
+ "pytest-benchmark>=4.0.0",
168
+ "pytest-cov>=5.0.0",
169
+ "pytest-mock>=3.14.0",
170
+ "pytest-qt>=4.4.0",
171
+ "pytest>=8.3.5",
172
+ "qdarkstyle>=3.2.3",
173
+ "ruff>=0.14.11",
174
+ "tomli>=2.4.0",
175
+ ]
@@ -0,0 +1,5 @@
1
+ """Single File commands for Interactive python."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "0.1.13"
@@ -0,0 +1,117 @@
1
+ # Alarm Clock
2
+
3
+ A digital alarm clock application with a graphical user interface built using PySide2. Features include configurable alarms, digital time display, visual notifications, alarm history, and advanced configuration options.
4
+
5
+ ## Features
6
+
7
+ - **Digital clock display** with animated border effects and customizable styling
8
+ - **Configurable alarm time setting** with precise time selection
9
+ - **Quick delay options** (1, 5, 10, 15, 30, 60 minutes) for fast alarm setup
10
+ - **Repeat alarm functionality** for daily recurring alarms
11
+ - **Snooze feature** with configurable snooze duration and count limits
12
+ - **Multiple visual notification effects** including color, opacity, and combined animations
13
+
14
+ - **Alarm history tracking** with statistics and recent activity
15
+ - **Dark theme interface** with modern styling
16
+ - **Persistent configuration** with automatic saving and loading
17
+ - **Advanced settings** including window behavior, logging, and performance options
18
+
19
+ ## Installation
20
+
21
+ Install the required dependencies:
22
+
23
+ ```bash
24
+ pip install -e .
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ Run the alarm clock application:
30
+
31
+ ```bash
32
+ alarmclk
33
+ ```
34
+
35
+ Or directly with Python:
36
+
37
+ ```bash
38
+ python -m sfi.alarmclock
39
+ ```
40
+
41
+ ### Command Line Options
42
+
43
+ - `-d, --debug`: Enable debug mode with verbose logging
44
+ - `-v, --version`: Show version information
45
+ - `--config PATH`: Use custom configuration file
46
+ - `--reset-config`: Reset configuration to defaults
47
+
48
+ ### Configuration
49
+
50
+ The application creates configuration files in `~/.pysfi/alarmclock/`:
51
+
52
+ - `config.json`: Main configuration settings
53
+ - `history.json`: Alarm history and statistics
54
+ - `alarmclock.log`: Application logs
55
+
56
+ Configuration can be customized through the config file or programmatically.
57
+
58
+ ## Configuration Parameters
59
+
60
+ The application uses the following configuration parameters:
61
+
62
+ - **Digital Clock**: Displays current time with animated border colors
63
+ - **Alarm Time**: Set specific time for the alarm to trigger
64
+ - **Delay Options**: Quick buttons to set alarms for specific intervals
65
+ - **Repeat Option**: Enable/disable alarm repetition
66
+ - **Visual Notifications**: Alert dialog with blinking effect
67
+
68
+ ## Architecture
69
+
70
+ The application follows a modular design:
71
+
72
+ - `AlarmClockConfig`: Configuration dataclass with all application settings
73
+ - `DigitalClock`: Widget displaying current time with animation
74
+ - `BlinkDialog`: Notification dialog with visual effects
75
+ - `AlarmClock`: Main application window with GUI controls
76
+
77
+ ## Testing
78
+
79
+ The module includes comprehensive tests divided into two categories:
80
+
81
+ ### Core Tests (Non-GUI)
82
+
83
+ ```bash
84
+ python -m pytest sfi/alarmclock/tests/test_alarmclock_core.py -v
85
+ ```
86
+
87
+ Tests configuration, data classes, enums, and core logic without requiring a GUI environment.
88
+
89
+ ### GUI Tests
90
+
91
+ ```bash
92
+ python -m pytest sfi/alarmclock/tests/test_alarmclock_gui.py -v -m qt
93
+ ```
94
+
95
+ Tests GUI components using pytest-qt. These tests require a working Qt environment.
96
+
97
+ ### Benchmark Tests
98
+
99
+ ```bash
100
+ python -m pytest sfi/alarmclock/tests/test_benchmark.py -v
101
+ ```
102
+
103
+ Performance benchmarks for critical operations.
104
+
105
+ ### Run All Tests
106
+
107
+ ```bash
108
+ python -m pytest sfi/alarmclock/tests/ -v
109
+ ```
110
+
111
+ ## Dependencies
112
+
113
+ - PySide2: GUI framework
114
+ - qdarkstyle: Dark theme styling
115
+ - typing-extensions: Type hinting support for older Python versions
116
+ - pytest: Testing framework
117
+ - pytest-qt: Qt testing utilities
@@ -0,0 +1,3 @@
1
+ """Alarm clock module for pysfi."""
2
+
3
+ from __future__ import annotations
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import argparse
4
3
  import logging
5
4
  import random
6
5
  import sys
@@ -8,7 +7,6 @@ from dataclasses import dataclass
8
7
  from datetime import datetime, timedelta, timezone
9
8
  from functools import partial
10
9
 
11
- import qdarkstyle
12
10
  from PySide2.QtCore import QSize, Qt, QTime, QTimer
13
11
  from PySide2.QtGui import QCloseEvent
14
12
  from PySide2.QtWidgets import (
@@ -28,7 +26,7 @@ __version__ = "0.1.3"
28
26
  __build_date__ = "2026-01-22"
29
27
 
30
28
 
31
- @dataclass(frozen=True)
29
+ @dataclass
32
30
  class AlarmClockConfig:
33
31
  """Configuration for the alarm clock application."""
34
32
 
@@ -87,9 +85,9 @@ class DigitalClock(QLabel):
87
85
  logger.debug(f"Updated time: {current}")
88
86
 
89
87
  # Add blink effect
90
- self._color = random.choice(
91
- [_ for _ in config.DIGITAL_BORDER_COLORS if _ != self._color],
92
- )
88
+ self._color = random.choice([
89
+ c for c in config.DIGITAL_BORDER_COLORS if c != self._color
90
+ ])
93
91
  self.setStyleSheet(f"""
94
92
  font: {config.DIGITAL_FONT};
95
93
  color: {config.DIGITAL_COLOR};
@@ -112,6 +110,7 @@ class BlinkDialog(QDialog):
112
110
  self.windowFlags() | Qt.WindowStaysOnTopHint | Qt.WindowType.Dialog,
113
111
  )
114
112
  self.setFixedSize(QSize(400, 240))
113
+ self.setWindowFlag(Qt.WindowCloseButtonHint, False)
115
114
 
116
115
  layout = QVBoxLayout()
117
116
  msg_label = QLabel(config.BLINK_CONTENT)
@@ -122,32 +121,28 @@ class BlinkDialog(QDialog):
122
121
  msg_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
123
122
 
124
123
  close_button = QPushButton("Close Alarm")
125
- close_button.clicked.connect(self.accept)
124
+ close_button.clicked.connect(self.close_alarm)
126
125
 
127
126
  layout.addWidget(msg_label)
128
127
  layout.addWidget(close_button)
129
128
  self.setLayout(layout)
130
129
 
131
- # Prevent user from closing dialog by other means, ensure button click only
132
- self.setWindowFlag(Qt.WindowCloseButtonHint, False)
133
-
134
130
  # Blink control variables and timer
135
131
  self.blink_timer = QTimer(self)
136
132
  self.blink_timer.timeout.connect(self.update_blink)
137
133
  self.blink_state = False
138
134
  self.blink_type = config.BLINK_TYPE
139
-
140
- # Initialize style
141
135
  self.bg_color = random.choice(config.BLINK_BG_COLORS)
142
- self.origin_style = self.styleSheet()
143
136
  self.blink_timer.start(config.BLINK_INTERVAL)
144
137
 
145
138
  def update_blink(self) -> None:
146
139
  """Timer timeout, update blink state."""
147
140
  if self.blink_type == "color":
148
141
  # Color blink logic
149
- colors = [_ for _ in config.BLINK_BG_COLORS[:] if _ != self.bg_color]
150
- self.setStyleSheet(f"background-color: {random.choice(colors)}")
142
+ colors = [c for c in config.BLINK_BG_COLORS if c != self.bg_color]
143
+ new_color = random.choice(colors)
144
+ self.setStyleSheet(f"background-color: {new_color}")
145
+ self.bg_color = new_color
151
146
  elif self.blink_type == "opacity":
152
147
  # Opacity blink logic - Note: Some systems may not fully support window opacity
153
148
  new_opacity = 0.3 if self.blink_state else 1.0
@@ -155,10 +150,14 @@ class BlinkDialog(QDialog):
155
150
 
156
151
  self.blink_state = not self.blink_state # Toggle state
157
152
 
153
+ def close_alarm(self) -> None:
154
+ """Close alarm dialog and stop blinking."""
155
+ self.stop_blinking()
156
+ self.accept()
157
+
158
158
  def stop_blinking(self) -> None:
159
- """Stop blinking, restore original style."""
159
+ """Stop blinking."""
160
160
  self.blink_timer.stop()
161
- self.setStyleSheet(self.origin_style) # Restore original style
162
161
  self.setWindowOpacity(1.0) # Ensure opacity is restored
163
162
 
164
163
  def closeEvent(self, event: QCloseEvent) -> None: # noqa: N802
@@ -173,13 +172,6 @@ class AlarmClock(QMainWindow):
173
172
  def __init__(self) -> None:
174
173
  super().__init__()
175
174
  self.setWindowTitle(f"{config.ALARM_CLOCK_TITLE} v{__version__}")
176
- self.setGeometry(
177
- QApplication.desktop().screenGeometry().center().x() - self.width() // 4,
178
- QApplication.desktop().screenGeometry().center().y() - self.height() // 2,
179
- self.width(),
180
- self.height(),
181
- )
182
- self.adjustSize()
183
175
 
184
176
  # Set window style
185
177
  self.setStyleSheet("""
@@ -277,6 +269,13 @@ class AlarmClock(QMainWindow):
277
269
  self.status_label.setStyleSheet("color: #aaaaaa; font-size: 16px;")
278
270
  main_layout.addWidget(self.status_label)
279
271
 
272
+ # Center window on screen
273
+ self.adjustSize()
274
+ screen = QApplication.desktop().screenGeometry()
275
+ x = (screen.width() - self.width()) // 2
276
+ y = (screen.height() - self.height()) // 2
277
+ self.move(x, y)
278
+
280
279
  # Alarm timer
281
280
  self.alarm_timer = QTimer()
282
281
  self.alarm_timer.timeout.connect(self.check_alarm)
@@ -330,11 +329,6 @@ class AlarmClock(QMainWindow):
330
329
  dialog.exec_()
331
330
 
332
331
  self.status_label.setText("⏰ Alarm Rang! ⏰")
333
- self.status_label.setStyleSheet(
334
- "color: #ff5555; font-size: 18px; font-weight: bold;",
335
- )
336
-
337
- # Add blink effect
338
332
  self.status_label.setStyleSheet("""
339
333
  color: #ff0000;
340
334
  font-size: 18px;
@@ -350,18 +344,7 @@ class AlarmClock(QMainWindow):
350
344
 
351
345
 
352
346
  def main() -> None:
353
- parser = argparse.ArgumentParser(
354
- prog="alarmclock", description="Digital Alarm Clock"
355
- )
356
- parser.add_argument("-d", "--debug", action="store_true", help="Enable debug mode")
357
- parser.add_argument("-v", "--version", action="version", version=f"{__version__}")
358
-
359
- args = parser.parse_args()
360
- if args.debug:
361
- logger.setLevel(logging.DEBUG)
362
-
363
347
  app = QApplication(sys.argv)
364
- app.setStyleSheet(qdarkstyle.load_stylesheet_pyside2())
365
348
  window = AlarmClock()
366
349
  window.show()
367
350
  sys.exit(app.exec_())
@@ -0,0 +1,5 @@
1
+ """Bumpversion - Automated version number management tool."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "0.1.13"
@@ -0,0 +1,3 @@
1
+ """Cleanbuild - Clean build artifacts and temporary files."""
2
+
3
+ from __future__ import annotations