fishertools 0.2.1__py3-none-any.whl → 0.4.0__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.
- fishertools/__init__.py +16 -5
- fishertools/errors/__init__.py +11 -3
- fishertools/errors/exception_types.py +282 -0
- fishertools/errors/explainer.py +87 -1
- fishertools/errors/models.py +73 -1
- fishertools/errors/patterns.py +40 -0
- fishertools/examples/cli_example.py +156 -0
- fishertools/examples/learn_example.py +65 -0
- fishertools/examples/logger_example.py +176 -0
- fishertools/examples/menu_example.py +101 -0
- fishertools/examples/storage_example.py +175 -0
- fishertools/input_utils.py +185 -0
- fishertools/learn/__init__.py +19 -2
- fishertools/learn/examples.py +88 -1
- fishertools/learn/knowledge_engine.py +321 -0
- fishertools/learn/repl/__init__.py +19 -0
- fishertools/learn/repl/cli.py +31 -0
- fishertools/learn/repl/code_sandbox.py +229 -0
- fishertools/learn/repl/command_handler.py +544 -0
- fishertools/learn/repl/command_parser.py +165 -0
- fishertools/learn/repl/engine.py +479 -0
- fishertools/learn/repl/models.py +121 -0
- fishertools/learn/repl/session_manager.py +284 -0
- fishertools/learn/repl/test_code_sandbox.py +261 -0
- fishertools/learn/repl/test_code_sandbox_pbt.py +148 -0
- fishertools/learn/repl/test_command_handler.py +224 -0
- fishertools/learn/repl/test_command_handler_pbt.py +189 -0
- fishertools/learn/repl/test_command_parser.py +160 -0
- fishertools/learn/repl/test_command_parser_pbt.py +100 -0
- fishertools/learn/repl/test_engine.py +190 -0
- fishertools/learn/repl/test_session_manager.py +310 -0
- fishertools/learn/repl/test_session_manager_pbt.py +182 -0
- fishertools/learn/test_knowledge_engine.py +241 -0
- fishertools/learn/test_knowledge_engine_pbt.py +180 -0
- fishertools/patterns/__init__.py +46 -0
- fishertools/patterns/cli.py +175 -0
- fishertools/patterns/logger.py +140 -0
- fishertools/patterns/menu.py +99 -0
- fishertools/patterns/storage.py +127 -0
- fishertools/readme_transformer.py +631 -0
- fishertools/safe/__init__.py +6 -1
- fishertools/safe/files.py +329 -1
- fishertools/transform_readme.py +105 -0
- fishertools-0.4.0.dist-info/METADATA +104 -0
- fishertools-0.4.0.dist-info/RECORD +131 -0
- {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/WHEEL +1 -1
- tests/test_documentation_properties.py +329 -0
- tests/test_documentation_structure.py +349 -0
- tests/test_errors/test_exception_types.py +446 -0
- tests/test_errors/test_exception_types_pbt.py +333 -0
- tests/test_errors/test_patterns.py +52 -0
- tests/test_input_utils/__init__.py +1 -0
- tests/test_input_utils/test_input_utils.py +65 -0
- tests/test_learn/test_examples.py +179 -1
- tests/test_learn/test_explain_properties.py +307 -0
- tests/test_patterns_cli.py +611 -0
- tests/test_patterns_docstrings.py +473 -0
- tests/test_patterns_logger.py +465 -0
- tests/test_patterns_menu.py +440 -0
- tests/test_patterns_storage.py +447 -0
- tests/test_readme_enhancements_v0_3_1.py +2036 -0
- tests/test_readme_transformer/__init__.py +1 -0
- tests/test_readme_transformer/test_readme_infrastructure.py +1023 -0
- tests/test_readme_transformer/test_transform_readme_integration.py +431 -0
- tests/test_safe/test_files.py +726 -1
- fishertools-0.2.1.dist-info/METADATA +0 -256
- fishertools-0.2.1.dist-info/RECORD +0 -81
- {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/top_level.txt +0 -0
fishertools/safe/files.py
CHANGED
|
@@ -237,4 +237,332 @@ def safe_list_files(directory: Union[str, Path], pattern: str = "*", default: Op
|
|
|
237
237
|
files = [f.name for f in directory_path.glob(pattern) if f.is_file()]
|
|
238
238
|
return sorted(files)
|
|
239
239
|
except (OSError, ValueError):
|
|
240
|
-
return default
|
|
240
|
+
return default
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def project_root(start_dir: Optional[Union[str, Path]] = None) -> str:
|
|
245
|
+
"""
|
|
246
|
+
Detect and return the project root directory.
|
|
247
|
+
|
|
248
|
+
Looks for markers: setup.py, pyproject.toml, .git, .gitignore
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
start_dir: Starting directory (default: current directory)
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
Path to project root
|
|
255
|
+
|
|
256
|
+
Raises:
|
|
257
|
+
RuntimeError: If project root cannot be determined
|
|
258
|
+
|
|
259
|
+
Examples:
|
|
260
|
+
>>> root = project_root()
|
|
261
|
+
>>> root = project_root("/path/to/subdir")
|
|
262
|
+
"""
|
|
263
|
+
if start_dir is None:
|
|
264
|
+
start_dir = Path.cwd()
|
|
265
|
+
else:
|
|
266
|
+
start_dir = Path(start_dir)
|
|
267
|
+
|
|
268
|
+
# Markers that indicate project root
|
|
269
|
+
markers = ['setup.py', 'pyproject.toml', '.git', '.gitignore']
|
|
270
|
+
|
|
271
|
+
current = start_dir.resolve()
|
|
272
|
+
|
|
273
|
+
# Walk up the directory tree
|
|
274
|
+
while True:
|
|
275
|
+
# Check if any marker exists in current directory
|
|
276
|
+
for marker in markers:
|
|
277
|
+
if (current / marker).exists():
|
|
278
|
+
return str(current)
|
|
279
|
+
|
|
280
|
+
# Move to parent directory
|
|
281
|
+
parent = current.parent
|
|
282
|
+
if parent == current:
|
|
283
|
+
# Reached filesystem root without finding project root
|
|
284
|
+
raise RuntimeError(f"Could not determine project root starting from {start_dir}")
|
|
285
|
+
|
|
286
|
+
current = parent
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def find_file(filename: str, start_dir: Optional[Union[str, Path]] = None) -> Optional[str]:
|
|
290
|
+
"""
|
|
291
|
+
Search for a file in the project directory tree.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
filename: Name of file to find
|
|
295
|
+
start_dir: Starting directory (default: project root)
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
Full path to file if found, None otherwise
|
|
299
|
+
|
|
300
|
+
Examples:
|
|
301
|
+
>>> path = find_file("setup.py")
|
|
302
|
+
>>> path = find_file("config.json", "/path/to/start")
|
|
303
|
+
"""
|
|
304
|
+
if start_dir is None:
|
|
305
|
+
try:
|
|
306
|
+
start_dir = project_root()
|
|
307
|
+
except RuntimeError:
|
|
308
|
+
start_dir = Path.cwd()
|
|
309
|
+
else:
|
|
310
|
+
start_dir = Path(start_dir)
|
|
311
|
+
|
|
312
|
+
start_dir = Path(start_dir).resolve()
|
|
313
|
+
|
|
314
|
+
# Search for the file
|
|
315
|
+
for path in start_dir.rglob(filename):
|
|
316
|
+
if path.is_file():
|
|
317
|
+
return str(path)
|
|
318
|
+
|
|
319
|
+
return None
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def safe_open(filepath: Union[str, Path], mode: str = 'r', encoding: str = 'utf-8'):
|
|
323
|
+
"""
|
|
324
|
+
Safely open a file with helpful error messages.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
filepath: Path to file (relative or absolute)
|
|
328
|
+
mode: File open mode ('r', 'w', 'a', etc.)
|
|
329
|
+
encoding: Text encoding (default: utf-8)
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
File object
|
|
333
|
+
|
|
334
|
+
Raises:
|
|
335
|
+
FileNotFoundError: With helpful suggestions if file not found
|
|
336
|
+
PermissionError: With helpful suggestions if permission denied
|
|
337
|
+
|
|
338
|
+
Examples:
|
|
339
|
+
>>> with safe_open("data.txt") as f:
|
|
340
|
+
... content = f.read()
|
|
341
|
+
"""
|
|
342
|
+
from ..errors.exceptions import SafeUtilityError
|
|
343
|
+
|
|
344
|
+
filepath = Path(filepath)
|
|
345
|
+
|
|
346
|
+
# If relative path, try to resolve relative to project root
|
|
347
|
+
if not filepath.is_absolute():
|
|
348
|
+
try:
|
|
349
|
+
root = project_root()
|
|
350
|
+
filepath = Path(root) / filepath
|
|
351
|
+
except RuntimeError:
|
|
352
|
+
# If project root not found, use as-is
|
|
353
|
+
pass
|
|
354
|
+
|
|
355
|
+
try:
|
|
356
|
+
return open(filepath, mode, encoding=encoding)
|
|
357
|
+
except FileNotFoundError as e:
|
|
358
|
+
raise FileNotFoundError(f"File not found: {filepath}") from e
|
|
359
|
+
except PermissionError as e:
|
|
360
|
+
raise PermissionError(f"Permission denied: {filepath}") from e
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
# ============================================================================
|
|
365
|
+
# New file utility functions for fishertools-file-utils spec
|
|
366
|
+
# ============================================================================
|
|
367
|
+
|
|
368
|
+
import hashlib
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def ensure_dir(path: Union[str, Path]) -> Path:
|
|
372
|
+
"""
|
|
373
|
+
Создаёт директорию рекурсивно, как os.makedirs с exist_ok=True.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
path: Путь к директории (str или Path).
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
Path: Объект pathlib.Path созданной директории.
|
|
380
|
+
|
|
381
|
+
Raises:
|
|
382
|
+
OSError: Если директория не может быть создана.
|
|
383
|
+
PermissionError: Если нет прав доступа.
|
|
384
|
+
|
|
385
|
+
Examples:
|
|
386
|
+
>>> ensure_dir("/path/to/directory")
|
|
387
|
+
PosixPath('/path/to/directory')
|
|
388
|
+
>>> ensure_dir("./nested/dir/structure")
|
|
389
|
+
PosixPath('./nested/dir/structure')
|
|
390
|
+
"""
|
|
391
|
+
try:
|
|
392
|
+
path_obj = Path(path)
|
|
393
|
+
path_obj.mkdir(parents=True, exist_ok=True)
|
|
394
|
+
return path_obj
|
|
395
|
+
except PermissionError as e:
|
|
396
|
+
raise PermissionError(f"Permission denied creating directory: {path}") from e
|
|
397
|
+
except OSError as e:
|
|
398
|
+
raise OSError(f"Failed to create directory: {path}") from e
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def get_file_hash(
|
|
402
|
+
file_path: Union[str, Path],
|
|
403
|
+
algorithm: str = 'sha256'
|
|
404
|
+
) -> str:
|
|
405
|
+
"""
|
|
406
|
+
Вычисляет хэш файла потоковым методом (8KB чанки).
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
file_path: Путь к файлу (str или Path).
|
|
410
|
+
algorithm: Алгоритм хэширования (md5, sha1, sha256, sha512, blake2b).
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
str: Хэш файла в hex формате.
|
|
414
|
+
|
|
415
|
+
Raises:
|
|
416
|
+
FileNotFoundError: Если файл не существует.
|
|
417
|
+
ValueError: Если алгоритм не поддерживается.
|
|
418
|
+
PermissionError: Если нет прав доступа на чтение.
|
|
419
|
+
|
|
420
|
+
Examples:
|
|
421
|
+
>>> get_file_hash("data.txt")
|
|
422
|
+
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
|
423
|
+
>>> get_file_hash("data.txt", algorithm='md5')
|
|
424
|
+
'd41d8cd98f00b204e9800998ecf8427e'
|
|
425
|
+
"""
|
|
426
|
+
# Supported algorithms
|
|
427
|
+
supported_algorithms = {'md5', 'sha1', 'sha256', 'sha512', 'blake2b'}
|
|
428
|
+
|
|
429
|
+
# Validate algorithm
|
|
430
|
+
if algorithm not in supported_algorithms:
|
|
431
|
+
raise ValueError(
|
|
432
|
+
f"Unsupported algorithm: {algorithm}. "
|
|
433
|
+
f"Supported algorithms: {', '.join(sorted(supported_algorithms))}"
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
# Convert to Path object
|
|
437
|
+
file_path_obj = Path(file_path)
|
|
438
|
+
|
|
439
|
+
# Check if file exists
|
|
440
|
+
if not file_path_obj.exists():
|
|
441
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
|
442
|
+
|
|
443
|
+
# Create hash object
|
|
444
|
+
if algorithm == 'blake2b':
|
|
445
|
+
hash_obj = hashlib.blake2b()
|
|
446
|
+
else:
|
|
447
|
+
hash_obj = hashlib.new(algorithm)
|
|
448
|
+
|
|
449
|
+
# Read file in chunks and update hash
|
|
450
|
+
chunk_size = 8192 # 8KB chunks
|
|
451
|
+
try:
|
|
452
|
+
with open(file_path_obj, 'rb') as f:
|
|
453
|
+
while True:
|
|
454
|
+
chunk = f.read(chunk_size)
|
|
455
|
+
if not chunk:
|
|
456
|
+
break
|
|
457
|
+
hash_obj.update(chunk)
|
|
458
|
+
except PermissionError as e:
|
|
459
|
+
raise PermissionError(f"Permission denied reading file: {file_path}") from e
|
|
460
|
+
except OSError as e:
|
|
461
|
+
raise OSError(f"Error reading file: {file_path}") from e
|
|
462
|
+
|
|
463
|
+
return hash_obj.hexdigest()
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def read_last_lines(
|
|
467
|
+
file_path: Union[str, Path],
|
|
468
|
+
n: int = 10
|
|
469
|
+
) -> List[str]:
|
|
470
|
+
"""
|
|
471
|
+
Читает последние N строк файла буферным алгоритмом от конца.
|
|
472
|
+
|
|
473
|
+
Args:
|
|
474
|
+
file_path: Путь к файлу (str или Path).
|
|
475
|
+
n: Количество строк для чтения (по умолчанию 10).
|
|
476
|
+
|
|
477
|
+
Returns:
|
|
478
|
+
List[str]: Список последних N строк без символов новой строки.
|
|
479
|
+
|
|
480
|
+
Raises:
|
|
481
|
+
FileNotFoundError: Если файл не существует.
|
|
482
|
+
PermissionError: Если нет прав доступа на чтение.
|
|
483
|
+
|
|
484
|
+
Examples:
|
|
485
|
+
>>> read_last_lines("log.txt", n=5)
|
|
486
|
+
['line 1', 'line 2', 'line 3', 'line 4', 'line 5']
|
|
487
|
+
>>> read_last_lines("data.txt")
|
|
488
|
+
['last line']
|
|
489
|
+
"""
|
|
490
|
+
# Convert to Path object
|
|
491
|
+
file_path_obj = Path(file_path)
|
|
492
|
+
|
|
493
|
+
# Check if file exists
|
|
494
|
+
if not file_path_obj.exists():
|
|
495
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
|
496
|
+
|
|
497
|
+
try:
|
|
498
|
+
with open(file_path_obj, 'rb') as f:
|
|
499
|
+
# Get file size
|
|
500
|
+
f.seek(0, 2) # Seek to end
|
|
501
|
+
file_size = f.tell()
|
|
502
|
+
|
|
503
|
+
# If file is empty, return empty list
|
|
504
|
+
if file_size == 0:
|
|
505
|
+
return []
|
|
506
|
+
|
|
507
|
+
# Buffer for reading from end
|
|
508
|
+
buffer_size = 8192 # 8KB buffer
|
|
509
|
+
lines = []
|
|
510
|
+
position = file_size
|
|
511
|
+
|
|
512
|
+
# Read file from end in chunks
|
|
513
|
+
while position > 0 and len(lines) < n:
|
|
514
|
+
# Calculate how much to read
|
|
515
|
+
read_size = min(buffer_size, position)
|
|
516
|
+
position -= read_size
|
|
517
|
+
|
|
518
|
+
# Seek and read
|
|
519
|
+
f.seek(position)
|
|
520
|
+
chunk = f.read(read_size)
|
|
521
|
+
|
|
522
|
+
# Decode chunk
|
|
523
|
+
try:
|
|
524
|
+
text = chunk.decode('utf-8')
|
|
525
|
+
except UnicodeDecodeError:
|
|
526
|
+
# Try with latin-1 as fallback
|
|
527
|
+
text = chunk.decode('latin-1', errors='replace')
|
|
528
|
+
|
|
529
|
+
# Split by newlines and process
|
|
530
|
+
chunk_lines = text.split('\n')
|
|
531
|
+
|
|
532
|
+
# If we're not at the start of file, the first line is incomplete
|
|
533
|
+
if position > 0:
|
|
534
|
+
# Keep the incomplete line for next iteration
|
|
535
|
+
incomplete_line = chunk_lines[0]
|
|
536
|
+
chunk_lines = chunk_lines[1:]
|
|
537
|
+
else:
|
|
538
|
+
# At start of file, all lines are complete
|
|
539
|
+
incomplete_line = None
|
|
540
|
+
|
|
541
|
+
# Add lines in reverse order (we're reading backwards)
|
|
542
|
+
for line in reversed(chunk_lines):
|
|
543
|
+
if line or lines: # Skip empty lines at the end
|
|
544
|
+
lines.insert(0, line)
|
|
545
|
+
if len(lines) >= n:
|
|
546
|
+
break
|
|
547
|
+
|
|
548
|
+
# If we're at the start and have incomplete line, add it
|
|
549
|
+
if position == 0 and incomplete_line:
|
|
550
|
+
lines.insert(0, incomplete_line)
|
|
551
|
+
|
|
552
|
+
# Clean up: remove empty lines at the end and limit to n
|
|
553
|
+
result = []
|
|
554
|
+
for line in lines:
|
|
555
|
+
# Strip newline characters
|
|
556
|
+
cleaned = line.rstrip('\r\n')
|
|
557
|
+
result.append(cleaned)
|
|
558
|
+
|
|
559
|
+
# Return only the last n lines
|
|
560
|
+
return result[-n:] if len(result) > n else result
|
|
561
|
+
|
|
562
|
+
except PermissionError as e:
|
|
563
|
+
raise PermissionError(f"Permission denied reading file: {file_path}") from e
|
|
564
|
+
except OSError as e:
|
|
565
|
+
raise OSError(f"Error reading file: {file_path}") from e
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
__all__ = ['ensure_dir', 'get_file_hash', 'read_last_lines']
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main transformation script for README improvements.
|
|
3
|
+
|
|
4
|
+
This script orchestrates the complete README transformation process,
|
|
5
|
+
including backup creation, transformation, validation, and error handling.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
from fishertools.readme_transformer import (
|
|
13
|
+
ReadmeTransformer,
|
|
14
|
+
FeatureEntry,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def transform_readme(
|
|
19
|
+
readme_path: str = "README.md",
|
|
20
|
+
create_backup: bool = True,
|
|
21
|
+
features: Optional[list] = None,
|
|
22
|
+
target_audience_bullets: Optional[list] = None,
|
|
23
|
+
) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Transform the README file with improved structure.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
readme_path: Path to the README.md file
|
|
29
|
+
create_backup: Whether to create a backup before transformation
|
|
30
|
+
features: List of feature entries (dicts with 'task' and 'function' keys)
|
|
31
|
+
target_audience_bullets: Custom target audience bullet points
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
True if transformation was successful, False otherwise
|
|
35
|
+
|
|
36
|
+
Raises:
|
|
37
|
+
FileNotFoundError: If README file does not exist
|
|
38
|
+
IOError: If file operations fail
|
|
39
|
+
"""
|
|
40
|
+
transformer = ReadmeTransformer(readme_path)
|
|
41
|
+
|
|
42
|
+
# Validate README exists
|
|
43
|
+
if not transformer.validate_readme_exists():
|
|
44
|
+
raise FileNotFoundError(f"README file not found: {readme_path}")
|
|
45
|
+
|
|
46
|
+
# Create backup if requested
|
|
47
|
+
if create_backup:
|
|
48
|
+
backup_path = transformer.create_backup()
|
|
49
|
+
print(f"✓ Backup created: {backup_path}")
|
|
50
|
+
|
|
51
|
+
# Convert feature dicts to FeatureEntry objects if provided
|
|
52
|
+
feature_entries = None
|
|
53
|
+
if features:
|
|
54
|
+
feature_entries = [
|
|
55
|
+
FeatureEntry(task=f["task"], function=f["function"]) for f in features
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
# Transform the README
|
|
59
|
+
try:
|
|
60
|
+
transformed_content = transformer.transform(
|
|
61
|
+
features=feature_entries,
|
|
62
|
+
target_audience_bullets=target_audience_bullets,
|
|
63
|
+
)
|
|
64
|
+
print("✓ README transformation completed")
|
|
65
|
+
except Exception as e:
|
|
66
|
+
print(f"✗ Transformation failed: {e}", file=sys.stderr)
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
# Validate the transformed content
|
|
70
|
+
is_valid, error_message = transformer.validate_transformed_content(
|
|
71
|
+
transformed_content
|
|
72
|
+
)
|
|
73
|
+
if not is_valid:
|
|
74
|
+
print(f"✗ Validation failed: {error_message}", file=sys.stderr)
|
|
75
|
+
return False
|
|
76
|
+
print("✓ Content validation passed")
|
|
77
|
+
|
|
78
|
+
# Write the transformed content
|
|
79
|
+
try:
|
|
80
|
+
transformer.write_transformed_readme(transformed_content)
|
|
81
|
+
print(f"✓ README updated: {readme_path}")
|
|
82
|
+
except IOError as e:
|
|
83
|
+
print(f"✗ Failed to write README: {e}", file=sys.stderr)
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
return True
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def main() -> int:
|
|
90
|
+
"""
|
|
91
|
+
Main entry point for the transformation script.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
0 if successful, 1 if failed
|
|
95
|
+
"""
|
|
96
|
+
try:
|
|
97
|
+
success = transform_readme()
|
|
98
|
+
return 0 if success else 1
|
|
99
|
+
except Exception as e:
|
|
100
|
+
print(f"✗ Error: {e}", file=sys.stderr)
|
|
101
|
+
return 1
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
if __name__ == "__main__":
|
|
105
|
+
sys.exit(main())
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fishertools
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Fishertools - инструменты, которые делают Python удобнее и безопаснее для новичков
|
|
5
|
+
Home-page: https://github.com/f1sherFM/My_1st_library_python
|
|
6
|
+
Author: f1sherFM
|
|
7
|
+
Author-email: f1sherFM <kirillka229top@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/f1sherFM/My_1st_library_python
|
|
10
|
+
Project-URL: Repository, https://github.com/f1sherFM/My_1st_library_python
|
|
11
|
+
Project-URL: Issues, https://github.com/f1sherFM/My_1st_library_python/issues
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: requests>=2.25.0
|
|
28
|
+
Requires-Dist: click>=8.0.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: hypothesis>=6.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: black>=24.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy>=1.8.0; extra == "dev"
|
|
35
|
+
Dynamic: author
|
|
36
|
+
Dynamic: home-page
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
|
|
40
|
+
# Fishertools
|
|
41
|
+
|
|
42
|
+
**Tools that make Python easier and safer for beginners**
|
|
43
|
+
|
|
44
|
+
Fishertools is a Python library designed specifically for beginner developers. It provides clear error explanations, safe utilities, and learning tools to help you master Python.
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install fishertools
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quick Reference
|
|
53
|
+
|
|
54
|
+
| Task | Function |
|
|
55
|
+
|------|----------|
|
|
56
|
+
| Explain an error | `explain_error(e)` |
|
|
57
|
+
| Get element safely | `safe_get(list, index, default)` |
|
|
58
|
+
| Divide safely | `safe_divide(a, b, default)` |
|
|
59
|
+
| Read file safely | `safe_read_file(path)` |
|
|
60
|
+
| Learn Python concepts | `explain(topic)` |
|
|
61
|
+
|
|
62
|
+
## Documentation
|
|
63
|
+
|
|
64
|
+
Complete documentation is available in the `docs/` folder:
|
|
65
|
+
|
|
66
|
+
- **[Getting Started](docs/getting-started.md)** - Quick start guide with installation and first example
|
|
67
|
+
- **[Features](docs/features.md)** - Overview of all features and capabilities
|
|
68
|
+
- **[Installation](docs/installation.md)** - Detailed installation instructions for different operating systems
|
|
69
|
+
- **[API Reference](docs/api-reference.md)** - Complete API documentation with all functions and classes
|
|
70
|
+
- **[Examples](docs/examples.md)** - Practical examples from basic to advanced usage
|
|
71
|
+
- **[Limitations](docs/limitations.md)** - Known limitations and performance considerations
|
|
72
|
+
- **[Contributing](docs/contributing.md)** - How to contribute to the project
|
|
73
|
+
|
|
74
|
+
## For Whom This Library?
|
|
75
|
+
|
|
76
|
+
- You're just starting to learn Python
|
|
77
|
+
- Error messages seem scary and confusing
|
|
78
|
+
- You want errors explained in plain language with examples
|
|
79
|
+
|
|
80
|
+
## Main Features
|
|
81
|
+
|
|
82
|
+
### Error Explanation
|
|
83
|
+
Get clear explanations of Python errors with suggestions for fixing them.
|
|
84
|
+
|
|
85
|
+
### Safe Utilities
|
|
86
|
+
Functions like `safe_get()`, `safe_divide()`, `safe_read_file()` that prevent typical beginner errors.
|
|
87
|
+
|
|
88
|
+
### Learning Tools
|
|
89
|
+
Structured explanations of Python concepts with examples and best practices.
|
|
90
|
+
|
|
91
|
+
### Ready-made Patterns
|
|
92
|
+
Templates for common tasks like menus, file storage, logging, and CLI applications.
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
MIT License - see [LICENSE](LICENSE) file
|
|
97
|
+
|
|
98
|
+
## Contributing
|
|
99
|
+
|
|
100
|
+
We welcome contributions! See [Contributing](docs/contributing.md) for details.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
**Fishertools** - Making Python easier and safer for beginners! 🐍✨
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
fishertools/__init__.py,sha256=iDmTniXz0fCeArJfKCuqn0fcK9LlPkM9lTc1K3tzL_E,3132
|
|
2
|
+
fishertools/decorators.py,sha256=DKWLy_USqTOUFGRyWllznYJ61jvRyXLDZ3iKOj6u-6k,3719
|
|
3
|
+
fishertools/helpers.py,sha256=qhSIY4ooZqCM5bKnku5XKjhONy9h1kMnrIEb4uRRZE4,4081
|
|
4
|
+
fishertools/input_utils.py,sha256=RR24grnLnA790bvzyAli2AXE123zA7kFh-H89l0nTOM,6193
|
|
5
|
+
fishertools/integration.py,sha256=m8oaKPENdS9aOck4gR8ooUqUa7EIdH7r7aOGaVEFWHw,19763
|
|
6
|
+
fishertools/readme_transformer.py,sha256=cZRzooeyi1JT5Xj20Q-Q5kZP6CKXIipj1tC23RE7_7U,20682
|
|
7
|
+
fishertools/transform_readme.py,sha256=K8CSiyvauL_3FcZUluRTCLppcU2L44tIIlny5Y88RWk,3117
|
|
8
|
+
fishertools/utils.py,sha256=6tUnCsHoHUoIpOYGgHAdqIqQ7FZhWzN3kCavgKKw1Uc,2159
|
|
9
|
+
fishertools/config/__init__.py,sha256=8slBbZSDgQeUIcEmkpZD9o30CMKd8pbJ2bJV3t01j5M,508
|
|
10
|
+
fishertools/config/manager.py,sha256=EPRjqYDcllanPA9w8PLjkanoi5ox38sVsuytz00ROhY,9095
|
|
11
|
+
fishertools/config/models.py,sha256=TXfFTee68B7VK7BFBorHQDPas8sFJacdUQVH61AKSDA,2594
|
|
12
|
+
fishertools/config/parser.py,sha256=oxf-LXf-7qr3aHKDZRFPsinwjSxI0gSY3kEEHALcwhk,10168
|
|
13
|
+
fishertools/documentation/__init__.py,sha256=kA7s2hssDLxxlJPxMeHQIuHm-BPYaS86EXERe4ZcRuU,806
|
|
14
|
+
fishertools/documentation/api.py,sha256=pn3K-3-xygpUfsNml6yAZeIhnGFPJyoL4c4AQJrxWCk,8718
|
|
15
|
+
fishertools/documentation/generator.py,sha256=mOduCARUboSs5Wmai0PCwpmNyNCjQGN756xmouzZtSI,18063
|
|
16
|
+
fishertools/documentation/models.py,sha256=8l2VC8dAib-c5jzuySnuOfKlM7Q1ITxV8phhBZDGd5Y,2884
|
|
17
|
+
fishertools/documentation/visual.py,sha256=JxyFrhkmuHxpIaBMbLtuP3a24FYIwyoT3_mKPV-oZPE,19307
|
|
18
|
+
fishertools/errors/__init__.py,sha256=lio34XZyQ9nB_rVQnOfLNvQsCL6fIC3L6At54KRq-IU,1734
|
|
19
|
+
fishertools/errors/exception_types.py,sha256=EnoFVrO7xrEX4IJz9nM5YepgBWGe6CK3H4eoPdoy-KY,9026
|
|
20
|
+
fishertools/errors/exceptions.py,sha256=ocBgqCMw8f_rJ2Rp_3uxlJFc-NphebdM0dizFQoAQcc,7301
|
|
21
|
+
fishertools/errors/explainer.py,sha256=2rnCPn3YSbJ4v5aYyXoiDuIUU9aBZz8gfZkKtnxsnBc,18499
|
|
22
|
+
fishertools/errors/formatters.py,sha256=khdiXGx4Lil5cqd3WWkh8ZLrQea0S8u90hbZgKnFsMo,13790
|
|
23
|
+
fishertools/errors/models.py,sha256=ZvHwhmf9sDvc0SPDCUdD9scCFLAYevLRyGMb0yQF4WA,11048
|
|
24
|
+
fishertools/errors/patterns.py,sha256=hClRz0uIqSXlwaSMBlB7xTQld8fF9AHdckLAfEMKya4,17458
|
|
25
|
+
fishertools/errors/recovery.py,sha256=7-3qd1uIv32vNltjvbVS2O5QJPixBLQVivU17f3Lxwo,17165
|
|
26
|
+
fishertools/examples/__init__.py,sha256=1D6EezNPBqY5blM_SfK0C3dxSnPOnfXOaqnjbCMlH0Y,457
|
|
27
|
+
fishertools/examples/cli_example.py,sha256=AEYrn8U708Db1C-aja78cs1ycYIYttYv2FuOPg19gUI,5571
|
|
28
|
+
fishertools/examples/learn_example.py,sha256=sseTUePSu1-km6ajwHQCEnhW3eeej4YeO-h59ho95nM,1927
|
|
29
|
+
fishertools/examples/logger_example.py,sha256=nMT7xxNYXDsMnmQ_MhN_6eqt8GT1AzTX_X6LG22B1PM,5485
|
|
30
|
+
fishertools/examples/menu_example.py,sha256=5DlI2qxaHw6FUeR2khrihWIj5Y18hG9izwzAY2tsEEk,3186
|
|
31
|
+
fishertools/examples/models.py,sha256=gmOIdz29qnbWKMNAQ6r1i4BE7rZHK8Hv5jtF9Z0MYP0,2845
|
|
32
|
+
fishertools/examples/repository.py,sha256=HO-rB2CCnMQBdEQuyfJbDF8PelMecyoltMs3hPUpjFM,31204
|
|
33
|
+
fishertools/examples/storage_example.py,sha256=Uk-XY65tu2-q0cRaicpFm_TXfwBd-rLSLrsCJsCmuQA,5318
|
|
34
|
+
fishertools/learn/__init__.py,sha256=zJGEH6YsiUVElN1H4kMWDtAcuDfVwHCrX2kKlJK20_s,862
|
|
35
|
+
fishertools/learn/examples.py,sha256=hY4aNRtiViGNWe7-4kdFBsLGrMX4dAzAj5Ogp8rOjCM,22878
|
|
36
|
+
fishertools/learn/knowledge_engine.py,sha256=icHqar-fZU81S-JwlcM8okIH4WDDnlCazF7CNpjqgss,9981
|
|
37
|
+
fishertools/learn/test_knowledge_engine.py,sha256=WWSTXNwiYWGYw4goKKYCDdSb2iwDinolBSDu10xT7J8,9298
|
|
38
|
+
fishertools/learn/test_knowledge_engine_pbt.py,sha256=efzunUirxT2SkZYdNchYtbzBpoE2s_e_6I-zaOf-IKY,6325
|
|
39
|
+
fishertools/learn/tips.py,sha256=lGxheuvKe0QgFOn7CDpW2XppZ7bW7a1jYysSghibkUU,9697
|
|
40
|
+
fishertools/learn/repl/__init__.py,sha256=hxS96V4CGzQq4IahtDozQumUsKK732ZXVr28SYz4ULk,526
|
|
41
|
+
fishertools/learn/repl/cli.py,sha256=C34JHre6S3Va86jKtqLbb2ejQaEZuBGCD9IFQFmuh9g,699
|
|
42
|
+
fishertools/learn/repl/code_sandbox.py,sha256=YYOO8OX2NCmT24tODHRadM8M5dRy_-iE6oCgIYLdG-s,8111
|
|
43
|
+
fishertools/learn/repl/command_handler.py,sha256=eBRrWP0F0Ty-QM89P6u-SynHtJE3OCppKkibfrS3v9Y,21350
|
|
44
|
+
fishertools/learn/repl/command_parser.py,sha256=LaSf_MQQFhJBfhOABS55BxA6rcgKRrtnjwdnWBR33mA,5157
|
|
45
|
+
fishertools/learn/repl/engine.py,sha256=f3l1unc70tR28baOnisrXf7PPUsS1wasDv3AkGtrDFM,17093
|
|
46
|
+
fishertools/learn/repl/models.py,sha256=WwKycJ7jvts7kHvJs3fNRH6j8U_eft1h_vwDPGlhIhY,4270
|
|
47
|
+
fishertools/learn/repl/session_manager.py,sha256=-0_FRY2MDRPT_gsBkrZcX2taJ0SN5PW459zKFgrwOG0,9526
|
|
48
|
+
fishertools/learn/repl/test_code_sandbox.py,sha256=DRwNoO6oN-grsNP6Ils84LA2llfZJekDcS3MWuwahaA,8575
|
|
49
|
+
fishertools/learn/repl/test_code_sandbox_pbt.py,sha256=6wz5ra4iwPuuA6YXhYcH9HRMs2PjFI7dUxQSU-RET8k,5513
|
|
50
|
+
fishertools/learn/repl/test_command_handler.py,sha256=dEFs7hGqFrSkXT96qMqfQutA87_EEiGOycfzfqXz24g,7681
|
|
51
|
+
fishertools/learn/repl/test_command_handler_pbt.py,sha256=klpxb87VtajUqDnYc_omk3ESpGsYNT9tDiazLFYRZbI,7371
|
|
52
|
+
fishertools/learn/repl/test_command_parser.py,sha256=KM-HUZbTnRZYJx6GvXMesZhDhqwhiGc5MFHEwfuuhR4,6617
|
|
53
|
+
fishertools/learn/repl/test_command_parser_pbt.py,sha256=uvG1GYNEdZeCrU6t35KEB44R1oxKY-7O1wmXvJjXVUc,3753
|
|
54
|
+
fishertools/learn/repl/test_engine.py,sha256=C3jGUsiQ-eTkxA6AM4SnJM4ngz9RFWpuvsHFylKis-8,6948
|
|
55
|
+
fishertools/learn/repl/test_session_manager.py,sha256=-qVfhSOmf2xpjDuI8SvZQOzpO-AseXKYcYMY9XkdqeA,12457
|
|
56
|
+
fishertools/learn/repl/test_session_manager_pbt.py,sha256=momGjN0rJ1lOrP08axxBP5jveIbarBtz_K5KQRqJc00,7561
|
|
57
|
+
fishertools/learning/__init__.py,sha256=fBwvqElVmhaUnRBwXfwQQSm7A0lzyrZihSNA91cnm_U,780
|
|
58
|
+
fishertools/learning/core.py,sha256=azR7rQLdSglSPZ-q-rZj5DEJ-2Ms0XyA0VV8KUvp1O0,14138
|
|
59
|
+
fishertools/learning/models.py,sha256=eLB9w-lSC0SKRkl-HwYRjfmxhDANtQXdogPFyiuD8cc,2861
|
|
60
|
+
fishertools/learning/progress.py,sha256=Nju1wei_UVYFW7LqYgMjKdLI8jiqHomH97gp-3d2ZOY,12761
|
|
61
|
+
fishertools/learning/session.py,sha256=9ZE-UJpd9tFph0ZaEl8FN1VDJIU-fmTF9CsDyBbpVng,19837
|
|
62
|
+
fishertools/learning/tutorial.py,sha256=jiRcOm0kDTHSMUzNw-1bNlzC9aOMJwHbXn8lW0IQHTc,28325
|
|
63
|
+
fishertools/legacy/__init__.py,sha256=9NYb7gfwtp-4o5TJyUFvFapY1SnDPezfdyrcI-gU97g,2156
|
|
64
|
+
fishertools/legacy/deprecated.py,sha256=rR4Z7eo42LFklkKBkrA05wzkes2IsjayeKzWZV27wI4,10033
|
|
65
|
+
fishertools/legacy/deprecation.py,sha256=2EPKgix0N-F7limO9cirurXvApDJGVxNfh2jCfMZ9uc,5068
|
|
66
|
+
fishertools/patterns/__init__.py,sha256=eqoJXstaGkKa1hsUX6N3TwryLYJAK6xkRIvAgZ9jY7E,1312
|
|
67
|
+
fishertools/patterns/cli.py,sha256=xigdz7GohL4AQ4oADdtXy_n5R4peE0bVxtA-jctiWxI,5320
|
|
68
|
+
fishertools/patterns/logger.py,sha256=s5hvNZ93KCNMH-Plv3GOX-N3iiR17M70-xnMeSnf1u4,3924
|
|
69
|
+
fishertools/patterns/menu.py,sha256=WOGK3mlE5GXeKxmSGP2g1ScgfGJERJk7eVfeKHpZD2s,3048
|
|
70
|
+
fishertools/patterns/storage.py,sha256=pYWFVz9eh59kG07itHJxf2-cbzITfFx6ePawmhd74g0,3909
|
|
71
|
+
fishertools/safe/__init__.py,sha256=EdK6NB9gd98KCkMVnp9ky4W-QgI4sFCXIMgMTpyX8SE,835
|
|
72
|
+
fishertools/safe/collections.py,sha256=NTfqVv4alPNr0wrcO5IGYSYk3FSSZYMIaYN3iFnOJlc,9738
|
|
73
|
+
fishertools/safe/files.py,sha256=Fxj0fm_uJAZE9uDe3wI22dTfyuKjcSaZYpDprYBrGb4,20733
|
|
74
|
+
fishertools/safe/strings.py,sha256=8kyN0ajwWBV4VE19LDspoVNFCTjghwx63aADZoX-6j8,315
|
|
75
|
+
fishertools-0.4.0.dist-info/licenses/LICENSE,sha256=eLEqXLzyplfeaqnVJgjvQUsaFYxAPJ38xNpFhlntZrw,1084
|
|
76
|
+
tests/__init__.py,sha256=09o34ess27Hp5ZJ9H6bqAiBkFWsp3cjy6hiT0kUH58E,139
|
|
77
|
+
tests/conftest.py,sha256=DAnUXhbJvYWj8XLuggM3JdL19R8-XJjbZeNYeiWXjik,828
|
|
78
|
+
tests/test_documentation_properties.py,sha256=C1EJj0Pv1VnBZKW7JqI9JTCroqciR0wJKsXO44T_tN4,12535
|
|
79
|
+
tests/test_documentation_structure.py,sha256=RutizKxPs9XhXf_ZY_Hxyrq-hKrNW7D8QdGeJib3Mgc,14402
|
|
80
|
+
tests/test_integration.py,sha256=5fmubUAKDCiNfIg-SJAWYeZlLPjgsky8ZmT0BUbd8kI,12236
|
|
81
|
+
tests/test_integration_enhancements.py,sha256=DHHUAn271QZlN-BDsOQNBpEoktQhZvHJKOLwisOyQqw,18708
|
|
82
|
+
tests/test_patterns_cli.py,sha256=qKWA-d2N4n8yZMeCbTm7pjJ9HzODOoItg4w37_3qZj8,21087
|
|
83
|
+
tests/test_patterns_docstrings.py,sha256=nFtdtuNdyZHhPoT-0TTynTz2E0HkAmF9Cncb2lqDzAs,20248
|
|
84
|
+
tests/test_patterns_logger.py,sha256=Rt6VGFDftE4MlWW5-ndpWMyexFe26hzxR67JJngo-kc,17687
|
|
85
|
+
tests/test_patterns_menu.py,sha256=445kSS_rPhGXqMaCKmgLPqEmx_dUGTzoLvGOj79f6Ak,16408
|
|
86
|
+
tests/test_patterns_storage.py,sha256=6YM9-Ll6t75ntVVVpNuYMe6PIoRIst460_dXy5E1O2c,16804
|
|
87
|
+
tests/test_readme_enhancements_v0_3_1.py,sha256=0NMvs9XI4dLeqKGd3GRGvQ1WKIXEcbVeiqMzkb7g9YQ,92732
|
|
88
|
+
tests/test_structure.py,sha256=Lhes-TH2TgbqW4K_G2KOjYPwHQW9dLT4mqLbm6Nc-w4,2015
|
|
89
|
+
tests/test_structure_enhancements.py,sha256=8_6hCYc_jOJVdO3O1dhFFNPc5TCE2kbNkP2LaWS5q98,4760
|
|
90
|
+
tests/test_config/__init__.py,sha256=9_IIF-3DZE06DR388NQp8WPEon2XZLR-VdoQXePkBCw,56
|
|
91
|
+
tests/test_config/test_basic_config.py,sha256=oIwfjhRz1pcZQcAADect9x705cOPFvNQFWFo1QThzAA,2195
|
|
92
|
+
tests/test_config/test_config_error_handling.py,sha256=aa0eviMv1MowPEnf9FK9iE2Ec19rdm-bZYNYxx-KIf0,12163
|
|
93
|
+
tests/test_config/test_config_properties.py,sha256=4wAwc8bAMzqdYqBDndi7nqugwJ1teG4Vdj2Ijj0THWg,20789
|
|
94
|
+
tests/test_documentation/__init__.py,sha256=xsEvmyIlWI3HnTTwr3Go3jGtmw4A0NboXxVYPpSA-tA,56
|
|
95
|
+
tests/test_documentation/test_documentation_properties.py,sha256=5bVq-vUDfM2035jBf5tozTKouS21p_1R0PNncNTZqgA,10742
|
|
96
|
+
tests/test_documentation/test_visual_documentation_properties.py,sha256=Z4LR5LBDlQTwTuDXJej8Itltmw_9NqYZG5uXWEE3lzA,19349
|
|
97
|
+
tests/test_errors/__init__.py,sha256=TgRhzGojrbDYRs4YD4yz7U0YeffhDn8ZO-1C0IS0Hpo,49
|
|
98
|
+
tests/test_errors/test_api.py,sha256=TGUoMKG5oNb6Im8rpXxPdFWEaV0Hu4kuYrDoDpUl5cs,12327
|
|
99
|
+
tests/test_errors/test_error_handling.py,sha256=6D2ak6FXR9PQaakPSEx5kepbra9_MP38g13STuq3OH8,15342
|
|
100
|
+
tests/test_errors/test_exception_types.py,sha256=8brIl2MRPZXLZV_FL1AX_Z9MWB0L6-hFIKnZdO9hmF0,17645
|
|
101
|
+
tests/test_errors/test_exception_types_pbt.py,sha256=8QsQYlnM030jLLRvgvIFuOo3bHTMee7Yj3D0aUvI9UA,13534
|
|
102
|
+
tests/test_errors/test_explainer.py,sha256=50O9oHOPNmCasp5MR9i2ql-py4HHN48s7nnv5Ck-hkM,7449
|
|
103
|
+
tests/test_errors/test_formatters.py,sha256=D7dHAonDe0Q-uqNvKnccNrMEazgHlV99YrDo54anAfw,16267
|
|
104
|
+
tests/test_errors/test_models.py,sha256=LMg86PO9F5qIrmVIqbWd4tr4zjLu-Tq6m4h95VGkGuM,10566
|
|
105
|
+
tests/test_errors/test_patterns.py,sha256=pqHtG6vGsVcMvitolbiXbv_lIw7Yl-8OAbGg-HlFWUo,15479
|
|
106
|
+
tests/test_examples/__init__.py,sha256=gf_sI2CD9TaM_mony0sUPEqBsOxXLqXE6WPau7bysWE,51
|
|
107
|
+
tests/test_examples/test_example_repository_properties.py,sha256=ksQgL5oEaJM-tUjOcwVmEBeDEGLqUAVKTXw766NZgJU,10361
|
|
108
|
+
tests/test_examples/test_specific_examples.py,sha256=VjDHvVrheGI2M7UiZVrnoD2qyJ9Q6uQFjG7qbD2zLpk,14698
|
|
109
|
+
tests/test_input_utils/__init__.py,sha256=yYfKrp0IQU7bVcH9UoQcH0q8RKlE3EF4IjPgniULjnY,41
|
|
110
|
+
tests/test_input_utils/test_input_utils.py,sha256=kaJ6nG9hUEvWaGgLy1RdpVZ1Jp1uIitTWidPIlurCAI,2328
|
|
111
|
+
tests/test_learn/__init__.py,sha256=Bw7w8u9uiRrvtIg3k9Ac-0gYoE_3_hFvDbEetpZaNFA,35
|
|
112
|
+
tests/test_learn/test_examples.py,sha256=c7JSIWXrywDuznYEkijqG8Y-QpYBXtAnQllbd5jJSh0,15495
|
|
113
|
+
tests/test_learn/test_explain_properties.py,sha256=mM3KDB81FZgGccgYoYx577X5Ft5ADXtuRdRybt6Ab1s,11755
|
|
114
|
+
tests/test_learn/test_tips.py,sha256=fRZ8U0jXnpZFkVFbDnLKBoVayXhXJx3qIn0YUgojguc,11201
|
|
115
|
+
tests/test_learning/__init__.py,sha256=h-oxqKnBXNlK_AB8SP1aTP4sChfYDdydpxU6XQUOufc,47
|
|
116
|
+
tests/test_learning/test_interactive_learning_properties.py,sha256=EaCABbHSHFde4E_gyC6vAns1paSE_2dergKxAx_f5jM,17528
|
|
117
|
+
tests/test_learning/test_learning_system_properties.py,sha256=09Ir-s1v7FM9uD6hqprEjLN6JvligxjFDoRdLQ5wPiI,8396
|
|
118
|
+
tests/test_learning/test_progress_tracking_properties.py,sha256=xLwIk_a9Xfhw1WFOO2NxjuC63Fa_KiXmBWWJnhmbB8A,13290
|
|
119
|
+
tests/test_legacy/__init__.py,sha256=ofWG_WJXsOheTEbGn_5Y0wvppcN0kKb2E6aUFL98a_s,62
|
|
120
|
+
tests/test_legacy/test_backward_compatibility.py,sha256=svdImGaTMAyAWoyF_Qm8nCbVrxnT9klg3u-OEVlXaUo,9786
|
|
121
|
+
tests/test_legacy/test_deprecation_warnings.py,sha256=lSFLTDXfTjZcpqczPlxrO6Sw0CErMepxIhuNHdv36PU,9890
|
|
122
|
+
tests/test_readme_transformer/__init__.py,sha256=5m9Jd-JTm9oni4a9ShNOPAS5aN_95QAOGK4HvwxloTE,55
|
|
123
|
+
tests/test_readme_transformer/test_readme_infrastructure.py,sha256=vLDGVEJz2itYP_ImiYdeIW0HFjBd-5TEJk3-W--57Go,40078
|
|
124
|
+
tests/test_readme_transformer/test_transform_readme_integration.py,sha256=gmcqB25qCiVfBuUPSmglhjFN5T89f6i8dPKTvsyhX8E,16491
|
|
125
|
+
tests/test_safe/__init__.py,sha256=ZEQlbeYtDtcBYqkE7sZbwkjKgqbPOwXI3S5U_2gjo0w,35
|
|
126
|
+
tests/test_safe/test_collections_properties.py,sha256=DYQ542pwoacsTRS3-TMdgtcqLj6SyUnag7gZoK4dFDc,8359
|
|
127
|
+
tests/test_safe/test_files.py,sha256=vG36Jh457SHh9csrPmq_WBpFHrQHfeQ9Mh2YY1FuC1A,31848
|
|
128
|
+
fishertools-0.4.0.dist-info/METADATA,sha256=8L9LIXhFLpPYse5tBq8aMLkXj-2zxFPun_TFgJkGP_4,3919
|
|
129
|
+
fishertools-0.4.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
130
|
+
fishertools-0.4.0.dist-info/top_level.txt,sha256=rZDacVWxcOzBe1B5mCXYqOShQ1KJyzXIPAAJNZ5OYv4,18
|
|
131
|
+
fishertools-0.4.0.dist-info/RECORD,,
|