attachments 0.3.0__tar.gz → 0.5.4__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 (92) hide show
  1. attachments-0.5.4/PKG-INFO +475 -0
  2. attachments-0.5.4/README.md +378 -0
  3. attachments-0.5.4/pyproject.toml +259 -0
  4. attachments-0.5.4/src/attachments/__init__.py +70 -0
  5. attachments-0.5.4/src/attachments/adapt.py +254 -0
  6. attachments-0.5.4/src/attachments/core.py +991 -0
  7. attachments-0.5.4/src/attachments/data/__init__.py +33 -0
  8. attachments-0.5.4/src/attachments/highest_level_api.py +399 -0
  9. attachments-0.5.4/src/attachments/load.py +13 -0
  10. attachments-0.5.4/src/attachments/loaders/__init__.py +17 -0
  11. attachments-0.5.4/src/attachments/loaders/data/__init__.py +7 -0
  12. attachments-0.5.4/src/attachments/loaders/data/csv.py +15 -0
  13. attachments-0.5.4/src/attachments/loaders/documents/__init__.py +14 -0
  14. attachments-0.5.4/src/attachments/loaders/documents/office.py +37 -0
  15. attachments-0.5.4/src/attachments/loaders/documents/pdf.py +51 -0
  16. attachments-0.5.4/src/attachments/loaders/documents/text.py +39 -0
  17. attachments-0.5.4/src/attachments/loaders/media/__init__.py +9 -0
  18. attachments-0.5.4/src/attachments/loaders/media/archives.py +48 -0
  19. attachments-0.5.4/src/attachments/loaders/media/images.py +34 -0
  20. attachments-0.5.4/src/attachments/loaders/repositories/__init__.py +9 -0
  21. attachments-0.5.4/src/attachments/loaders/repositories/directories.py +205 -0
  22. attachments-0.5.4/src/attachments/loaders/repositories/git.py +145 -0
  23. attachments-0.5.4/src/attachments/loaders/repositories/utils.py +520 -0
  24. attachments-0.5.4/src/attachments/loaders/web/__init__.py +8 -0
  25. attachments-0.5.4/src/attachments/loaders/web/urls.py +101 -0
  26. attachments-0.5.4/src/attachments/matchers.py +73 -0
  27. attachments-0.5.4/src/attachments/modify.py +361 -0
  28. attachments-0.5.4/src/attachments/pipelines/__init__.py +205 -0
  29. attachments-0.5.4/src/attachments/pipelines/csv_processor.py +100 -0
  30. attachments-0.5.4/src/attachments/pipelines/docx_processor.py +99 -0
  31. attachments-0.5.4/src/attachments/pipelines/example_processors.py +172 -0
  32. attachments-0.5.4/src/attachments/pipelines/excel_processor.py +103 -0
  33. attachments-0.5.4/src/attachments/pipelines/image_processor.py +48 -0
  34. attachments-0.5.4/src/attachments/pipelines/pdf_processor.py +127 -0
  35. attachments-0.5.4/src/attachments/pipelines/pptx_processor.py +99 -0
  36. attachments-0.5.4/src/attachments/pipelines/webpage_processor.py +136 -0
  37. attachments-0.5.4/src/attachments/present.py +1 -0
  38. attachments-0.5.4/src/attachments/presenters/__init__.py +15 -0
  39. attachments-0.5.4/src/attachments/presenters/data/__init__.py +11 -0
  40. attachments-0.5.4/src/attachments/presenters/data/repositories.py +293 -0
  41. attachments-0.5.4/src/attachments/presenters/data/summaries.py +77 -0
  42. attachments-0.5.4/src/attachments/presenters/metadata/__init__.py +7 -0
  43. attachments-0.5.4/src/attachments/presenters/metadata/info.py +77 -0
  44. attachments-0.5.4/src/attachments/presenters/text/__init__.py +18 -0
  45. attachments-0.5.4/src/attachments/presenters/text/markdown.py +301 -0
  46. attachments-0.5.4/src/attachments/presenters/text/ocr.py +104 -0
  47. attachments-0.5.4/src/attachments/presenters/text/plain.py +210 -0
  48. attachments-0.5.4/src/attachments/presenters/text/structured.py +183 -0
  49. attachments-0.5.4/src/attachments/presenters/visual/__init__.py +7 -0
  50. attachments-0.5.4/src/attachments/presenters/visual/images.py +887 -0
  51. attachments-0.5.4/src/attachments/py.typed +4 -0
  52. attachments-0.5.4/src/attachments/refine.py +555 -0
  53. attachments-0.5.4/src/attachments/split.py +395 -0
  54. attachments-0.5.4/src/attachments.egg-info/PKG-INFO +475 -0
  55. attachments-0.5.4/src/attachments.egg-info/SOURCES.txt +61 -0
  56. attachments-0.5.4/src/attachments.egg-info/not-zip-safe +1 -0
  57. attachments-0.5.4/src/attachments.egg-info/requires.txt +77 -0
  58. attachments-0.5.4/tests/test_api_methods.py +145 -0
  59. attachments-0.5.4/tests/test_smoke.py +251 -0
  60. attachments-0.3.0/PKG-INFO +0 -172
  61. attachments-0.3.0/README.md +0 -132
  62. attachments-0.3.0/pyproject.toml +0 -68
  63. attachments-0.3.0/src/attachments/__init__.py +0 -39
  64. attachments-0.3.0/src/attachments/audio_processing.py +0 -217
  65. attachments-0.3.0/src/attachments/config.py +0 -35
  66. attachments-0.3.0/src/attachments/core.py +0 -848
  67. attachments-0.3.0/src/attachments/detectors.py +0 -144
  68. attachments-0.3.0/src/attachments/exceptions.py +0 -69
  69. attachments-0.3.0/src/attachments/image_processing.py +0 -272
  70. attachments-0.3.0/src/attachments/office_contact_sheet.py +0 -192
  71. attachments-0.3.0/src/attachments/parsers.py +0 -414
  72. attachments-0.3.0/src/attachments/renderers.py +0 -140
  73. attachments-0.3.0/src/attachments/utils.py +0 -389
  74. attachments-0.3.0/src/attachments.egg-info/PKG-INFO +0 -172
  75. attachments-0.3.0/src/attachments.egg-info/SOURCES.txt +0 -31
  76. attachments-0.3.0/src/attachments.egg-info/requires.txt +0 -26
  77. attachments-0.3.0/tests/test_audio_processing.py +0 -342
  78. attachments-0.3.0/tests/test_base.py +0 -290
  79. attachments-0.3.0/tests/test_core_functionality.py +0 -336
  80. attachments-0.3.0/tests/test_document_parsing.py +0 -87
  81. attachments-0.3.0/tests/test_html_parsing.py +0 -90
  82. attachments-0.3.0/tests/test_image_processing.py +0 -193
  83. attachments-0.3.0/tests/test_indexing_slicing.py +0 -79
  84. attachments-0.3.0/tests/test_markdown_rendering.py +0 -212
  85. attachments-0.3.0/tests/test_office_contact_sheet.py +0 -102
  86. attachments-0.3.0/tests/test_pdf_parsing.py +0 -170
  87. attachments-0.3.0/tests/test_pptx_parsing.py +0 -119
  88. attachments-0.3.0/tests/test_simple.py +0 -8
  89. {attachments-0.3.0 → attachments-0.5.4}/LICENSE +0 -0
  90. {attachments-0.3.0 → attachments-0.5.4}/setup.cfg +0 -0
  91. {attachments-0.3.0 → attachments-0.5.4}/src/attachments.egg-info/dependency_links.txt +0 -0
  92. {attachments-0.3.0 → attachments-0.5.4}/src/attachments.egg-info/top_level.txt +0 -0
@@ -0,0 +1,475 @@
1
+ Metadata-Version: 2.4
2
+ Name: attachments
3
+ Version: 0.5.4
4
+ Summary: The Python funnel for LLM context - turn any file into model-ready text + images, in one line.
5
+ Author-email: Maxime Rivest <mrive052@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://maximerivest.github.io/attachments/
8
+ Project-URL: Documentation, https://maximerivest.github.io/attachments/
9
+ Project-URL: Repository, https://github.com/maximrivest/attachments
10
+ Project-URL: Bug Tracker, https://github.com/maximrivest/attachments/issues
11
+ Project-URL: Changelog, https://maximerivest.github.io/attachments/changelog.html
12
+ Keywords: llm,ai,pdf,document,multimodal,openai,claude,context,attachments
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: Text Processing
24
+ Classifier: Topic :: Multimedia
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: requests>=2.25.0
29
+ Requires-Dist: beautifulsoup4>=4.9.0
30
+ Requires-Dist: playwright>=1.52.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
33
+ Requires-Dist: pytest-randomly>=3.15.0; extra == "dev"
34
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
35
+ Requires-Dist: black>=24.0.0; extra == "dev"
36
+ Requires-Dist: flake8>=7.0.0; extra == "dev"
37
+ Requires-Dist: mypy>=1.8.0; extra == "dev"
38
+ Requires-Dist: pre-commit>=3.6.0; extra == "dev"
39
+ Provides-Extra: docs
40
+ Requires-Dist: mystmd>=1.2.0; extra == "docs"
41
+ Requires-Dist: jupyter>=1.0.0; extra == "docs"
42
+ Requires-Dist: jupytext>=1.16.0; extra == "docs"
43
+ Requires-Dist: sphinx>=7.0.0; extra == "docs"
44
+ Requires-Dist: sphinx-autodoc2>=0.5.0; extra == "docs"
45
+ Provides-Extra: common
46
+ Requires-Dist: pandas>=2.0.0; extra == "common"
47
+ Requires-Dist: Pillow>=10.0.0; extra == "common"
48
+ Requires-Dist: pdfplumber>=0.10.0; extra == "common"
49
+ Requires-Dist: python-pptx>=0.6.0; extra == "common"
50
+ Requires-Dist: python-docx>=1.1.0; extra == "common"
51
+ Requires-Dist: openpyxl>=3.1.0; extra == "common"
52
+ Requires-Dist: pypdfium2>=4.0.0; extra == "common"
53
+ Provides-Extra: pdf
54
+ Requires-Dist: pdfplumber>=0.7.0; extra == "pdf"
55
+ Requires-Dist: pypdf>=5.0.0; extra == "pdf"
56
+ Requires-Dist: pypdfium2>=4.26.0; extra == "pdf"
57
+ Provides-Extra: pdf-agpl
58
+ Requires-Dist: PyMuPDF>=1.24.0; extra == "pdf-agpl"
59
+ Provides-Extra: extended
60
+ Requires-Dist: python-magic>=0.4.27; extra == "extended"
61
+ Requires-Dist: mammoth>=1.6.0; extra == "extended"
62
+ Requires-Dist: odfpy>=1.4.1; extra == "extended"
63
+ Requires-Dist: pillow-heif>=0.22.0; extra == "extended"
64
+ Requires-Dist: pydub>=0.25.1; extra == "extended"
65
+ Requires-Dist: SpeechRecognition>=3.10.0; extra == "extended"
66
+ Requires-Dist: markitdown[all]>=0.1.1; extra == "extended"
67
+ Requires-Dist: pytesseract>=0.3.10; extra == "extended"
68
+ Provides-Extra: browser
69
+ Requires-Dist: playwright>=1.43.0; extra == "browser"
70
+ Requires-Dist: selenium>=4.15.0; extra == "browser"
71
+ Provides-Extra: all
72
+ Requires-Dist: pandas>=1.3.0; extra == "all"
73
+ Requires-Dist: Pillow>=8.0.0; extra == "all"
74
+ Requires-Dist: pdfplumber>=0.7.0; extra == "all"
75
+ Requires-Dist: python-pptx>=0.6.21; extra == "all"
76
+ Requires-Dist: python-docx>=0.8.11; extra == "all"
77
+ Requires-Dist: openpyxl>=3.0.9; extra == "all"
78
+ Requires-Dist: python-magic>=0.4.27; extra == "all"
79
+ Requires-Dist: mammoth>=1.6.0; extra == "all"
80
+ Requires-Dist: odfpy>=1.4.1; extra == "all"
81
+ Requires-Dist: pillow-heif>=0.22.0; extra == "all"
82
+ Requires-Dist: pydub>=0.25.1; extra == "all"
83
+ Requires-Dist: SpeechRecognition>=3.10.0; extra == "all"
84
+ Requires-Dist: markitdown[all]>=0.1.1; extra == "all"
85
+ Requires-Dist: pytesseract>=0.3.10; extra == "all"
86
+ Requires-Dist: pypdf>=5.0.0; extra == "all"
87
+ Requires-Dist: pypdfium2>=4.26.0; extra == "all"
88
+ Requires-Dist: playwright>=1.43.0; extra == "all"
89
+ Requires-Dist: selenium>=4.15.0; extra == "all"
90
+ Provides-Extra: test
91
+ Requires-Dist: pytest>=8.0.0; extra == "test"
92
+ Requires-Dist: pytest-randomly>=3.15.0; extra == "test"
93
+ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
94
+ Requires-Dist: tox>=4.0.0; extra == "test"
95
+ Requires-Dist: coverage[toml]>=7.4.0; extra == "test"
96
+ Dynamic: license-file
97
+
98
+ # Attachments – the Python funnel for LLM context
99
+
100
+ ### Turn *any* file into model-ready text + images, in one line
101
+
102
+ Most users will not have to learn anything more than: `Attachments("path/to/file.pdf")`
103
+
104
+ > **TL;DR**
105
+ > ```bash
106
+ > pip install attachments
107
+ > ```
108
+ > ```python
109
+ > from attachments import Attachments
110
+ > ctx = Attachments("https://github.com/MaximeRivest/attachments/raw/main/src/attachments/data/sample.pdf",
111
+ > "https://github.com/MaximeRivest/attachments/raw/refs/heads/main/src/attachments/data/sample_multipage.pptx")
112
+ > llm_ready_text = str(ctx) # all extracted text, already "prompt-engineered"
113
+ > llm_ready_images = ctx.images # list[str] – base64 PNGs
114
+ > ```
115
+
116
+
117
+ Attachments aims to be **the** community funnel from *file → text + base64 images* for LLMs.
118
+ Stop re-writing that plumbing in every project – contribute your *loader / transform / renderer* plugin instead!
119
+
120
+ ## Quick-start ⚡
121
+
122
+ ```bash
123
+ pip install attachments
124
+ ```
125
+
126
+ ### Try it now with sample files
127
+
128
+ ```python
129
+ from attachments import Attachments
130
+ from attachments.data import get_sample_path
131
+
132
+ # Option 1: Use included sample files (works offline)
133
+ pdf_path = get_sample_path("sample.pdf")
134
+ txt_path = get_sample_path("sample.txt")
135
+ ctx = Attachments(pdf_path, txt_path)
136
+
137
+ print(str(ctx)) # Pretty text view
138
+ print(len(ctx.images)) # Number of extracted images
139
+
140
+ # Try different file types
141
+ docx_path = get_sample_path("test_document.docx")
142
+ csv_path = get_sample_path("test.csv")
143
+ json_path = get_sample_path("sample.json")
144
+
145
+ ctx = Attachments(docx_path, csv_path, json_path)
146
+ print(f"Processed {len(ctx)} files: Word doc, CSV data, and JSON")
147
+
148
+ # Option 2: Use URLs (same API, works with any URL)
149
+ ctx = Attachments(
150
+ "https://github.com/MaximeRivest/attachments/raw/main/src/attachments/data/sample.pdf",
151
+ "https://github.com/MaximeRivest/attachments/raw/main/src/attachments/data/sample_multipage.pptx"
152
+ )
153
+
154
+ print(str(ctx)) # Pretty text view
155
+ print(len(ctx.images)) # Number of extracted images
156
+ ```
157
+
158
+ ### Advanced usage with DSL
159
+
160
+ ```python
161
+ from attachments import Attachments
162
+
163
+ a = Attachments(
164
+ "https://github.com/MaximeRivest/attachments/raw/main/src/attachments/data/" \
165
+ "sample_multipage.pptx[3-5]"
166
+ )
167
+ print(a) # pretty text view
168
+ len(a.images) # 👉 base64 PNG list
169
+ ```
170
+
171
+ ### Send to OpenAI
172
+
173
+ ```bash
174
+ pip install openai
175
+ ```
176
+
177
+ ```python
178
+ from openai import OpenAI
179
+ from attachments import Attachments
180
+
181
+ pdf = Attachments("https://github.com/MaximeRivest/attachments/raw/main/src/attachments/data/sample_multipage.pptx[3-5]")
182
+
183
+ client = OpenAI()
184
+ resp = client.chat.completions.create(
185
+ model="gpt-4.1-nano",
186
+ messages=pdf.openai_chat("Analyse the following document:")
187
+ )
188
+ print(resp.choices[0].message.content)
189
+ ```
190
+
191
+ or with the response API
192
+
193
+ ```python
194
+ from openai import OpenAI
195
+ from attachments import Attachments
196
+
197
+ pdf = Attachments("https://github.com/MaximeRivest/attachments/raw/main/src/attachments/data/sample_multipage.pptx[3-5]")
198
+
199
+ client = OpenAI()
200
+ resp = client.responses.create(
201
+ input=pdf.openai_responses("Analyse the following document:"),
202
+ model="gpt-4.1-nano"
203
+ )
204
+ print(resp.output[0].content[0].text)
205
+ ```
206
+
207
+ ### Send to Anthropic / Claude
208
+
209
+ ```bash
210
+ pip install anthropic
211
+ ```
212
+
213
+ ```python
214
+ import anthropic
215
+ from attachments import Attachments
216
+
217
+ pptx = Attachments("https://github.com/MaximeRivest/attachments/raw/main/src/attachments/data/sample_multipage.pptx[3-5]")
218
+
219
+ msg = anthropic.Anthropic().messages.create(
220
+ model="claude-3-5-haiku-20241022",
221
+ max_tokens=8_192,
222
+ messages=pptx.claude("Analyse the slides:")
223
+ )
224
+ print(msg.content)
225
+ ```
226
+
227
+ ### DSPy Integration
228
+
229
+ ```bash
230
+ pip install dspy
231
+ ```
232
+
233
+ ```python
234
+ import dspy
235
+ from attachments import Attachments
236
+
237
+ dspy.configure(lm=dspy.LM('openai/gpt-4.1-nano'))
238
+ rag = dspy.ChainOfThought("question, document -> answer")
239
+
240
+ result = rag(
241
+ question="What is the main message of the document?",
242
+ document=Attachments("https://github.com/MaximeRivest/attachments/raw/main/src/attachments/data/sample_multipage.pptx[3-5]").dspy()
243
+ )
244
+ print(result.answer)
245
+ ```
246
+
247
+ ### Optional: CSS Selector Highlighting 🎯
248
+
249
+ For advanced web scraping with visual element highlighting in screenshots:
250
+
251
+ ```bash
252
+ # Install Playwright for CSS selector highlighting
253
+ pip install playwright
254
+ playwright install chromium
255
+
256
+ # Or with uv
257
+ uv add playwright
258
+ uv run playwright install chromium
259
+
260
+ # Or install with browser extras
261
+ pip install attachments[browser]
262
+ playwright install chromium
263
+ ```
264
+
265
+ **What this enables:**
266
+ - 🎯 Visual highlighting of selected elements with animations
267
+ - 📸 High-quality screenshots with JavaScript rendering
268
+ - 🎨 Professional styling with glowing borders and badges
269
+ - 🔍 Perfect for extracting specific page elements
270
+
271
+ ```python
272
+ # CSS selector highlighting examples
273
+ title = Attachments("https://example.com[select:h1]") # Highlights H1 elements
274
+ content = Attachments("https://example.com[select:.content]") # Highlights .content class
275
+ main = Attachments("https://example.com[select:#main]") # Highlights #main ID
276
+
277
+ # Multiple elements with counters and different colors
278
+ multi = Attachments("https://example.com[select:h1, .important][viewport:1920x1080]")
279
+ ```
280
+
281
+ *Note: Without Playwright, CSS selectors still work for text extraction, but no visual highlighting screenshots are generated.*
282
+
283
+ ### Advanced Pipeline Processing
284
+
285
+ For power users, use the full grammar system with composable pipelines:
286
+
287
+ ```python
288
+ from attachments import attach, load, modify, present, refine, adapt
289
+
290
+ # Custom processing pipeline
291
+ result = (attach("document.pdf[pages:1-5]")
292
+ | load.pdf_to_pdfplumber
293
+ | modify.pages
294
+ | present.markdown + present.images
295
+ | refine.add_headers | refine.truncate
296
+ | adapt.claude("Analyze this content"))
297
+
298
+ # Web scraping pipeline
299
+ title = (attach("https://en.wikipedia.org/wiki/Llama[select:title]")
300
+ | load.url_to_bs4
301
+ | modify.select
302
+ | present.text)
303
+
304
+ # Reusable processors
305
+ csv_analyzer = (load.csv_to_pandas
306
+ | modify.limit
307
+ | present.head + present.summary + present.metadata
308
+ | refine.add_headers)
309
+
310
+ # Use as function
311
+ result = csv_analyzer("data.csv[limit:100]")
312
+ analysis = result.claude("What patterns do you see?")
313
+ ```
314
+
315
+
316
+
317
+ ---
318
+
319
+ ## DSL cheatsheet 📝
320
+
321
+ | Piece | Example | Notes |
322
+ | ------------------------- | ------------------------- | --------------------------------------------- |
323
+ | **Select pages / slides** | `report.pdf[1,3-5,-1]` | Supports ranges, negative indices, `N` = last |
324
+ | **Image transforms** | `photo.jpg[rotate:90]` | Any token implemented by a `Transform` plugin |
325
+ | **Data-frame summary** | `table.csv[summary:true]` | Ships with a quick `df.describe()` renderer |
326
+ | **Web content selection** | `url[select:title]` | CSS selectors for web scraping |
327
+ | **Web element highlighting** | `url[select:h1][viewport:1920x1080]` | Visual highlighting in screenshots |
328
+ | **Image processing** | `image.jpg[crop:100,100,400,300][rotate:45]` | Chain multiple transformations |
329
+ | **Content filtering** | `doc.pdf[format:plain][images:false]` | Control text/image extraction |
330
+ | **Repository processing** | `repo[files:false][ignore:standard]` | Smart codebase analysis |
331
+
332
+ ---
333
+
334
+ ## Supported formats (out of the box)
335
+
336
+ * **Docs**: PDF, PowerPoint (`.pptx`), CSV, TXT, Markdown, HTML
337
+ * **Images**: PNG, JPEG, BMP, GIF, WEBP, HEIC/HEIF, …
338
+ * **Web**: URLs with BeautifulSoup parsing and CSS selection
339
+ * **Archives**: ZIP files → image collections with tiling
340
+ * **Repositories**: Git repos with smart ignore patterns
341
+ * **Data**: CSV with pandas, JSON
342
+
343
+ ---
344
+
345
+ ## Advanced Examples 🧩
346
+
347
+ ### **Multimodal Document Processing**
348
+ ```python
349
+ # PDF with image tiling and analysis
350
+ result = Attachments("report.pdf[tile:2x3][resize_images:400]")
351
+ analysis = result.claude("Analyze both text and visual elements")
352
+
353
+ # Multiple file types in one context
354
+ ctx = Attachments("report.pdf", "data.csv", "chart.png")
355
+ comparison = ctx.openai("Compare insights across all documents")
356
+ ```
357
+
358
+ ### **Repository Analysis**
359
+ ```python
360
+ # Codebase structure only
361
+ structure = Attachments("./my-project[mode:structure]")
362
+
363
+ # Full codebase analysis with smart filtering
364
+ codebase = Attachments("./my-project[ignore:standard]")
365
+ review = codebase.claude("Review this code for best practices")
366
+
367
+ # Custom ignore patterns
368
+ filtered = Attachments("./app[ignore:.env,*.log,node_modules]")
369
+ ```
370
+
371
+ ### **Web Scraping with CSS Selectors**
372
+ ```python
373
+ # Extract specific content from web pages
374
+ title = Attachments("https://example.com[select:h1]")
375
+ paragraphs = Attachments("https://example.com[select:p]")
376
+
377
+ # Visual highlighting in screenshots with animations
378
+ highlighted = Attachments("https://example.com[select:h1][viewport:1920x1080]")
379
+ # Creates screenshot with animated highlighting of h1 elements
380
+
381
+ # Multiple element highlighting with counters
382
+ multi_select = Attachments("https://example.com[select:h1, .important][fullpage:true]")
383
+ # Shows "H1 (1/3)", "DIV (2/3)", etc. with different colors for multiple selections
384
+
385
+ # Pipeline approach for complex scraping
386
+ content = (attach("https://en.wikipedia.org/wiki/Llama[select:p]")
387
+ | load.url_to_bs4
388
+ | modify.select
389
+ | present.text
390
+ | refine.truncate)
391
+ ```
392
+
393
+ ### **Image Processing Chains**
394
+ ```python
395
+ # HEIC support with transformations
396
+ processed = Attachments("IMG_2160.HEIC[crop:100,100,400,300][rotate:90]")
397
+
398
+ # Batch image processing with tiling
399
+ collage = Attachments("photos.zip[tile:3x2][resize_images:800]")
400
+ description = collage.claude("Describe this image collage")
401
+ ```
402
+
403
+ ### **Data Analysis Workflows**
404
+ ```python
405
+ # Rich data presentation
406
+ data_summary = Attachments("sales_data.csv[limit:1000][summary:true]")
407
+
408
+ # Pipeline for complex data processing
409
+ result = (attach("data.csv[limit:500]")
410
+ | load.csv_to_pandas
411
+ | modify.limit
412
+ | present.head + present.summary + present.metadata
413
+ | refine.add_headers
414
+ | adapt.claude("What trends do you see?"))
415
+ ```
416
+
417
+ ---
418
+
419
+ ## Extending 🧩
420
+
421
+ ```python
422
+ # my_ocr_renderer.py
423
+ from attachments.plugin_api import register_plugin, requires
424
+ from attachments.core import Renderer
425
+
426
+ @register_plugin("renderer_text", priority=50)
427
+ @requires("pytesseract", "PIL")
428
+ class ImageOCR(Renderer):
429
+ content_type = "text"
430
+
431
+ def match(self, obj):
432
+ from PIL import Image
433
+ return isinstance(obj, Image.Image)
434
+
435
+ def render(self, obj, meta):
436
+ import pytesseract
437
+ return pytesseract.image_to_string(obj)
438
+ ```
439
+
440
+ 1. Put the file somewhere on disk.
441
+ 2. `export ATTACHMENTS_PLUGIN_PATH=/abs/path/to/dir_or_file`
442
+ 3. `import attachments` – your plugin is auto-discovered, no code changes.
443
+
444
+ ---
445
+
446
+ ## API reference (essentials)
447
+
448
+ | Object / method | Description |
449
+ | ----------------------- | --------------------------------------------------------------- |
450
+ | `Attachments(*sources)` | Many `Attachment` objects flattened into one container |
451
+ | `Attachments.text` | All text joined with blank lines |
452
+ | `Attachments.images` | Flat list of base64 PNGs |
453
+ | `.claude(prompt="")` | Claude API format with image support |
454
+ | `.openai_chat(prompt="")` | OpenAI Chat Completions API format |
455
+ | `.openai_responses(prompt="")` | OpenAI Responses API format (different structure) |
456
+ | `.openai(prompt="")` | Alias for openai_chat (backwards compatibility) |
457
+ | `.dspy()` | DSPy BaseType-compatible objects |
458
+
459
+ ### Grammar System (Advanced)
460
+
461
+ | Namespace | Purpose | Examples |
462
+ |-----------|---------|----------|
463
+ | `load.*` | File format → objects | `pdf_to_pdfplumber`, `csv_to_pandas`, `url_to_bs4` |
464
+ | `modify.*` | Transform objects | `pages`, `limit`, `select`, `crop`, `rotate` |
465
+ | `present.*` | Extract content | `text`, `images`, `markdown`, `summary` |
466
+ | `refine.*` | Post-process | `truncate`, `add_headers`, `tile_images` |
467
+ | `adapt.*` | Format for APIs | `claude`, `openai`, `dspy` |
468
+
469
+ **Operators**: `|` (sequential), `+` (additive)
470
+
471
+ ---
472
+
473
+ ### Roadmap
474
+
475
+ Join us – file an issue or open a PR! 🚀