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.
Files changed (69) hide show
  1. fishertools/__init__.py +16 -5
  2. fishertools/errors/__init__.py +11 -3
  3. fishertools/errors/exception_types.py +282 -0
  4. fishertools/errors/explainer.py +87 -1
  5. fishertools/errors/models.py +73 -1
  6. fishertools/errors/patterns.py +40 -0
  7. fishertools/examples/cli_example.py +156 -0
  8. fishertools/examples/learn_example.py +65 -0
  9. fishertools/examples/logger_example.py +176 -0
  10. fishertools/examples/menu_example.py +101 -0
  11. fishertools/examples/storage_example.py +175 -0
  12. fishertools/input_utils.py +185 -0
  13. fishertools/learn/__init__.py +19 -2
  14. fishertools/learn/examples.py +88 -1
  15. fishertools/learn/knowledge_engine.py +321 -0
  16. fishertools/learn/repl/__init__.py +19 -0
  17. fishertools/learn/repl/cli.py +31 -0
  18. fishertools/learn/repl/code_sandbox.py +229 -0
  19. fishertools/learn/repl/command_handler.py +544 -0
  20. fishertools/learn/repl/command_parser.py +165 -0
  21. fishertools/learn/repl/engine.py +479 -0
  22. fishertools/learn/repl/models.py +121 -0
  23. fishertools/learn/repl/session_manager.py +284 -0
  24. fishertools/learn/repl/test_code_sandbox.py +261 -0
  25. fishertools/learn/repl/test_code_sandbox_pbt.py +148 -0
  26. fishertools/learn/repl/test_command_handler.py +224 -0
  27. fishertools/learn/repl/test_command_handler_pbt.py +189 -0
  28. fishertools/learn/repl/test_command_parser.py +160 -0
  29. fishertools/learn/repl/test_command_parser_pbt.py +100 -0
  30. fishertools/learn/repl/test_engine.py +190 -0
  31. fishertools/learn/repl/test_session_manager.py +310 -0
  32. fishertools/learn/repl/test_session_manager_pbt.py +182 -0
  33. fishertools/learn/test_knowledge_engine.py +241 -0
  34. fishertools/learn/test_knowledge_engine_pbt.py +180 -0
  35. fishertools/patterns/__init__.py +46 -0
  36. fishertools/patterns/cli.py +175 -0
  37. fishertools/patterns/logger.py +140 -0
  38. fishertools/patterns/menu.py +99 -0
  39. fishertools/patterns/storage.py +127 -0
  40. fishertools/readme_transformer.py +631 -0
  41. fishertools/safe/__init__.py +6 -1
  42. fishertools/safe/files.py +329 -1
  43. fishertools/transform_readme.py +105 -0
  44. fishertools-0.4.0.dist-info/METADATA +104 -0
  45. fishertools-0.4.0.dist-info/RECORD +131 -0
  46. {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/WHEEL +1 -1
  47. tests/test_documentation_properties.py +329 -0
  48. tests/test_documentation_structure.py +349 -0
  49. tests/test_errors/test_exception_types.py +446 -0
  50. tests/test_errors/test_exception_types_pbt.py +333 -0
  51. tests/test_errors/test_patterns.py +52 -0
  52. tests/test_input_utils/__init__.py +1 -0
  53. tests/test_input_utils/test_input_utils.py +65 -0
  54. tests/test_learn/test_examples.py +179 -1
  55. tests/test_learn/test_explain_properties.py +307 -0
  56. tests/test_patterns_cli.py +611 -0
  57. tests/test_patterns_docstrings.py +473 -0
  58. tests/test_patterns_logger.py +465 -0
  59. tests/test_patterns_menu.py +440 -0
  60. tests/test_patterns_storage.py +447 -0
  61. tests/test_readme_enhancements_v0_3_1.py +2036 -0
  62. tests/test_readme_transformer/__init__.py +1 -0
  63. tests/test_readme_transformer/test_readme_infrastructure.py +1023 -0
  64. tests/test_readme_transformer/test_transform_readme_integration.py +431 -0
  65. tests/test_safe/test_files.py +726 -1
  66. fishertools-0.2.1.dist-info/METADATA +0 -256
  67. fishertools-0.2.1.dist-info/RECORD +0 -81
  68. {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/licenses/LICENSE +0 -0
  69. {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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5