pysfi 0.1.7__py3-none-any.whl → 0.1.11__py3-none-any.whl
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.
- {pysfi-0.1.7.dist-info → pysfi-0.1.11.dist-info}/METADATA +11 -9
- pysfi-0.1.11.dist-info/RECORD +60 -0
- pysfi-0.1.11.dist-info/entry_points.txt +28 -0
- sfi/__init__.py +1 -1
- sfi/alarmclock/alarmclock.py +40 -40
- sfi/bumpversion/__init__.py +1 -1
- sfi/cleanbuild/cleanbuild.py +155 -0
- sfi/condasetup/condasetup.py +116 -0
- sfi/docscan/__init__.py +1 -1
- sfi/docscan/docscan.py +407 -103
- sfi/docscan/docscan_gui.py +1282 -596
- sfi/docscan/lang/eng.py +152 -0
- sfi/docscan/lang/zhcn.py +170 -0
- sfi/filedate/filedate.py +185 -112
- sfi/gittool/__init__.py +2 -0
- sfi/gittool/gittool.py +401 -0
- sfi/llmclient/llmclient.py +592 -0
- sfi/llmquantize/llmquantize.py +480 -0
- sfi/llmserver/llmserver.py +335 -0
- sfi/makepython/makepython.py +31 -30
- sfi/pdfsplit/pdfsplit.py +173 -173
- sfi/pyarchive/pyarchive.py +418 -0
- sfi/pyembedinstall/pyembedinstall.py +629 -0
- sfi/pylibpack/__init__.py +0 -0
- sfi/pylibpack/pylibpack.py +1457 -0
- sfi/pylibpack/rules/numpy.json +22 -0
- sfi/pylibpack/rules/pymupdf.json +10 -0
- sfi/pylibpack/rules/pyqt5.json +19 -0
- sfi/pylibpack/rules/pyside2.json +23 -0
- sfi/pylibpack/rules/scipy.json +23 -0
- sfi/pylibpack/rules/shiboken2.json +24 -0
- sfi/pyloadergen/pyloadergen.py +512 -227
- sfi/pypack/__init__.py +0 -0
- sfi/pypack/pypack.py +1142 -0
- sfi/pyprojectparse/__init__.py +0 -0
- sfi/pyprojectparse/pyprojectparse.py +500 -0
- sfi/pysourcepack/pysourcepack.py +308 -0
- sfi/quizbase/__init__.py +0 -0
- sfi/quizbase/quizbase.py +828 -0
- sfi/quizbase/quizbase_gui.py +987 -0
- sfi/regexvalidate/__init__.py +0 -0
- sfi/regexvalidate/regex_help.html +284 -0
- sfi/regexvalidate/regexvalidate.py +468 -0
- sfi/taskkill/taskkill.py +0 -2
- sfi/workflowengine/__init__.py +0 -0
- sfi/workflowengine/workflowengine.py +444 -0
- pysfi-0.1.7.dist-info/RECORD +0 -31
- pysfi-0.1.7.dist-info/entry_points.txt +0 -15
- sfi/embedinstall/embedinstall.py +0 -418
- sfi/projectparse/projectparse.py +0 -152
- sfi/pypacker/fspacker.py +0 -91
- {pysfi-0.1.7.dist-info → pysfi-0.1.11.dist-info}/WHEEL +0 -0
- /sfi/{embedinstall → docscan/lang}/__init__.py +0 -0
- /sfi/{projectparse → llmquantize}/__init__.py +0 -0
- /sfi/{pypacker → pyembedinstall}/__init__.py +0 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""Source code packaging tool for projects defined in projects.json."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import logging
|
|
7
|
+
import shutil
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
__version__ = "0.1.0"
|
|
11
|
+
__all__ = [
|
|
12
|
+
"pack_project",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
cwd = Path.cwd()
|
|
16
|
+
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
# Default directories and files to exclude during packaging
|
|
20
|
+
DEFAULT_EXCLUDE = {
|
|
21
|
+
"__pycache__",
|
|
22
|
+
"*.pyc",
|
|
23
|
+
"*.pyo",
|
|
24
|
+
".pytest_cache",
|
|
25
|
+
".benchmarks",
|
|
26
|
+
"tests",
|
|
27
|
+
".git",
|
|
28
|
+
".gitignore",
|
|
29
|
+
"dist",
|
|
30
|
+
"build",
|
|
31
|
+
"*.egg-info",
|
|
32
|
+
"node_modules",
|
|
33
|
+
".idea",
|
|
34
|
+
"*.log",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Default files to include in packaging
|
|
38
|
+
DEFAULT_INCLUDE = {
|
|
39
|
+
"*.py",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE",
|
|
42
|
+
"pyproject.toml",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def should_exclude(path: Path, exclude_patterns: set[str]) -> bool:
|
|
47
|
+
"""Check if a path should be excluded based on patterns.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
path: Path to check
|
|
51
|
+
exclude_patterns: Set of patterns to exclude
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
True if path should be excluded, False otherwise
|
|
55
|
+
"""
|
|
56
|
+
for pattern in exclude_patterns:
|
|
57
|
+
if pattern.startswith("*"):
|
|
58
|
+
# Wildcard pattern (e.g., "*.pyc")
|
|
59
|
+
if path.match(pattern):
|
|
60
|
+
return True
|
|
61
|
+
else:
|
|
62
|
+
# Exact name pattern
|
|
63
|
+
if path.name == pattern:
|
|
64
|
+
return True
|
|
65
|
+
if path.parts:
|
|
66
|
+
# Check if any parent directory matches
|
|
67
|
+
for part in path.parts:
|
|
68
|
+
if part == pattern:
|
|
69
|
+
return True
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def should_include(
|
|
74
|
+
path: Path, include_patterns: set[str], exclude_patterns: set[str]
|
|
75
|
+
) -> bool:
|
|
76
|
+
"""Check if a path should be included based on include and exclude patterns.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
path: Path to check
|
|
80
|
+
include_patterns: Set of patterns to include
|
|
81
|
+
exclude_patterns: Set of patterns to exclude
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
True if path should be included, False otherwise
|
|
85
|
+
"""
|
|
86
|
+
# Check if should be excluded first
|
|
87
|
+
if should_exclude(path, exclude_patterns):
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
# If no include patterns, include everything not excluded
|
|
91
|
+
if not include_patterns:
|
|
92
|
+
return True
|
|
93
|
+
|
|
94
|
+
# Check if matches any include pattern
|
|
95
|
+
for pattern in include_patterns:
|
|
96
|
+
if pattern.startswith("*"):
|
|
97
|
+
# Wildcard pattern (e.g., "*.py")
|
|
98
|
+
if path.match(pattern):
|
|
99
|
+
return True
|
|
100
|
+
else:
|
|
101
|
+
# Exact name pattern
|
|
102
|
+
if path.name == pattern:
|
|
103
|
+
return True
|
|
104
|
+
if path.is_dir() and path.name == pattern:
|
|
105
|
+
# Include directory and all its contents
|
|
106
|
+
return True
|
|
107
|
+
|
|
108
|
+
return False
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _check_project_path(project_path: Path) -> bool:
|
|
112
|
+
if not project_path.exists():
|
|
113
|
+
logger.error(f"Project directory {project_path} does not exist")
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
if not project_path.is_dir():
|
|
117
|
+
logger.error(f"{project_path} is not a directory")
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
return True
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def pack_project(
|
|
124
|
+
base_dir: Path,
|
|
125
|
+
projects: dict,
|
|
126
|
+
project_name: str,
|
|
127
|
+
include_patterns: set[str] | None = None,
|
|
128
|
+
exclude_patterns: set[str] | None = None,
|
|
129
|
+
) -> bool:
|
|
130
|
+
"""Pack project source code and resources to dist/src directory.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
base_dir: Base directory containing project folders
|
|
134
|
+
project_name: Name of the project to pack
|
|
135
|
+
include_patterns: File patterns to include (default: DEFAULT_INCLUDE)
|
|
136
|
+
exclude_patterns: File patterns to exclude (default: DEFAULT_EXCLUDE)
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
True if packing succeeded, False otherwise
|
|
140
|
+
"""
|
|
141
|
+
logger.debug(f"Start packing project: {project_name}")
|
|
142
|
+
|
|
143
|
+
if project_name not in projects:
|
|
144
|
+
logger.error(f"Project '{project_name}' not found in projects.json")
|
|
145
|
+
return False
|
|
146
|
+
|
|
147
|
+
if not project_name:
|
|
148
|
+
logger.error("Project name cannot be empty")
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
project_path = base_dir if len(projects) == 1 else base_dir / project_name
|
|
152
|
+
output_dir = base_dir / "dist" / "src" / project_name
|
|
153
|
+
|
|
154
|
+
logger.debug(f"Project path: {project_path}, project_name: {project_name}")
|
|
155
|
+
if not _check_project_path(project_path):
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
159
|
+
|
|
160
|
+
# Use default patterns if not specified
|
|
161
|
+
if include_patterns is None:
|
|
162
|
+
include_patterns = DEFAULT_INCLUDE
|
|
163
|
+
if exclude_patterns is None:
|
|
164
|
+
exclude_patterns = DEFAULT_EXCLUDE
|
|
165
|
+
|
|
166
|
+
# Copy files
|
|
167
|
+
copied_files = 0
|
|
168
|
+
copied_dirs = 0
|
|
169
|
+
|
|
170
|
+
logger.info(f"Packing project '{project_name}' to {output_dir}")
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
for item in project_path.iterdir():
|
|
174
|
+
if item.is_file():
|
|
175
|
+
# For files, check if should be included
|
|
176
|
+
if should_include(item, include_patterns, exclude_patterns):
|
|
177
|
+
dest_file = output_dir / item.name
|
|
178
|
+
shutil.copy2(item, dest_file)
|
|
179
|
+
logger.debug(f"Copied file: {item.name}")
|
|
180
|
+
copied_files += 1
|
|
181
|
+
elif item.is_dir() and not should_exclude(item, exclude_patterns):
|
|
182
|
+
# Copy directory recursively with exclude patterns
|
|
183
|
+
dest_dir = output_dir / item.name
|
|
184
|
+
if dest_dir.exists():
|
|
185
|
+
shutil.rmtree(dest_dir)
|
|
186
|
+
shutil.copytree(
|
|
187
|
+
item, dest_dir, ignore=shutil.ignore_patterns(*DEFAULT_EXCLUDE)
|
|
188
|
+
)
|
|
189
|
+
logger.debug(f"Copied directory: {item.name}")
|
|
190
|
+
copied_dirs += 1
|
|
191
|
+
|
|
192
|
+
logger.info(
|
|
193
|
+
f"Successfully packed {project_name}: {copied_files} files, {copied_dirs} directories"
|
|
194
|
+
)
|
|
195
|
+
return True
|
|
196
|
+
|
|
197
|
+
except Exception as e:
|
|
198
|
+
logger.error(f"Error packing project {project_name}: {e}")
|
|
199
|
+
return False
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def create_parser() -> argparse.ArgumentParser:
|
|
203
|
+
"""Create and return an argument parser for the PySourcePack tool."""
|
|
204
|
+
parser = argparse.ArgumentParser(
|
|
205
|
+
description="PySourcePack - Source code packaging tool",
|
|
206
|
+
epilog="Pack source code and resources for projects defined in projects.json",
|
|
207
|
+
)
|
|
208
|
+
parser.add_argument(
|
|
209
|
+
"directory",
|
|
210
|
+
default=str(cwd),
|
|
211
|
+
nargs="?",
|
|
212
|
+
help="Base directory containing project folders (default: current directory)",
|
|
213
|
+
)
|
|
214
|
+
parser.add_argument(
|
|
215
|
+
"-p",
|
|
216
|
+
"--project",
|
|
217
|
+
default=None,
|
|
218
|
+
help="Project name to pack (default: pack all projects)",
|
|
219
|
+
)
|
|
220
|
+
parser.add_argument(
|
|
221
|
+
"-l",
|
|
222
|
+
"--list",
|
|
223
|
+
action="store_true",
|
|
224
|
+
help="List all available projects",
|
|
225
|
+
)
|
|
226
|
+
parser.add_argument(
|
|
227
|
+
"--include",
|
|
228
|
+
nargs="*",
|
|
229
|
+
default=None,
|
|
230
|
+
help="File patterns to include (default: *.py, README.md, pyproject.toml)",
|
|
231
|
+
)
|
|
232
|
+
parser.add_argument(
|
|
233
|
+
"--exclude",
|
|
234
|
+
nargs="*",
|
|
235
|
+
default=None,
|
|
236
|
+
help="File patterns to exclude (default: __pycache__, *.pyc, tests, .benchmarks, etc.)",
|
|
237
|
+
)
|
|
238
|
+
parser.add_argument(
|
|
239
|
+
"--debug",
|
|
240
|
+
"-d",
|
|
241
|
+
action="store_true",
|
|
242
|
+
help="Enable debug mode",
|
|
243
|
+
)
|
|
244
|
+
return parser
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def main() -> None:
|
|
248
|
+
from sfi.pyprojectparse.pyprojectparse import Solution
|
|
249
|
+
|
|
250
|
+
parser = create_parser()
|
|
251
|
+
args = parser.parse_args()
|
|
252
|
+
|
|
253
|
+
if args.debug:
|
|
254
|
+
logger.setLevel(logging.DEBUG)
|
|
255
|
+
|
|
256
|
+
# Load projects file
|
|
257
|
+
base_dir = Path(args.directory)
|
|
258
|
+
project_json = base_dir / "projects.json"
|
|
259
|
+
projects = Solution.from_directory(base_dir, recursive=True, update=True).projects
|
|
260
|
+
|
|
261
|
+
if not project_json.exists():
|
|
262
|
+
logger.error("Failed to create projects.json")
|
|
263
|
+
return
|
|
264
|
+
|
|
265
|
+
if not projects:
|
|
266
|
+
logger.error("No projects found in projects.json")
|
|
267
|
+
return
|
|
268
|
+
|
|
269
|
+
if args.list:
|
|
270
|
+
logger.info("Available projects:")
|
|
271
|
+
for info in projects.values():
|
|
272
|
+
logger.info(info)
|
|
273
|
+
return
|
|
274
|
+
|
|
275
|
+
# Process include and exclude patterns
|
|
276
|
+
include_patterns = set(args.include) if args.include else None
|
|
277
|
+
exclude_patterns = set(args.exclude) if args.exclude else None
|
|
278
|
+
|
|
279
|
+
logger.debug(
|
|
280
|
+
f"Start packing, config: base_dir={base_dir}, project_name={args.project}, include_patterns={include_patterns}, exclude_patterns={exclude_patterns}"
|
|
281
|
+
)
|
|
282
|
+
# Pack specified project or all projects
|
|
283
|
+
if args.project:
|
|
284
|
+
if pack_project(
|
|
285
|
+
base_dir=base_dir,
|
|
286
|
+
projects=projects,
|
|
287
|
+
project_name=args.project,
|
|
288
|
+
include_patterns=include_patterns,
|
|
289
|
+
exclude_patterns=exclude_patterns,
|
|
290
|
+
):
|
|
291
|
+
logger.info(f"Packed project '{args.project}' successfully")
|
|
292
|
+
else:
|
|
293
|
+
logger.error(f"Failed to pack project '{args.project}'")
|
|
294
|
+
return
|
|
295
|
+
|
|
296
|
+
# Pack all projects
|
|
297
|
+
logger.info("Packing all projects...")
|
|
298
|
+
success_count = 0
|
|
299
|
+
for project_name in projects:
|
|
300
|
+
if pack_project(
|
|
301
|
+
base_dir=base_dir,
|
|
302
|
+
projects=projects,
|
|
303
|
+
project_name=project_name,
|
|
304
|
+
include_patterns=include_patterns,
|
|
305
|
+
exclude_patterns=exclude_patterns,
|
|
306
|
+
):
|
|
307
|
+
success_count += 1
|
|
308
|
+
logger.info(f"Packed {success_count}/{len(projects)} projects successfully")
|
sfi/quizbase/__init__.py
ADDED
|
File without changes
|