diskii 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. diskii-0.2.0/LICENSE +15 -0
  2. diskii-0.2.0/PKG-INFO +286 -0
  3. diskii-0.2.0/README.md +261 -0
  4. diskii-0.2.0/pyproject.toml +100 -0
  5. diskii-0.2.0/src/diskii/__init__.py +140 -0
  6. diskii-0.2.0/src/diskii/__main__.py +7 -0
  7. diskii-0.2.0/src/diskii/addressing.py +129 -0
  8. diskii-0.2.0/src/diskii/basic/__init__.py +81 -0
  9. diskii-0.2.0/src/diskii/basic/applesoft/__init__.py +11 -0
  10. diskii-0.2.0/src/diskii/basic/applesoft/detokenizer.py +176 -0
  11. diskii-0.2.0/src/diskii/basic/applesoft/tokenizer.py +399 -0
  12. diskii-0.2.0/src/diskii/basic/applesoft/validator.py +140 -0
  13. diskii-0.2.0/src/diskii/basic/common.py +359 -0
  14. diskii-0.2.0/src/diskii/basic/common_validator.py +540 -0
  15. diskii-0.2.0/src/diskii/basic/integer/__init__.py +11 -0
  16. diskii-0.2.0/src/diskii/basic/integer/detokenizer.py +400 -0
  17. diskii-0.2.0/src/diskii/basic/integer/tokenizer.py +442 -0
  18. diskii-0.2.0/src/diskii/basic/integer/validator.py +394 -0
  19. diskii-0.2.0/src/diskii/basic/tokens.py +338 -0
  20. diskii-0.2.0/src/diskii/basic_tokenizer.py +165 -0
  21. diskii-0.2.0/src/diskii/basic_tokens.py +19 -0
  22. diskii-0.2.0/src/diskii/cli/__init__.py +5 -0
  23. diskii-0.2.0/src/diskii/cli/commands/__init__.py +1 -0
  24. diskii-0.2.0/src/diskii/cli/commands/add.py +203 -0
  25. diskii-0.2.0/src/diskii/cli/commands/basic.py +212 -0
  26. diskii-0.2.0/src/diskii/cli/commands/convert.py +151 -0
  27. diskii-0.2.0/src/diskii/cli/commands/create.py +180 -0
  28. diskii-0.2.0/src/diskii/cli/commands/extract.py +203 -0
  29. diskii-0.2.0/src/diskii/cli/commands/info.py +268 -0
  30. diskii-0.2.0/src/diskii/cli/main.py +262 -0
  31. diskii-0.2.0/src/diskii/cli/utils.py +160 -0
  32. diskii-0.2.0/src/diskii/detection.py +422 -0
  33. diskii-0.2.0/src/diskii/disk_creator.py +370 -0
  34. diskii-0.2.0/src/diskii/dos32.py +390 -0
  35. diskii-0.2.0/src/diskii/dos33.py +385 -0
  36. diskii-0.2.0/src/diskii/dos_ordered_block_reader.py +286 -0
  37. diskii-0.2.0/src/diskii/dos_writer.py +501 -0
  38. diskii-0.2.0/src/diskii/exceptions.py +119 -0
  39. diskii-0.2.0/src/diskii/file_operations.py +242 -0
  40. diskii-0.2.0/src/diskii/file_reading.py +148 -0
  41. diskii-0.2.0/src/diskii/file_type_conversion.py +150 -0
  42. diskii-0.2.0/src/diskii/fileentry.py +599 -0
  43. diskii-0.2.0/src/diskii/image.py +637 -0
  44. diskii-0.2.0/src/diskii/prodos.py +605 -0
  45. diskii-0.2.0/src/diskii/prodos_ordered_sector_reader.py +293 -0
  46. diskii-0.2.0/src/diskii/prodos_types.py +279 -0
  47. diskii-0.2.0/src/diskii/prodos_writer.py +653 -0
diskii-0.2.0/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2025, Seth Kushniryk
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diskii-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,286 @@
1
+ Metadata-Version: 2.3
2
+ Name: diskii
3
+ Version: 0.2.0
4
+ Summary: diskii - Apple II Disk Image Tool & Library
5
+ License: ISC
6
+ Keywords: apple2,apple-ii,disk-image,prodos,dos33,retro-computing
7
+ Author: Seth Kushniryk
8
+ Author-email: seth@kushniryk.com
9
+ Requires-Python: >=3.13
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: License :: OSI Approved :: ISC License (ISCL)
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: System :: Archiving
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: System :: Filesystems
20
+ Project-URL: Bug Reports, https://todo.sr.ht/~sethkush/diskii
21
+ Project-URL: Documentation, https://git.sr.ht/~sethkush/diskii/tree/master/item/docs
22
+ Project-URL: Homepage, https://git.sr.ht/~sethkush/diskii
23
+ Project-URL: Source, https://git.sr.ht/~sethkush/diskii
24
+ Description-Content-Type: text/markdown
25
+
26
+ # diskii - Apple II Disk Image Tool & Library
27
+
28
+ **diskii** is both a command-line utility and Python library for reading, writing, and manipulating Apple II disk images. It supports both DOS 3.3 and ProDOS filesystems across various image formats.
29
+
30
+ ## Features
31
+
32
+ ### ✅ **Disk Image Reading**
33
+ - **Complete DOS 3.3 support**: Read catalogs, extract files, handle all file types (T/I/A/B/S/R)
34
+ - **Full ProDOS support**: Volume directories, subdirectories, all storage types (seedling/sapling/tree)
35
+ - **DOS 3.2 support**: Read 13-sector disk images (.d13 format)
36
+ - **Multiple image formats**: .dsk, .do, .po, .hdv, .d13
37
+ - **Automatic format detection**: Smart detection based on file extension and content analysis
38
+
39
+ ### ✅ **File Operations**
40
+ - **File extraction**: Read any file from disk images to host filesystem
41
+ - **File writing**: Create new files on disk images with proper metadata
42
+ - **File type preservation**: Maintain Apple II file types and auxiliary information
43
+ - **Cross-format operations**: Copy files between DOS 3.3 and ProDOS images
44
+
45
+ ### ✅ **Disk Image Creation**
46
+ - **Blank disk creation**: Create empty DOS 3.3, DOS 3.2, and ProDOS images
47
+ - **Multiple sizes supported**: Standard 140K disks up to 32MB ProDOS volumes
48
+ - **Proper filesystem initialization**: Correct VTOC, catalogs, and volume bitmaps
49
+
50
+ ### ✅ **Advanced Features**
51
+ - **Hierarchical directory support**: Full ProDOS subdirectory navigation
52
+ - **Sparse file handling**: Efficient handling of ProDOS sparse files
53
+ - **Free space tracking**: Volume bitmap and VTOC management
54
+ - **BASIC (de)tokenization**: Convert between tokenized and text BASIC programs
55
+ - **BASIC syntax validation**: ROM-compliant syntax checking for Apple II BASIC programs
56
+ - **Robust error handling**: Graceful handling of corrupted or invalid images
57
+ - **Type-safe**: Full type annotations throughout
58
+ - **Comprehensive testing**: Extensive test suite with real disk images
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ pip install diskii
64
+ ```
65
+
66
+ Or with Poetry:
67
+
68
+ ```bash
69
+ poetry add diskii
70
+ ```
71
+
72
+ ## Command Line Usage
73
+
74
+ diskii provides a comprehensive command-line interface for disk image manipulation:
75
+
76
+ ```bash
77
+ # Show disk information
78
+ diskii info mydisk.dsk
79
+
80
+ # Extract all files from a disk
81
+ diskii extract mydisk.po
82
+
83
+ # Extract specific files
84
+ diskii extract mydisk.dsk HELLO.BAS
85
+
86
+ # Add files to a disk
87
+ diskii add mydisk.po myfile.txt
88
+
89
+ # Create blank disk images
90
+ diskii create blank.po --name MYDISK
91
+
92
+ # Convert between sector orderings
93
+ diskii convert mydisk.dsk output.po
94
+
95
+ # BASIC program utilities
96
+ diskii basic detokenize HELLO.BAS
97
+ diskii basic tokenize myprogram.txt --variant applesoft
98
+ diskii basic validate myprogram.txt
99
+ ```
100
+
101
+ For detailed help on any command:
102
+ ```bash
103
+ diskii --help
104
+ diskii <command> --help
105
+ ```
106
+
107
+ ## Python Library Usage
108
+
109
+ ```python
110
+ import diskii
111
+
112
+ # Open any disk image - format detected automatically
113
+ with diskii.open_disk_image("mydisk.dsk") as image:
114
+ # Get volume information
115
+ print(f"Volume: {image.get_volume_name()}")
116
+ print(f"Format: {image.format}")
117
+
118
+ # List all files
119
+ files = image.get_file_list()
120
+ for file_entry in files:
121
+ print(f"{file_entry.filename} ({file_entry.size} bytes)")
122
+
123
+ # Extract file
124
+ data = file_entry.read_data()
125
+ with open(file_entry.filename, 'wb') as f:
126
+ f.write(data)
127
+
128
+ # Create a new blank disk
129
+ diskii.disk_creator.create_blank_prodos_image("new_disk.po", "MY.DISK")
130
+
131
+ # Add files to existing disk (requires read_only=False)
132
+ with diskii.open_disk_image("mydisk.po", read_only=False) as image:
133
+ image.create_file("HELLO.TXT", 0x04, b"Hello from diskii!")
134
+
135
+ # BASIC program tokenization
136
+ import diskii
137
+
138
+ # Tokenize Applesoft BASIC program
139
+ program_text = '''10 HOME
140
+ 20 PRINT "HELLO WORLD!"
141
+ 30 END'''
142
+
143
+ tokenized = diskii.tokenize_applesoft(program_text)
144
+ detokenized = diskii.detokenize_applesoft(tokenized)
145
+
146
+ # Work with BASIC files on disk images
147
+ with diskii.open_disk_image("mydisk.po", read_only=False) as image:
148
+ # Save as tokenized BASIC program
149
+ image.create_file("HELLO.BAS", 0xFC, tokenized)
150
+
151
+ # Read BASIC file and detokenize automatically
152
+ files = image.get_file_list()
153
+ for file_entry in files:
154
+ if file_entry.is_basic_file():
155
+ plain_text = file_entry.read_as_text() # Auto-detokenizes
156
+ raw_tokens = file_entry.read_as_tokens() # Raw tokenized data
157
+
158
+ # BASIC syntax validation with ROM compliance
159
+ program_text = '''10 HOME
160
+ 20 FOR I = 1 TO 10
161
+ 30 PRINT "COUNT: "; I
162
+ 40 NEXT I
163
+ 50 END'''
164
+
165
+ # Validate Applesoft BASIC syntax
166
+ errors = diskii.validate_basic_syntax(program_text, "applesoft")
167
+ if not errors:
168
+ print("✅ Program syntax is valid!")
169
+ else:
170
+ for error in errors:
171
+ print(f"Line {error.line}: {error.message}")
172
+
173
+ # Advanced syntax validation with custom validator
174
+ validator = diskii.BASICSyntaxValidator("applesoft")
175
+ errors = validator.validate_program(program_text)
176
+
177
+ # Validate Integer BASIC programs
178
+ integer_program = '''10 HOME
179
+ 20 FOR I = 1 TO 10
180
+ 30 PRINT "COUNT: "; I
181
+ 40 NEXT I
182
+ 50 END'''
183
+
184
+ # Also test Integer BASIC tokenization functions
185
+ tokenized_integer = diskii.tokenize_integer_basic(integer_program)
186
+ detokenized_integer = diskii.detokenize_integer_basic(tokenized_integer)
187
+
188
+ errors = diskii.validate_basic_syntax(integer_program, "integer")
189
+ ```
190
+
191
+ ## Supported Formats
192
+
193
+ | Extension | Description | Sector Ordering | Supported Filesystems |
194
+ |-----------|-------------|----------------|----------------------|
195
+ | `.dsk` | DOS order disk images (140KB) | DOS order | DOS 3.3, ProDOS |
196
+ | `.do` | DOS order disk images | DOS order | DOS 3.3, ProDOS |
197
+ | `.po` | ProDOS order disk images | ProDOS order | DOS 3.3, ProDOS |
198
+ | `.hdv` | ProDOS hard disk volumes (up to 32MB) | ProDOS order | ProDOS |
199
+ | `.d13` | DOS 3.2 13-sector images | DOS 3.2 order | DOS 3.2, ProDOS* |
200
+
201
+ *ProDOS on 13-sector images is theoretically possible but extremely rare in practice.
202
+
203
+ ## Error Handling
204
+
205
+ diskii provides comprehensive error handling:
206
+
207
+ ```python
208
+ try:
209
+ with diskii.open_disk_image("questionable.dsk") as image:
210
+ files = image.get_file_list()
211
+ except diskii.UnrecognizedFormatError:
212
+ print("Not a valid disk image")
213
+ except diskii.CorruptedImageError:
214
+ print("Image appears to be corrupted")
215
+ except diskii.AccessError:
216
+ print("Cannot access the image file")
217
+ ```
218
+
219
+ ## Examples
220
+
221
+ The `examples/` directory contains practical usage examples:
222
+
223
+ - **`directory_tree.py`**: Display disk contents in tree format
224
+ - **`file_info.py`**: Show detailed file metadata and type information
225
+ - **`create_files.py`**: Demonstrate creating files on disk images
226
+ - **`cross_format_copy.py`**: Copy files between ProDOS and DOS formats
227
+ - **`basic_tokenization.py`**: BASIC program tokenization and detokenization examples
228
+
229
+ ## Requirements
230
+
231
+ - Python 3.13+
232
+ - No external dependencies for core functionality
233
+
234
+ ## Development
235
+
236
+ ```bash
237
+ # Install with development dependencies
238
+ poetry install --with dev,docs
239
+
240
+ # Run tests
241
+ poetry run pytest
242
+
243
+ # Run with coverage
244
+ poetry run pytest --cov=src/diskii
245
+
246
+ # Format code
247
+ poetry run ruff format src/ tests/
248
+
249
+ # Type checking
250
+ poetry run mypy src/
251
+
252
+ # Build documentation
253
+ cd docs && make html
254
+ ```
255
+
256
+ ## Planned Features
257
+
258
+ - **Advanced copy operations**: Batch file operations with progress reporting
259
+ - **CLI interface**: Command-line tools for disk manipulation
260
+
261
+ ## Not Planned (Pull Requests Welcome)
262
+
263
+ - WOZ image format support
264
+ - 2MG image format support
265
+ - NIB image format support
266
+ - Pascal or CP/M filesystem support
267
+
268
+ ## References
269
+
270
+ - [ProDOS Technical Reference](https://prodos8.com/docs/techref/file-organization/)
271
+ - [ProDOS Format Notes](https://ciderpress2.com/formatdoc/ProDOS-notes.html)
272
+ - [DOS 3.3 Format Notes](https://ciderpress2.com/formatdoc/DOS-notes.html)
273
+ - [Disk Image Format Reference](https://ciderpress2.com/formatdoc/Unadorned-notes.html)
274
+ - [Applesoft BASIC Tokenized File Format](http://justsolve.archiveteam.org/wiki/Applesoft_BASIC_tokenized_file)
275
+ - [Applesoft BASIC Programming Reference Manual](https://mirrors.apple2.org.za/ftp.apple.asimov.net/documentation/programming/basic/Applesoft%20BASIC%20Programming%20Reference%20Manual%20-%20Apple%20Computer.pdf)
276
+ - [BASIC Keywords and Tokens Reference](http://mirrors.apple2.org.za/apple.cabi.net/Languages.Programming/BASIC.keywords.tokens.txt)
277
+ - [Integer BASIC ROM Disassembly](https://6502disassembly.com/a2-rom/IntegerBASIC.html)
278
+ - [Applesoft BASIC ROM Disassembly](https://6502disassembly.com/a2-rom/Applesoft.html)
279
+
280
+ ## License
281
+
282
+ ISC License - see [LICENSE](LICENSE) file for details.
283
+
284
+ ## Contributing
285
+
286
+ Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
diskii-0.2.0/README.md ADDED
@@ -0,0 +1,261 @@
1
+ # diskii - Apple II Disk Image Tool & Library
2
+
3
+ **diskii** is both a command-line utility and Python library for reading, writing, and manipulating Apple II disk images. It supports both DOS 3.3 and ProDOS filesystems across various image formats.
4
+
5
+ ## Features
6
+
7
+ ### ✅ **Disk Image Reading**
8
+ - **Complete DOS 3.3 support**: Read catalogs, extract files, handle all file types (T/I/A/B/S/R)
9
+ - **Full ProDOS support**: Volume directories, subdirectories, all storage types (seedling/sapling/tree)
10
+ - **DOS 3.2 support**: Read 13-sector disk images (.d13 format)
11
+ - **Multiple image formats**: .dsk, .do, .po, .hdv, .d13
12
+ - **Automatic format detection**: Smart detection based on file extension and content analysis
13
+
14
+ ### ✅ **File Operations**
15
+ - **File extraction**: Read any file from disk images to host filesystem
16
+ - **File writing**: Create new files on disk images with proper metadata
17
+ - **File type preservation**: Maintain Apple II file types and auxiliary information
18
+ - **Cross-format operations**: Copy files between DOS 3.3 and ProDOS images
19
+
20
+ ### ✅ **Disk Image Creation**
21
+ - **Blank disk creation**: Create empty DOS 3.3, DOS 3.2, and ProDOS images
22
+ - **Multiple sizes supported**: Standard 140K disks up to 32MB ProDOS volumes
23
+ - **Proper filesystem initialization**: Correct VTOC, catalogs, and volume bitmaps
24
+
25
+ ### ✅ **Advanced Features**
26
+ - **Hierarchical directory support**: Full ProDOS subdirectory navigation
27
+ - **Sparse file handling**: Efficient handling of ProDOS sparse files
28
+ - **Free space tracking**: Volume bitmap and VTOC management
29
+ - **BASIC (de)tokenization**: Convert between tokenized and text BASIC programs
30
+ - **BASIC syntax validation**: ROM-compliant syntax checking for Apple II BASIC programs
31
+ - **Robust error handling**: Graceful handling of corrupted or invalid images
32
+ - **Type-safe**: Full type annotations throughout
33
+ - **Comprehensive testing**: Extensive test suite with real disk images
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install diskii
39
+ ```
40
+
41
+ Or with Poetry:
42
+
43
+ ```bash
44
+ poetry add diskii
45
+ ```
46
+
47
+ ## Command Line Usage
48
+
49
+ diskii provides a comprehensive command-line interface for disk image manipulation:
50
+
51
+ ```bash
52
+ # Show disk information
53
+ diskii info mydisk.dsk
54
+
55
+ # Extract all files from a disk
56
+ diskii extract mydisk.po
57
+
58
+ # Extract specific files
59
+ diskii extract mydisk.dsk HELLO.BAS
60
+
61
+ # Add files to a disk
62
+ diskii add mydisk.po myfile.txt
63
+
64
+ # Create blank disk images
65
+ diskii create blank.po --name MYDISK
66
+
67
+ # Convert between sector orderings
68
+ diskii convert mydisk.dsk output.po
69
+
70
+ # BASIC program utilities
71
+ diskii basic detokenize HELLO.BAS
72
+ diskii basic tokenize myprogram.txt --variant applesoft
73
+ diskii basic validate myprogram.txt
74
+ ```
75
+
76
+ For detailed help on any command:
77
+ ```bash
78
+ diskii --help
79
+ diskii <command> --help
80
+ ```
81
+
82
+ ## Python Library Usage
83
+
84
+ ```python
85
+ import diskii
86
+
87
+ # Open any disk image - format detected automatically
88
+ with diskii.open_disk_image("mydisk.dsk") as image:
89
+ # Get volume information
90
+ print(f"Volume: {image.get_volume_name()}")
91
+ print(f"Format: {image.format}")
92
+
93
+ # List all files
94
+ files = image.get_file_list()
95
+ for file_entry in files:
96
+ print(f"{file_entry.filename} ({file_entry.size} bytes)")
97
+
98
+ # Extract file
99
+ data = file_entry.read_data()
100
+ with open(file_entry.filename, 'wb') as f:
101
+ f.write(data)
102
+
103
+ # Create a new blank disk
104
+ diskii.disk_creator.create_blank_prodos_image("new_disk.po", "MY.DISK")
105
+
106
+ # Add files to existing disk (requires read_only=False)
107
+ with diskii.open_disk_image("mydisk.po", read_only=False) as image:
108
+ image.create_file("HELLO.TXT", 0x04, b"Hello from diskii!")
109
+
110
+ # BASIC program tokenization
111
+ import diskii
112
+
113
+ # Tokenize Applesoft BASIC program
114
+ program_text = '''10 HOME
115
+ 20 PRINT "HELLO WORLD!"
116
+ 30 END'''
117
+
118
+ tokenized = diskii.tokenize_applesoft(program_text)
119
+ detokenized = diskii.detokenize_applesoft(tokenized)
120
+
121
+ # Work with BASIC files on disk images
122
+ with diskii.open_disk_image("mydisk.po", read_only=False) as image:
123
+ # Save as tokenized BASIC program
124
+ image.create_file("HELLO.BAS", 0xFC, tokenized)
125
+
126
+ # Read BASIC file and detokenize automatically
127
+ files = image.get_file_list()
128
+ for file_entry in files:
129
+ if file_entry.is_basic_file():
130
+ plain_text = file_entry.read_as_text() # Auto-detokenizes
131
+ raw_tokens = file_entry.read_as_tokens() # Raw tokenized data
132
+
133
+ # BASIC syntax validation with ROM compliance
134
+ program_text = '''10 HOME
135
+ 20 FOR I = 1 TO 10
136
+ 30 PRINT "COUNT: "; I
137
+ 40 NEXT I
138
+ 50 END'''
139
+
140
+ # Validate Applesoft BASIC syntax
141
+ errors = diskii.validate_basic_syntax(program_text, "applesoft")
142
+ if not errors:
143
+ print("✅ Program syntax is valid!")
144
+ else:
145
+ for error in errors:
146
+ print(f"Line {error.line}: {error.message}")
147
+
148
+ # Advanced syntax validation with custom validator
149
+ validator = diskii.BASICSyntaxValidator("applesoft")
150
+ errors = validator.validate_program(program_text)
151
+
152
+ # Validate Integer BASIC programs
153
+ integer_program = '''10 HOME
154
+ 20 FOR I = 1 TO 10
155
+ 30 PRINT "COUNT: "; I
156
+ 40 NEXT I
157
+ 50 END'''
158
+
159
+ # Also test Integer BASIC tokenization functions
160
+ tokenized_integer = diskii.tokenize_integer_basic(integer_program)
161
+ detokenized_integer = diskii.detokenize_integer_basic(tokenized_integer)
162
+
163
+ errors = diskii.validate_basic_syntax(integer_program, "integer")
164
+ ```
165
+
166
+ ## Supported Formats
167
+
168
+ | Extension | Description | Sector Ordering | Supported Filesystems |
169
+ |-----------|-------------|----------------|----------------------|
170
+ | `.dsk` | DOS order disk images (140KB) | DOS order | DOS 3.3, ProDOS |
171
+ | `.do` | DOS order disk images | DOS order | DOS 3.3, ProDOS |
172
+ | `.po` | ProDOS order disk images | ProDOS order | DOS 3.3, ProDOS |
173
+ | `.hdv` | ProDOS hard disk volumes (up to 32MB) | ProDOS order | ProDOS |
174
+ | `.d13` | DOS 3.2 13-sector images | DOS 3.2 order | DOS 3.2, ProDOS* |
175
+
176
+ *ProDOS on 13-sector images is theoretically possible but extremely rare in practice.
177
+
178
+ ## Error Handling
179
+
180
+ diskii provides comprehensive error handling:
181
+
182
+ ```python
183
+ try:
184
+ with diskii.open_disk_image("questionable.dsk") as image:
185
+ files = image.get_file_list()
186
+ except diskii.UnrecognizedFormatError:
187
+ print("Not a valid disk image")
188
+ except diskii.CorruptedImageError:
189
+ print("Image appears to be corrupted")
190
+ except diskii.AccessError:
191
+ print("Cannot access the image file")
192
+ ```
193
+
194
+ ## Examples
195
+
196
+ The `examples/` directory contains practical usage examples:
197
+
198
+ - **`directory_tree.py`**: Display disk contents in tree format
199
+ - **`file_info.py`**: Show detailed file metadata and type information
200
+ - **`create_files.py`**: Demonstrate creating files on disk images
201
+ - **`cross_format_copy.py`**: Copy files between ProDOS and DOS formats
202
+ - **`basic_tokenization.py`**: BASIC program tokenization and detokenization examples
203
+
204
+ ## Requirements
205
+
206
+ - Python 3.13+
207
+ - No external dependencies for core functionality
208
+
209
+ ## Development
210
+
211
+ ```bash
212
+ # Install with development dependencies
213
+ poetry install --with dev,docs
214
+
215
+ # Run tests
216
+ poetry run pytest
217
+
218
+ # Run with coverage
219
+ poetry run pytest --cov=src/diskii
220
+
221
+ # Format code
222
+ poetry run ruff format src/ tests/
223
+
224
+ # Type checking
225
+ poetry run mypy src/
226
+
227
+ # Build documentation
228
+ cd docs && make html
229
+ ```
230
+
231
+ ## Planned Features
232
+
233
+ - **Advanced copy operations**: Batch file operations with progress reporting
234
+ - **CLI interface**: Command-line tools for disk manipulation
235
+
236
+ ## Not Planned (Pull Requests Welcome)
237
+
238
+ - WOZ image format support
239
+ - 2MG image format support
240
+ - NIB image format support
241
+ - Pascal or CP/M filesystem support
242
+
243
+ ## References
244
+
245
+ - [ProDOS Technical Reference](https://prodos8.com/docs/techref/file-organization/)
246
+ - [ProDOS Format Notes](https://ciderpress2.com/formatdoc/ProDOS-notes.html)
247
+ - [DOS 3.3 Format Notes](https://ciderpress2.com/formatdoc/DOS-notes.html)
248
+ - [Disk Image Format Reference](https://ciderpress2.com/formatdoc/Unadorned-notes.html)
249
+ - [Applesoft BASIC Tokenized File Format](http://justsolve.archiveteam.org/wiki/Applesoft_BASIC_tokenized_file)
250
+ - [Applesoft BASIC Programming Reference Manual](https://mirrors.apple2.org.za/ftp.apple.asimov.net/documentation/programming/basic/Applesoft%20BASIC%20Programming%20Reference%20Manual%20-%20Apple%20Computer.pdf)
251
+ - [BASIC Keywords and Tokens Reference](http://mirrors.apple2.org.za/apple.cabi.net/Languages.Programming/BASIC.keywords.tokens.txt)
252
+ - [Integer BASIC ROM Disassembly](https://6502disassembly.com/a2-rom/IntegerBASIC.html)
253
+ - [Applesoft BASIC ROM Disassembly](https://6502disassembly.com/a2-rom/Applesoft.html)
254
+
255
+ ## License
256
+
257
+ ISC License - see [LICENSE](LICENSE) file for details.
258
+
259
+ ## Contributing
260
+
261
+ Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
@@ -0,0 +1,100 @@
1
+ [project]
2
+ name = "diskii"
3
+ version = "0.2.0"
4
+ description = "diskii - Apple II Disk Image Tool & Library"
5
+ authors = [
6
+ {name = "Seth Kushniryk", email = "seth@kushniryk.com"}
7
+ ]
8
+ license = {text = "ISC"}
9
+ readme = "README.md"
10
+ requires-python = ">=3.13"
11
+ keywords = ["apple2", "apple-ii", "disk-image", "prodos", "dos33", "retro-computing"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Intended Audience :: Developers",
15
+ "Intended Audience :: End Users/Desktop",
16
+ "License :: OSI Approved :: ISC License (ISCL)",
17
+ "Operating System :: OS Independent",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Topic :: System :: Archiving",
21
+ "Topic :: Software Development :: Libraries :: Python Modules",
22
+ "Topic :: System :: Filesystems",
23
+ ]
24
+ dependencies = [
25
+ ]
26
+
27
+ [project.scripts]
28
+ diskii = "diskii.cli:main"
29
+
30
+ [project.urls]
31
+ "Homepage" = "https://git.sr.ht/~sethkush/diskii"
32
+ "Bug Reports" = "https://todo.sr.ht/~sethkush/diskii"
33
+ "Source" = "https://git.sr.ht/~sethkush/diskii"
34
+ "Documentation" = "https://git.sr.ht/~sethkush/diskii/tree/master/item/docs"
35
+
36
+ [tool.poetry]
37
+ packages = [{include = "diskii", from = "src"}]
38
+
39
+ [tool.poetry.dependencies]
40
+ python = ">=3.13"
41
+
42
+ [tool.poetry.group.dev.dependencies]
43
+ pytest = ">=7.0.0"
44
+ pytest-cov = ">=4.0.0"
45
+ ruff = ">=0.1.0"
46
+ mypy = ">=1.0.0"
47
+
48
+ [tool.poetry.group.docs.dependencies]
49
+ sphinx = ">=7.0.0"
50
+ sphinx-autodoc-typehints = ">=1.24.0"
51
+ sphinx-rtd-theme = ">=1.3.0"
52
+ myst-parser = ">=2.0.0"
53
+
54
+ [build-system]
55
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
56
+ build-backend = "poetry.core.masonry.api"
57
+
58
+ [tool.pytest.ini_options]
59
+ testpaths = ["tests"]
60
+ python_files = ["test_*.py", "*_test.py"]
61
+ python_classes = ["Test*"]
62
+ python_functions = ["test_*"]
63
+ addopts = [
64
+ "--strict-markers",
65
+ "--strict-config",
66
+ "--cov=src/diskii",
67
+ "--cov-report=term-missing",
68
+ "--cov-report=html:htmlcov",
69
+ "--cov-fail-under=80"
70
+ ]
71
+
72
+ [tool.ruff]
73
+ line-length = 88
74
+ target-version = "py313"
75
+
76
+ [tool.ruff.lint]
77
+ select = [
78
+ "E", # pycodestyle errors
79
+ "W", # pycodestyle warnings
80
+ "F", # pyflakes
81
+ "I", # isort
82
+ "B", # flake8-bugbear
83
+ "C4", # flake8-comprehensions
84
+ "UP", # pyupgrade
85
+ ]
86
+
87
+ [tool.mypy]
88
+ python_version = "3.13"
89
+ warn_return_any = true
90
+ warn_unused_configs = true
91
+ disallow_untyped_defs = true
92
+ disallow_incomplete_defs = true
93
+ check_untyped_defs = true
94
+ disallow_untyped_decorators = true
95
+ no_implicit_optional = true
96
+ warn_redundant_casts = true
97
+ warn_unused_ignores = true
98
+ warn_no_return = true
99
+ warn_unreachable = true
100
+ strict_equality = true