basic-open-agent-tools 0.1.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.
@@ -0,0 +1,39 @@
1
+ """Basic Open Agent Tools.
2
+
3
+ An open foundational toolkit providing essential components for building AI agents
4
+ with minimal dependencies for local (non-HTTP/API) actions.
5
+ """
6
+
7
+ __version__ = "0.1.0"
8
+
9
+ # Modular structure
10
+ from . import file_system
11
+
12
+ # Future modules (placeholder imports for when modules are implemented)
13
+ # from . import text
14
+ # from . import system
15
+ # from . import network
16
+ # from . import data
17
+ # from . import crypto
18
+ # from . import utilities
19
+
20
+ # Common infrastructure
21
+ from . import exceptions
22
+ from . import types
23
+
24
+ __all__ = [
25
+ # Modular structure
26
+ "file_system",
27
+
28
+ # Future modules (uncomment when implemented)
29
+ # "text",
30
+ # "system",
31
+ # "network",
32
+ # "data",
33
+ # "crypto",
34
+ # "utilities",
35
+
36
+ # Common infrastructure
37
+ "exceptions",
38
+ "types",
39
+ ]
@@ -0,0 +1,60 @@
1
+ # Cryptographic Tools TODO
2
+
3
+ ## Overview
4
+ Hashing, encoding, and basic cryptographic utilities (no encryption/decryption).
5
+
6
+ ## Planned Modules
7
+
8
+ ### High Priority
9
+ - [ ] **Hashing** (`hashing.py`)
10
+ - File content hashing (MD5, SHA1, SHA256, SHA512)
11
+ - String hashing utilities
12
+ - Hash verification and comparison
13
+ - Checksum generation and validation
14
+ - Hash-based file integrity checking
15
+ - Bulk file hashing operations
16
+
17
+ - [ ] **Encoding** (`encoding.py`)
18
+ - Base64 encoding/decoding
19
+ - URL-safe base64 operations
20
+ - Hexadecimal encoding/decoding
21
+ - URL encoding/decoding
22
+ - HTML entity encoding/decoding
23
+ - Percent encoding utilities
24
+
25
+ ### Medium Priority
26
+ - [ ] **Utilities** (`utilities.py`)
27
+ - Random string generation
28
+ - UUID generation and validation
29
+ - Token generation (non-cryptographic)
30
+ - Data fingerprinting
31
+ - Simple obfuscation (not security)
32
+
33
+ - [ ] **Validation** (`validation.py`)
34
+ - Hash format validation
35
+ - Checksum verification
36
+ - Integrity checking utilities
37
+ - Format validation for encoded data
38
+
39
+ ### Low Priority
40
+ - [ ] **File Integrity** (`integrity.py`)
41
+ - File signature verification
42
+ - Batch integrity checking
43
+ - Integrity report generation
44
+ - File corruption detection
45
+
46
+ ## Important Notes
47
+ - **NO ENCRYPTION/DECRYPTION** - This violates the project's security principles
48
+ - Focus on data integrity and encoding only
49
+ - Use only well-established, standard algorithms
50
+ - Provide secure defaults
51
+ - Clear documentation about security limitations
52
+
53
+ ## Design Considerations
54
+ - Use standard library implementations where possible
55
+ - Clear separation between secure and non-secure operations
56
+ - Consistent error handling
57
+ - Performance considerations for large files
58
+ - Cross-platform compatibility
59
+ - Clear documentation of security properties
60
+ - Warning messages for deprecated hash algorithms
@@ -0,0 +1,6 @@
1
+ """Cryptographic tools for AI agents.
2
+
3
+ This module is not yet implemented. See TODO.md for planned functionality.
4
+ """
5
+
6
+ __all__ = [] # No functions available yet
@@ -0,0 +1,69 @@
1
+ # Data Tools TODO
2
+
3
+ ## Overview
4
+ Data structure utilities, validation, and serialization tools for AI agents.
5
+
6
+ ## Planned Modules
7
+
8
+ ### High Priority
9
+ - [ ] **Data Structures** (`structures.py`)
10
+ - Dictionary manipulation utilities
11
+ - List processing helpers
12
+ - Data flattening and unflattening
13
+ - Nested data structure navigation
14
+ - Data merging and comparison
15
+ - Safe data access patterns
16
+
17
+ - [ ] **Validation** (`validation.py`)
18
+ - Schema validation utilities
19
+ - Data type checking
20
+ - Range and constraint validation
21
+ - Required field validation
22
+ - Custom validation patterns
23
+ - Error aggregation and reporting
24
+
25
+ - [ ] **Serialization** (`serialization.py`)
26
+ - JSON serialization with error handling
27
+ - Pickle utilities (with security considerations)
28
+ - Custom object serialization
29
+ - Data format conversion
30
+ - Safe deserialization patterns
31
+
32
+ ### Medium Priority
33
+ - [ ] **Transformation** (`transform.py`)
34
+ - Data mapping and transformation
35
+ - Field renaming and restructuring
36
+ - Data type conversion
37
+ - Batch data processing
38
+ - Data cleaning utilities
39
+ - Duplicate detection and removal
40
+
41
+ - [ ] **Query** (`query.py`)
42
+ - Simple data querying (like JSONPath)
43
+ - Data filtering utilities
44
+ - Search and find operations
45
+ - Data aggregation helpers
46
+ - Sorting and grouping utilities
47
+
48
+ ### Low Priority
49
+ - [ ] **Caching** (`caching.py`)
50
+ - Simple in-memory caching
51
+ - LRU cache implementations
52
+ - Cache expiration handling
53
+ - Persistent cache utilities
54
+ - Cache statistics and monitoring
55
+
56
+ - [ ] **Streaming** (`streaming.py`)
57
+ - Large data processing utilities
58
+ - Streaming data processors
59
+ - Batch processing helpers
60
+ - Memory-efficient data handling
61
+
62
+ ## Design Considerations
63
+ - Memory efficiency for large datasets
64
+ - Type safety and validation
65
+ - Immutable data operations where possible
66
+ - Clear error messages and handling
67
+ - Performance considerations for bulk operations
68
+ - Security awareness for deserialization
69
+ - Consistent API design across modules
@@ -0,0 +1,6 @@
1
+ """Data tools for AI agents.
2
+
3
+ This module is not yet implemented. See TODO.md for planned functionality.
4
+ """
5
+
6
+ __all__ = [] # No functions available yet
@@ -0,0 +1,11 @@
1
+ """Common exceptions for basic-open-agent-tools."""
2
+
3
+
4
+ class BasicAgentToolsError(Exception):
5
+ """Base exception for all basic-open-agent-tools errors."""
6
+ pass
7
+
8
+
9
+ class FileSystemError(BasicAgentToolsError):
10
+ """Exception for file system operations."""
11
+ pass
@@ -0,0 +1,58 @@
1
+ # File System Tools TODO
2
+
3
+ ## Current Status
4
+ - ✅ Basic file operations (read, write, append) - implemented in `operations.py`
5
+ - ✅ Directory operations (create, list, delete) - implemented in `operations.py`
6
+ - ✅ File metadata and information - implemented in `info.py`
7
+ - ✅ Directory tree functionality - implemented in `tree.py`
8
+ - ✅ Path validation utilities - implemented in `validation.py`
9
+
10
+ ## Completed Tasks
11
+ - ✅ Moved functionality to modular structure (`operations.py`, `info.py`, `tree.py`, `validation.py`)
12
+ - ✅ Created proper `__init__.py` with organized exports
13
+ - ✅ Added enhanced functionality (directory tree with depth control)
14
+
15
+ ## Future Enhancements
16
+
17
+ ### High Priority
18
+ - [ ] **File Watching/Monitoring** (`watch.py`)
19
+ - Monitor file/directory changes
20
+ - Event-based file system notifications
21
+ - Polling-based monitoring for compatibility
22
+
23
+ - [ ] **File Permissions** (`permissions.py`)
24
+ - Cross-platform permission management
25
+ - Permission checking and validation
26
+ - Safe permission modification
27
+
28
+ ### Medium Priority
29
+ - [ ] **Advanced Operations** (`operations.py` extensions)
30
+ - Atomic file operations
31
+ - Temporary file management
32
+ - File locking mechanisms
33
+ - Bulk operations (batch copy, move, delete)
34
+
35
+ - [ ] **Path Utilities** (`paths.py`)
36
+ - Path normalization and validation
37
+ - Relative/absolute path conversion
38
+ - Path pattern matching
39
+ - Cross-platform path handling
40
+
41
+ ### Low Priority
42
+ - [ ] **File Comparison** (`compare.py`)
43
+ - File content comparison
44
+ - Directory structure comparison
45
+ - Checksums and integrity verification
46
+
47
+ - [ ] **Archive Operations** (`archives.py`)
48
+ - ZIP file creation/extraction
49
+ - TAR file operations
50
+ - Directory compression
51
+
52
+ ## Design Considerations
53
+ - Maintain cross-platform compatibility (Windows, macOS, Linux)
54
+ - Use pathlib for modern path handling
55
+ - Consistent error handling with custom exceptions
56
+ - Type hints for all functions
57
+ - Comprehensive docstrings and examples
58
+ - Security considerations for file operations
@@ -0,0 +1,73 @@
1
+ """File system tools for agent operations.
2
+
3
+ This module provides comprehensive file and directory operations organized into logical submodules:
4
+
5
+ - operations: Core file/directory operations (read, write, create, delete, copy, move)
6
+ - info: File information and existence checking
7
+ - tree: Directory tree listing functionality
8
+ - validation: Path validation utilities
9
+
10
+ All functions are also available directly from this module for convenience.
11
+ """
12
+
13
+ # Import all functions from submodules
14
+ from .operations import (
15
+ read_file_to_string,
16
+ write_file_from_string,
17
+ append_to_file,
18
+ list_directory_contents,
19
+ create_directory,
20
+ delete_file,
21
+ delete_directory,
22
+ move_file,
23
+ copy_file,
24
+ )
25
+
26
+ from .info import (
27
+ get_file_info,
28
+ file_exists,
29
+ directory_exists,
30
+ get_file_size,
31
+ is_empty_directory,
32
+ )
33
+
34
+ from .tree import (
35
+ list_all_directory_contents,
36
+ generate_directory_tree,
37
+ )
38
+
39
+ from .validation import (
40
+ validate_path,
41
+ validate_file_content,
42
+ )
43
+
44
+ # Re-export all functions at module level for convenience
45
+ __all__ = [
46
+ # File operations
47
+ "read_file_to_string",
48
+ "write_file_from_string",
49
+ "append_to_file",
50
+
51
+ # Directory operations
52
+ "list_directory_contents",
53
+ "create_directory",
54
+ "delete_file",
55
+ "delete_directory",
56
+ "move_file",
57
+ "copy_file",
58
+
59
+ # Information and checking
60
+ "get_file_info",
61
+ "file_exists",
62
+ "directory_exists",
63
+ "get_file_size",
64
+ "is_empty_directory",
65
+
66
+ # Tree operations
67
+ "list_all_directory_contents",
68
+ "generate_directory_tree",
69
+
70
+ # Validation utilities
71
+ "validate_path",
72
+ "validate_file_content",
73
+ ]
@@ -0,0 +1,118 @@
1
+ """File and directory information utilities."""
2
+
3
+ from typing import Dict, Union
4
+ from ..exceptions import FileSystemError
5
+ from .validation import validate_path
6
+
7
+
8
+ def get_file_info(file_path: str) -> Dict[str, Union[str, int, float, bool]]:
9
+ """Get file or directory information.
10
+
11
+ Args:
12
+ file_path: Path to the file or directory
13
+
14
+ Returns:
15
+ Dictionary with file info: size, modified_time, is_file, is_directory, etc.
16
+
17
+ Raises:
18
+ FileSystemError: If path doesn't exist or info can't be retrieved
19
+ """
20
+ path = validate_path(file_path, "get info")
21
+
22
+ if not path.exists():
23
+ raise FileSystemError(f"Path not found: {path}")
24
+
25
+ try:
26
+ stat = path.stat()
27
+ return {
28
+ "name": path.name,
29
+ "size": stat.st_size,
30
+ "modified_time": stat.st_mtime,
31
+ "is_file": path.is_file(),
32
+ "is_directory": path.is_dir(),
33
+ "is_symlink": path.is_symlink(),
34
+ "absolute_path": str(path),
35
+ "parent": str(path.parent),
36
+ "suffix": path.suffix,
37
+ "permissions": oct(stat.st_mode)[-3:]
38
+ }
39
+ except OSError as e:
40
+ raise FileSystemError(f"Failed to get info for {path}: {e}")
41
+
42
+
43
+ def file_exists(file_path: str) -> bool:
44
+ """Check if a file exists.
45
+
46
+ Args:
47
+ file_path: Path to check
48
+
49
+ Returns:
50
+ True if file exists, False otherwise
51
+ """
52
+ try:
53
+ path = validate_path(file_path, "check file existence")
54
+ return path.is_file()
55
+ except FileSystemError:
56
+ return False
57
+
58
+
59
+ def directory_exists(directory_path: str) -> bool:
60
+ """Check if a directory exists.
61
+
62
+ Args:
63
+ directory_path: Path to check
64
+
65
+ Returns:
66
+ True if directory exists, False otherwise
67
+ """
68
+ try:
69
+ path = validate_path(directory_path, "check directory existence")
70
+ return path.is_dir()
71
+ except FileSystemError:
72
+ return False
73
+
74
+
75
+ def get_file_size(file_path: str) -> int:
76
+ """Get file size in bytes.
77
+
78
+ Args:
79
+ file_path: Path to the file
80
+
81
+ Returns:
82
+ File size in bytes
83
+
84
+ Raises:
85
+ FileSystemError: If file doesn't exist or size can't be retrieved
86
+ """
87
+ path = validate_path(file_path, "get file size")
88
+
89
+ if not path.is_file():
90
+ raise FileSystemError(f"File not found: {path}")
91
+
92
+ try:
93
+ return path.stat().st_size
94
+ except OSError as e:
95
+ raise FileSystemError(f"Failed to get size for {path}: {e}")
96
+
97
+
98
+ def is_empty_directory(directory_path: str) -> bool:
99
+ """Check if a directory is empty.
100
+
101
+ Args:
102
+ directory_path: Path to the directory
103
+
104
+ Returns:
105
+ True if directory is empty, False otherwise
106
+
107
+ Raises:
108
+ FileSystemError: If directory doesn't exist or can't be read
109
+ """
110
+ path = validate_path(directory_path, "check empty directory")
111
+
112
+ if not path.is_dir():
113
+ raise FileSystemError(f"Directory not found: {path}")
114
+
115
+ try:
116
+ return not any(path.iterdir())
117
+ except OSError as e:
118
+ raise FileSystemError(f"Failed to check if directory is empty {path}: {e}")
@@ -0,0 +1,232 @@
1
+ """Core file and directory operations."""
2
+
3
+ import shutil
4
+ from typing import List
5
+ from ..exceptions import FileSystemError
6
+ from .validation import validate_path, validate_file_content
7
+
8
+
9
+ def read_file_to_string(file_path: str) -> str:
10
+ """Load string from a text file.
11
+
12
+ Args:
13
+ file_path: Path to the text file
14
+
15
+ Returns:
16
+ The file content as a string with leading/trailing whitespace stripped
17
+
18
+ Raises:
19
+ FileSystemError: If file doesn't exist or can't be read
20
+ """
21
+ path = validate_path(file_path, "read")
22
+
23
+ if not path.is_file():
24
+ raise FileSystemError(f"File not found: {path}")
25
+
26
+ try:
27
+ return path.read_text(encoding='utf-8').strip()
28
+ except (OSError, UnicodeDecodeError) as e:
29
+ raise FileSystemError(f"Failed to read file {path}: {e}")
30
+
31
+
32
+ def write_file_from_string(file_path: str, content: str) -> bool:
33
+ """Write string content to a text file.
34
+
35
+ Args:
36
+ file_path: Path to the output file
37
+ content: String content to write
38
+
39
+ Returns:
40
+ True if successful
41
+
42
+ Raises:
43
+ FileSystemError: If write operation fails
44
+ """
45
+ validate_file_content(content, "write")
46
+ path = validate_path(file_path, "write")
47
+
48
+ try:
49
+ path.parent.mkdir(parents=True, exist_ok=True)
50
+ path.write_text(content, encoding='utf-8')
51
+ return True
52
+ except OSError as e:
53
+ raise FileSystemError(f"Failed to write file {path}: {e}")
54
+
55
+
56
+ def append_to_file(file_path: str, content: str) -> bool:
57
+ """Append string content to a text file.
58
+
59
+ Args:
60
+ file_path: Path to the file
61
+ content: String content to append
62
+
63
+ Returns:
64
+ True if successful
65
+
66
+ Raises:
67
+ FileSystemError: If append operation fails
68
+ """
69
+ validate_file_content(content, "append")
70
+ path = validate_path(file_path, "append")
71
+
72
+ try:
73
+ path.parent.mkdir(parents=True, exist_ok=True)
74
+ with path.open('a', encoding='utf-8') as file:
75
+ file.write(content)
76
+ return True
77
+ except OSError as e:
78
+ raise FileSystemError(f"Failed to append to file {path}: {e}")
79
+
80
+
81
+ def list_directory_contents(directory_path: str, include_hidden: bool = False) -> List[str]:
82
+ """List contents of a directory.
83
+
84
+ Args:
85
+ directory_path: Path to the directory
86
+ include_hidden: Whether to include hidden files/directories
87
+
88
+ Returns:
89
+ Sorted list of file and directory names
90
+
91
+ Raises:
92
+ FileSystemError: If directory doesn't exist or can't be read
93
+ """
94
+ path = validate_path(directory_path, "list directory")
95
+
96
+ if not path.is_dir():
97
+ raise FileSystemError(f"Directory not found: {path}")
98
+
99
+ try:
100
+ contents = [item.name for item in path.iterdir()]
101
+ if not include_hidden:
102
+ contents = [name for name in contents if not name.startswith('.')]
103
+ return sorted(contents)
104
+ except OSError as e:
105
+ raise FileSystemError(f"Failed to list directory {path}: {e}")
106
+
107
+
108
+ def create_directory(directory_path: str) -> bool:
109
+ """Create a directory and any necessary parent directories.
110
+
111
+ Args:
112
+ directory_path: Path to the directory to create
113
+
114
+ Returns:
115
+ True if successful
116
+
117
+ Raises:
118
+ FileSystemError: If directory creation fails
119
+ """
120
+ path = validate_path(directory_path, "create directory")
121
+
122
+ try:
123
+ path.mkdir(parents=True, exist_ok=True)
124
+ return True
125
+ except OSError as e:
126
+ raise FileSystemError(f"Failed to create directory {path}: {e}")
127
+
128
+
129
+ def delete_file(file_path: str) -> bool:
130
+ """Delete a file.
131
+
132
+ Args:
133
+ file_path: Path to the file to delete
134
+
135
+ Returns:
136
+ True if successful (including if file doesn't exist)
137
+
138
+ Raises:
139
+ FileSystemError: If deletion fails
140
+ """
141
+ path = validate_path(file_path, "delete file")
142
+
143
+ try:
144
+ path.unlink(missing_ok=True)
145
+ return True
146
+ except OSError as e:
147
+ raise FileSystemError(f"Failed to delete file {path}: {e}")
148
+
149
+
150
+ def delete_directory(directory_path: str, recursive: bool = False) -> bool:
151
+ """Delete a directory.
152
+
153
+ Args:
154
+ directory_path: Path to the directory to delete
155
+ recursive: If True, delete directory and all contents recursively
156
+
157
+ Returns:
158
+ True if successful (including if directory doesn't exist)
159
+
160
+ Raises:
161
+ FileSystemError: If deletion fails
162
+ """
163
+ path = validate_path(directory_path, "delete directory")
164
+
165
+ if not path.exists():
166
+ return True
167
+
168
+ try:
169
+ if recursive:
170
+ shutil.rmtree(path)
171
+ else:
172
+ path.rmdir() # Only works if directory is empty
173
+ return True
174
+ except OSError as e:
175
+ raise FileSystemError(f"Failed to delete directory {path}: {e}")
176
+
177
+
178
+ def move_file(source_path: str, destination_path: str) -> bool:
179
+ """Move or rename a file or directory.
180
+
181
+ Args:
182
+ source_path: Current path of the file/directory
183
+ destination_path: New path for the file/directory
184
+
185
+ Returns:
186
+ True if successful
187
+
188
+ Raises:
189
+ FileSystemError: If move operation fails
190
+ """
191
+ src_path = validate_path(source_path, "move source")
192
+ dst_path = validate_path(destination_path, "move destination")
193
+
194
+ if not src_path.exists():
195
+ raise FileSystemError(f"Source path not found: {src_path}")
196
+
197
+ try:
198
+ dst_path.parent.mkdir(parents=True, exist_ok=True)
199
+ shutil.move(str(src_path), str(dst_path))
200
+ return True
201
+ except OSError as e:
202
+ raise FileSystemError(f"Failed to move {src_path} to {dst_path}: {e}")
203
+
204
+
205
+ def copy_file(source_path: str, destination_path: str) -> bool:
206
+ """Copy a file or directory.
207
+
208
+ Args:
209
+ source_path: Path of the source file/directory
210
+ destination_path: Path for the copied file/directory
211
+
212
+ Returns:
213
+ True if successful
214
+
215
+ Raises:
216
+ FileSystemError: If copy operation fails
217
+ """
218
+ src_path = validate_path(source_path, "copy source")
219
+ dst_path = validate_path(destination_path, "copy destination")
220
+
221
+ if not src_path.exists():
222
+ raise FileSystemError(f"Source path not found: {src_path}")
223
+
224
+ try:
225
+ dst_path.parent.mkdir(parents=True, exist_ok=True)
226
+ if src_path.is_file():
227
+ shutil.copy2(str(src_path), str(dst_path))
228
+ else:
229
+ shutil.copytree(str(src_path), str(dst_path))
230
+ return True
231
+ except OSError as e:
232
+ raise FileSystemError(f"Failed to copy {src_path} to {dst_path}: {e}")
@@ -0,0 +1,135 @@
1
+ """Directory tree listing functionality."""
2
+
3
+ from pathlib import Path
4
+ from typing import List
5
+ from ..exceptions import FileSystemError
6
+ from .validation import validate_path
7
+
8
+
9
+ def list_all_directory_contents(directory_path: str) -> str:
10
+ """Generate a tree of all contents in a directory and its subdirectories.
11
+
12
+ Args:
13
+ directory_path: Path to the root directory to list
14
+
15
+ Returns:
16
+ Tree-like string representation of directory contents
17
+
18
+ Raises:
19
+ FileSystemError: If directory doesn't exist or can't be read
20
+ """
21
+ path = validate_path(directory_path, "list all directory contents")
22
+
23
+ if not path.is_dir():
24
+ raise FileSystemError(f"Directory not found: {path}")
25
+
26
+ def _should_include(item_path: Path) -> bool:
27
+ """Determine if an item should be included (exclude hidden files)."""
28
+ return not item_path.name.startswith('.')
29
+
30
+ def _generate_tree(current_path: Path, prefix: str = '', is_last: bool = True) -> List[str]:
31
+ """Recursively generate tree representation."""
32
+ tree_lines = []
33
+
34
+ # Prepare prefix for current level
35
+ current_prefix = prefix + ('└── ' if is_last else '├── ')
36
+ next_prefix = prefix + (' ' if is_last else '│ ')
37
+
38
+ # Add current directory/file to tree
39
+ tree_lines.append(f"{current_prefix}{current_path.name}")
40
+
41
+ # If it's a directory, explore its contents
42
+ if current_path.is_dir():
43
+ try:
44
+ # Get contents, filtering hidden files
45
+ contents = [
46
+ item for item in sorted(current_path.iterdir())
47
+ if _should_include(item)
48
+ ]
49
+
50
+ # Recursively add subdirectories and files
51
+ for i, item in enumerate(contents):
52
+ is_last_item = (i == len(contents) - 1)
53
+ tree_lines.extend(
54
+ _generate_tree(item, next_prefix, is_last_item)
55
+ )
56
+ except OSError as e:
57
+ tree_lines.append(f" [Error reading directory: {e}]")
58
+
59
+ return tree_lines
60
+
61
+ try:
62
+ # Generate tree-like representation
63
+ return '\n'.join(_generate_tree(path))
64
+
65
+ except OSError as e:
66
+ raise FileSystemError(f"Failed to list directory contents {path}: {e}")
67
+
68
+
69
+ def generate_directory_tree(directory_path: str, max_depth: int = None, include_hidden: bool = False) -> str:
70
+ """Generate a customizable directory tree.
71
+
72
+ Args:
73
+ directory_path: Path to the root directory to list
74
+ max_depth: Maximum depth to traverse (None for unlimited)
75
+ include_hidden: Whether to include hidden files/directories
76
+
77
+ Returns:
78
+ Tree-like string representation of directory contents
79
+
80
+ Raises:
81
+ FileSystemError: If directory doesn't exist or can't be read
82
+ """
83
+ path = validate_path(directory_path, "generate directory tree")
84
+
85
+ if not path.is_dir():
86
+ raise FileSystemError(f"Directory not found: {path}")
87
+
88
+ def _should_include(item_path: Path) -> bool:
89
+ """Determine if an item should be included."""
90
+ if not include_hidden and item_path.name.startswith('.'):
91
+ return False
92
+ return True
93
+
94
+ def _generate_tree(current_path: Path, prefix: str = '', depth: int = 0, is_last: bool = True) -> List[str]:
95
+ """Recursively generate tree representation with depth control."""
96
+ tree_lines = []
97
+
98
+ # Check depth limit
99
+ if max_depth is not None and depth > max_depth:
100
+ return tree_lines
101
+
102
+ # Prepare prefix for current level
103
+ current_prefix = prefix + ('└── ' if is_last else '├── ')
104
+ next_prefix = prefix + (' ' if is_last else '│ ')
105
+
106
+ # Add current directory/file to tree
107
+ tree_lines.append(f"{current_prefix}{current_path.name}")
108
+
109
+ # If it's a directory and we haven't reached max depth, explore its contents
110
+ if current_path.is_dir() and (max_depth is None or depth < max_depth):
111
+ try:
112
+ # Get contents, filtering based on include_hidden
113
+ contents = [
114
+ item for item in sorted(current_path.iterdir())
115
+ if _should_include(item)
116
+ ]
117
+
118
+ # Recursively add subdirectories and files
119
+ for i, item in enumerate(contents):
120
+ is_last_item = (i == len(contents) - 1)
121
+ tree_lines.extend(
122
+ _generate_tree(item, next_prefix, depth + 1, is_last_item)
123
+ )
124
+ except OSError as e:
125
+ tree_lines.append(f"{next_prefix}[Error reading directory: {e}]")
126
+
127
+ return tree_lines
128
+
129
+ try:
130
+ # Generate tree-like representation
131
+ result = _generate_tree(path)
132
+ return '\n'.join(result) if result else path.name
133
+
134
+ except OSError as e:
135
+ raise FileSystemError(f"Failed to generate directory tree for {path}: {e}")
@@ -0,0 +1,40 @@
1
+ """Path validation utilities for file system operations."""
2
+
3
+ from pathlib import Path
4
+ from ..exceptions import FileSystemError
5
+
6
+
7
+ def validate_path(path: str, operation: str) -> Path:
8
+ """Validate and convert path string to Path object.
9
+
10
+ Args:
11
+ path: Path string to validate
12
+ operation: Operation name for error messages
13
+
14
+ Returns:
15
+ Validated Path object
16
+
17
+ Raises:
18
+ FileSystemError: If path is invalid
19
+ """
20
+ if not path or not isinstance(path, str):
21
+ raise FileSystemError(f"Invalid path for {operation}: {path}")
22
+
23
+ try:
24
+ return Path(path).resolve()
25
+ except (OSError, ValueError) as e:
26
+ raise FileSystemError(f"Invalid path for {operation}: {path} - {e}")
27
+
28
+
29
+ def validate_file_content(content: str, operation: str) -> None:
30
+ """Validate file content for write operations.
31
+
32
+ Args:
33
+ content: Content to validate
34
+ operation: Operation name for error messages
35
+
36
+ Raises:
37
+ FileSystemError: If content is not a string
38
+ """
39
+ if not isinstance(content, str):
40
+ raise FileSystemError(f"Content must be a string for {operation}")
@@ -0,0 +1,55 @@
1
+ # Network Tools TODO
2
+
3
+ ## Overview
4
+ Local network utilities and validation tools (no HTTP/API operations).
5
+
6
+ ## Planned Modules
7
+
8
+ ### High Priority
9
+ - [ ] **Validation** (`validation.py`)
10
+ - URL format validation
11
+ - IP address validation (IPv4/IPv6)
12
+ - Port number validation
13
+ - Domain name validation
14
+ - Email format validation
15
+ - Network address validation
16
+
17
+ - [ ] **Local Utilities** (`local.py`)
18
+ - Local network interface enumeration
19
+ - Available port checking
20
+ - Local IP address discovery
21
+ - Network connectivity testing (ping-like)
22
+ - Local hostname resolution
23
+ - MAC address utilities
24
+
25
+ ### Medium Priority
26
+ - [ ] **Discovery** (`discovery.py`)
27
+ - Local service discovery
28
+ - Network scanning (local subnet only)
29
+ - Port scanning (local only)
30
+ - Device discovery on local network
31
+ - Network topology detection
32
+
33
+ - [ ] **Address Utilities** (`addresses.py`)
34
+ - IP address manipulation
35
+ - Subnet calculations
36
+ - CIDR notation handling
37
+ - Network range operations
38
+ - IP address sorting and comparison
39
+
40
+ ### Low Priority
41
+ - [ ] **Protocol Utilities** (`protocols.py`)
42
+ - Basic protocol detection
43
+ - Port-to-service mapping
44
+ - Network protocol validation
45
+ - Common port definitions
46
+
47
+ ## Design Considerations
48
+ - No external HTTP/API calls (follows project principle)
49
+ - Focus on local network operations only
50
+ - Cross-platform network interface handling
51
+ - Security considerations (no unauthorized scanning)
52
+ - IPv6 compatibility
53
+ - Proper error handling for network operations
54
+ - Timeout handling for network checks
55
+ - Permission awareness for network operations
@@ -0,0 +1,6 @@
1
+ """Network tools for AI agents.
2
+
3
+ This module is not yet implemented. See TODO.md for planned functionality.
4
+ """
5
+
6
+ __all__ = [] # No functions available yet
@@ -0,0 +1,62 @@
1
+ # System Tools TODO
2
+
3
+ ## Overview
4
+ System-level operations and information gathering tools for AI agents.
5
+
6
+ ## Planned Modules
7
+
8
+ ### High Priority
9
+ - [ ] **Process Management** (`process.py`)
10
+ - Command execution with timeout
11
+ - Process spawning and monitoring
12
+ - Subprocess communication
13
+ - Process tree operations
14
+ - Safe command execution
15
+ - Return code handling
16
+
17
+ - [ ] **Environment Management** (`environment.py`)
18
+ - Environment variable access
19
+ - PATH manipulation
20
+ - Working directory management
21
+ - User/system information
22
+ - Platform detection
23
+ - Shell detection
24
+
25
+ ### Medium Priority
26
+ - [ ] **Resource Monitoring** (`resources.py`)
27
+ - CPU usage monitoring
28
+ - Memory usage information
29
+ - Disk space checking
30
+ - System load information
31
+ - Process resource usage
32
+ - Basic performance metrics
33
+
34
+ - [ ] **System Information** (`info.py`)
35
+ - Operating system details
36
+ - Hardware information (basic)
37
+ - Network interface enumeration
38
+ - Timezone and locale information
39
+ - System uptime and boot time
40
+ - Available system tools detection
41
+
42
+ ### Low Priority
43
+ - [ ] **Service Management** (`services.py`)
44
+ - System service status checking
45
+ - Basic service interaction
46
+ - Daemon/service utilities
47
+ - Process management helpers
48
+
49
+ - [ ] **Logging Integration** (`logging.py`)
50
+ - System log access (where available)
51
+ - Log file monitoring
52
+ - Structured logging helpers
53
+ - Log rotation utilities
54
+
55
+ ## Design Considerations
56
+ - Cross-platform compatibility (Windows, macOS, Linux)
57
+ - Secure command execution (avoid shell injection)
58
+ - Proper error handling for system operations
59
+ - Resource cleanup (processes, file handles)
60
+ - Permission and security awareness
61
+ - Timeout handling for long-running operations
62
+ - Non-blocking operations where possible
@@ -0,0 +1,6 @@
1
+ """System tools for AI agents.
2
+
3
+ This module is not yet implemented. See TODO.md for planned functionality.
4
+ """
5
+
6
+ __all__ = [] # No functions available yet
@@ -0,0 +1,66 @@
1
+ # Text Processing Tools TODO
2
+
3
+ ## Overview
4
+ Text manipulation, processing, and format conversion tools for AI agents.
5
+
6
+ ## Planned Modules
7
+
8
+ ### High Priority
9
+ - [ ] **Text Processing** (`processing.py`)
10
+ - String cleaning and normalization
11
+ - Whitespace handling (strip, normalize, dedent)
12
+ - Case conversion utilities
13
+ - Text splitting and joining
14
+ - Line ending normalization
15
+ - Unicode handling and normalization
16
+
17
+ - [ ] **Search Operations** (`search.py`)
18
+ - Pattern matching and regex utilities
19
+ - Text search and replacement
20
+ - Fuzzy string matching
21
+ - Text extraction from patterns
22
+ - Multi-line text processing
23
+
24
+ - [ ] **Format Handling** (`formats.py`)
25
+ - JSON parsing and formatting
26
+ - CSV reading and writing
27
+ - YAML processing (if dependency allowed)
28
+ - Basic markdown processing
29
+ - INI/config file parsing
30
+
31
+ ### Medium Priority
32
+ - [ ] **Encoding/Decoding** (`encoding.py`)
33
+ - Character encoding detection
34
+ - Encoding conversion (UTF-8, ASCII, etc.)
35
+ - URL encoding/decoding
36
+ - HTML entity encoding/decoding
37
+ - Base64 text operations
38
+
39
+ - [ ] **Text Analysis** (`analysis.py`)
40
+ - Character and word counting
41
+ - Basic text statistics
42
+ - Language detection (basic)
43
+ - Text similarity comparison
44
+ - Keyword extraction
45
+
46
+ ### Low Priority
47
+ - [ ] **Template Processing** (`templates.py`)
48
+ - Simple string templating
49
+ - Variable substitution
50
+ - Basic template engine
51
+ - Configuration templating
52
+
53
+ - [ ] **Validation** (`validation.py`)
54
+ - Text format validation
55
+ - Input sanitization
56
+ - Content filtering
57
+ - Schema-based text validation
58
+
59
+ ## Design Considerations
60
+ - Keep dependencies minimal (prefer standard library)
61
+ - Handle different encodings gracefully
62
+ - Provide both simple and advanced APIs
63
+ - Consistent error handling
64
+ - Memory-efficient for large texts
65
+ - Cross-platform line ending handling
66
+ - Security considerations for text processing
@@ -0,0 +1,6 @@
1
+ """Text processing tools for AI agents.
2
+
3
+ This module is not yet implemented. See TODO.md for planned functionality.
4
+ """
5
+
6
+ __all__ = [] # No functions available yet
@@ -0,0 +1,9 @@
1
+ """Common type definitions for basic-open-agent-tools."""
2
+
3
+ from typing import Union
4
+ from pathlib import Path
5
+
6
+ # Common type aliases currently in use
7
+ PathLike = Union[str, Path]
8
+
9
+ # Additional types will be added as modules are implemented
@@ -0,0 +1,79 @@
1
+ # Utilities TODO
2
+
3
+ ## Overview
4
+ Common utilities and helper functions that don't fit into other categories.
5
+
6
+ ## Planned Modules
7
+
8
+ ### High Priority
9
+ - [ ] **Logging** (`logging.py`)
10
+ - Structured logging setup
11
+ - Log formatter utilities
12
+ - Log level management
13
+ - File and console logging
14
+ - Log rotation helpers
15
+ - Context-aware logging
16
+
17
+ - [ ] **Configuration** (`configuration.py`)
18
+ - Configuration file management
19
+ - Environment-based configuration
20
+ - Configuration validation
21
+ - Default value handling
22
+ - Configuration merging
23
+ - INI, JSON, YAML config support
24
+
25
+ - [ ] **Caching** (`caching.py`)
26
+ - Simple in-memory caching
27
+ - File-based caching
28
+ - Cache expiration policies
29
+ - LRU cache implementations
30
+ - Cache statistics
31
+ - Thread-safe caching
32
+
33
+ ### Medium Priority
34
+ - [ ] **Timing** (`timing.py`)
35
+ - Execution timing utilities
36
+ - Timeout decorators
37
+ - Rate limiting helpers
38
+ - Retry mechanisms with backoff
39
+ - Performance profiling helpers
40
+ - Scheduling utilities
41
+
42
+ - [ ] **Decorators** (`decorators.py`)
43
+ - Common function decorators
44
+ - Retry decorators
45
+ - Timeout decorators
46
+ - Memoization decorators
47
+ - Logging decorators
48
+ - Validation decorators
49
+
50
+ - [ ] **Error Handling** (`errors.py`)
51
+ - Custom exception classes
52
+ - Error reporting utilities
53
+ - Exception chaining helpers
54
+ - Error context management
55
+ - Graceful error handling patterns
56
+
57
+ ### Low Priority
58
+ - [ ] **Helpers** (`helpers.py`)
59
+ - Common utility functions
60
+ - Data conversion helpers
61
+ - Type checking utilities
62
+ - Default value helpers
63
+ - Function composition utilities
64
+
65
+ - [ ] **Testing** (`testing.py`)
66
+ - Test utilities and helpers
67
+ - Mock data generation
68
+ - Test fixture management
69
+ - Assertion helpers
70
+ - Test environment setup
71
+
72
+ ## Design Considerations
73
+ - Keep modules focused and cohesive
74
+ - Provide both simple and advanced APIs
75
+ - Thread-safety where applicable
76
+ - Memory efficiency
77
+ - Clear documentation and examples
78
+ - Minimal external dependencies
79
+ - Cross-platform compatibility
@@ -0,0 +1,6 @@
1
+ """Utility tools for AI agents.
2
+
3
+ This module is not yet implemented. See TODO.md for planned functionality.
4
+ """
5
+
6
+ __all__ = [] # No functions available yet
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: basic-open-agent-tools
3
+ Version: 0.1.0
4
+ Summary: An open foundational toolkit providing essential components for building AI agents with minimal dependencies for local (non-HTTP/API) actions.
5
+ Project-URL: Homepage, https://github.com/open-agent-tools/basic-open-agent-tools
6
+ Project-URL: Documentation, https://github.com/open-agent-tools/basic-open-agent-tools#readme
7
+ Project-URL: Repository, https://github.com/open-agent-tools/basic-open-agent-tools
8
+ Project-URL: Issues, https://github.com/open-agent-tools/basic-open-agent-tools/issues
9
+ Author-email: Open Agent Tools <info@openagenttools.org>
10
+ License: MIT License
11
+
12
+ Copyright (c) 2025 Open Agent Tools
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: agents,ai,automation,local-tools,toolkit
33
+ Classifier: Development Status :: 3 - Alpha
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3.8
39
+ Classifier: Programming Language :: Python :: 3.9
40
+ Classifier: Programming Language :: Python :: 3.10
41
+ Classifier: Programming Language :: Python :: 3.11
42
+ Classifier: Programming Language :: Python :: 3.12
43
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
44
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
45
+ Requires-Python: >=3.8
46
+ Provides-Extra: dev
47
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
48
+ Requires-Dist: pre-commit>=3.0.0; extra == 'dev'
49
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
50
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
51
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
52
+ Provides-Extra: test
53
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'test'
54
+ Requires-Dist: pytest>=7.0.0; extra == 'test'
55
+ Description-Content-Type: text/markdown
56
+
57
+ # basic-open-agent-tools
58
+
59
+ An open foundational toolkit providing essential components for building AI agents with minimal dependencies for local (non-HTTP/API) actions. Designed to offer core utilities and interfaces that developers can easily integrate into their own agents to avoid excess boilerplate, while being simpler than solutions requiring MCP or A2A.
60
+
61
+ ## Installation
62
+
63
+ ```bash
64
+ pip install basic-open-agent-tools
65
+ ```
66
+
67
+ Or with UV:
68
+ ```bash
69
+ uv add basic-open-agent-tools
70
+ ```
71
+
72
+ ## Usage
73
+
74
+ ```python
75
+ from basic_open_agent_tools import file_system
76
+
77
+ # File operations
78
+ content = file_system.read_file_to_string("file.txt")
79
+ file_system.write_file_from_string("output.txt", "Hello!")
80
+
81
+ # Directory operations
82
+ files = file_system.list_directory_contents("/path/to/dir")
83
+ file_system.create_directory("new_dir")
84
+ ```
85
+
86
+
87
+
88
+
89
+ # Best Practices for Contributors and Reviewers
90
+
91
+ ## Regularly Sync Your Fork/Branch:
92
+
93
+ Before starting new work or submitting a PR, git pull upstream main to get the latest changes into your local main branch, then rebase your feature branch on top of it.
94
+
95
+ ## Small, Focused Pull Requests:
96
+
97
+ Break down large features into smaller, atomic PRs.
98
+
99
+ ## Clear Titles and Descriptions:
100
+
101
+ Use a consistent format (e.g., "Feat: Add user profile page," "Fix: Resolve login bug"). Include context, what changed, why, and how to test. Link to related issues (e.g., "Closes #123").
102
+
103
+ ## Use Draft Pull Requests:
104
+
105
+ Contributors can open PRs as "Draft" and mark them "Ready for review" when complete. Draft PRs won't trigger required status checks or reviews.
106
+
107
+ ## Descriptive Commit Messages:
108
+
109
+ Add well-written commit messages (subject line + body for details).
110
+
111
+ ## Self-Review First:
112
+
113
+ Contributors should review their own PRs thoroughly before requesting reviews.
114
+
115
+ ## Responsive to Feedback:
116
+
117
+ Contributors should address comments and questions from reviewers promptly. If changes are requested, push new commits to the same branch; the PR will automatically update.
118
+
119
+
120
+
@@ -0,0 +1,25 @@
1
+ basic_open_agent_tools/__init__.py,sha256=_SYS6OtAQSbRN_Zb4eis6d4yq_fxVVCyEPBRJR2zn9s,800
2
+ basic_open_agent_tools/exceptions.py,sha256=FYgYp8GCcxfY_BGQgp1W5EnRCZSqBBpANbc1Zo4fWfY,269
3
+ basic_open_agent_tools/types.py,sha256=_p4m9KtSsNkCgscK2P2zrMNv0p-cWKdj1URGRSFDu-M,237
4
+ basic_open_agent_tools/crypto/TODO.md,sha256=Hur8_7AKP4OJIYn06Je5iDIbjn4hV6YPdBYQ-pTmj5A,1824
5
+ basic_open_agent_tools/crypto/__init__.py,sha256=ycEvqObFD1GOrR7ttr3Xay-Rwc8f-e2F7SMmLUXLlLE,162
6
+ basic_open_agent_tools/data/TODO.md,sha256=SETVwuxUkP9AoDm01yYQJ9aJHVJC-EVbBBWrIo4tG5w,1977
7
+ basic_open_agent_tools/data/__init__.py,sha256=8tkNs8AIEJLSQjDYE14ry8EV7Zi0E6yMNeg4r4STnGo,153
8
+ basic_open_agent_tools/file_system/TODO.md,sha256=_geHQx_hzmCv-hyXygOY4k7UCq7vO1vs94MfWA9IofY,2002
9
+ basic_open_agent_tools/file_system/__init__.py,sha256=GKslHUOcWRcBSVgYDSEJkcjkdl6Bya8FdYzGL8B5T2s,1655
10
+ basic_open_agent_tools/file_system/info.py,sha256=MJpjyoBcFxBI3wq_rsrbPuAqAlpnezuNd0Cje4Y-ye8,3110
11
+ basic_open_agent_tools/file_system/operations.py,sha256=nRgff4FyZQ089nXk0J8UA66JCA_gTjsySSGb7sIA2Og,6513
12
+ basic_open_agent_tools/file_system/tree.py,sha256=El1L8e67rm7pqrYqFBXXxtMo3Wl1tfInnH2NZ6w8yDg,5130
13
+ basic_open_agent_tools/file_system/validation.py,sha256=8DLOAqsJM_Oi-HCMEfuCCTAqRwtjnpu5mJKXtRjTkx4,1168
14
+ basic_open_agent_tools/network/TODO.md,sha256=1XgSXg9iBo0vGlLWtiS_TpTGq_B_pyuM3VI90LvymZw,1572
15
+ basic_open_agent_tools/network/__init__.py,sha256=oz5dLofvEURWmjBSv5F_oBcW0S6Fif3A41Im_WgSMcQ,156
16
+ basic_open_agent_tools/system/TODO.md,sha256=gv2b0loew0-wd7ZBorPteXGp-MgWBYu9zNj2P1_aBfc,1754
17
+ basic_open_agent_tools/system/__init__.py,sha256=AzFfXB_xU3ky1SUUW04drvvu4Fpy5ouduu1RbaNkrCI,155
18
+ basic_open_agent_tools/text/TODO.md,sha256=t7JMeOgMtb6GIyDJJH_HmgnhfPsbymxLmF17gZu_JQ8,1869
19
+ basic_open_agent_tools/text/__init__.py,sha256=oaClrpc_F_lSeuhr7MOyNAGjgbQJjMK9pWrQ49RhCCU,164
20
+ basic_open_agent_tools/utilities/TODO.md,sha256=OIAVtnrawLU5qZpyW3kTvHiHfPpQkRrNhRtz1r3577c,1992
21
+ basic_open_agent_tools/utilities/__init__.py,sha256=fIq1GU6ryoQE8rLpgGpvhkFoM62HLWIz0N4M9HWotSc,156
22
+ basic_open_agent_tools-0.1.0.dist-info/METADATA,sha256=kaOt0aGsMV-5UZ549DO1vClck9NfrgoLAb3spsV7hY8,4964
23
+ basic_open_agent_tools-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
24
+ basic_open_agent_tools-0.1.0.dist-info/licenses/LICENSE,sha256=4yVsLRHKwmGobVox6N7LAsrmXo52Sytn6XFnHgxXGnE,1073
25
+ basic_open_agent_tools-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Open Agent Tools
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.