0
# Source Management
1
2
Source management provides comprehensive functionality for creating, configuring, and managing Python source code objects. The Source class abstracts different input formats and provides metadata management, automatic language detection, and flexible source creation patterns.
3
4
## Capabilities
5
6
### Source Creation
7
8
Create Source objects from various input formats including strings, files, URLs, and streams.
9
10
```java { .api }
11
/**
12
* Creates a builder for constructing Source objects from string content
13
* @param language the language identifier (use "python" for Python)
14
* @param characters the source code content
15
* @param name a descriptive name for the source
16
* @return Source.Builder for configuration
17
*/
18
public static Builder newBuilder(String language, CharSequence characters, String name);
19
20
/**
21
* Creates a builder for constructing Source objects from files
22
* @param language the language identifier
23
* @param file the source file
24
* @return Source.Builder for configuration
25
*/
26
public static Builder newBuilder(String language, File file);
27
28
/**
29
* Creates a builder for constructing Source objects from URLs
30
* @param language the language identifier
31
* @param url the source URL
32
* @return Source.Builder for configuration
33
*/
34
public static Builder newBuilder(String language, URL url);
35
36
/**
37
* Creates a builder for constructing Source objects from readers
38
* @param language the language identifier
39
* @param source the Reader providing source content
40
* @param name a descriptive name for the source
41
* @return Source.Builder for configuration
42
*/
43
public static Builder newBuilder(String language, Reader source, String name);
44
45
/**
46
* Quick creation method for simple string sources
47
* @param language the language identifier
48
* @param source the source code content
49
* @return Source object ready for evaluation
50
*/
51
public static Source create(String language, CharSequence source);
52
```
53
54
**Usage Examples:**
55
56
```java
57
// Simple string source
58
Source simpleSource = Source.create("python", "print('Hello, World!')");
59
60
// Named string source with builder
61
Source namedSource = Source.newBuilder("python",
62
"def factorial(n):\n return 1 if n <= 1 else n * factorial(n-1)",
63
"factorial.py")
64
.build();
65
66
// File-based source
67
File pythonFile = new File("/path/to/script.py");
68
Source fileSource = Source.newBuilder("python", pythonFile)
69
.mimeType("text/x-python")
70
.build();
71
72
// URL-based source
73
URL scriptUrl = new URL("https://example.com/script.py");
74
Source urlSource = Source.newBuilder("python", scriptUrl)
75
.cached(true)
76
.build();
77
78
// Reader-based source
79
StringReader reader = new StringReader("import math\nprint(math.pi)");
80
Source readerSource = Source.newBuilder("python", reader, "math_example.py")
81
.build();
82
83
// Multi-line Python script
84
String pythonScript = """
85
import sys
86
import json
87
88
def process_data(data):
89
result = []
90
for item in data:
91
if isinstance(item, dict):
92
result.append(item.get('value', 0) * 2)
93
return result
94
95
data = [{'value': 1}, {'value': 2}, {'value': 3}]
96
print(json.dumps(process_data(data)))
97
""";
98
99
Source scriptSource = Source.newBuilder("python", pythonScript, "data_processor.py")
100
.uri(URI.create("file:///examples/data_processor.py"))
101
.build();
102
```
103
104
### Language Detection
105
106
Automatically detect the language of source files based on file extensions and content analysis.
107
108
```java { .api }
109
/**
110
* Detects the language of a file based on its extension and content
111
* @param file the file to analyze
112
* @return language identifier string, or null if detection fails
113
*/
114
public static String findLanguage(File file);
115
116
/**
117
* Detects the language of a URL resource based on path and content
118
* @param url the URL to analyze
119
* @return language identifier string, or null if detection fails
120
*/
121
public static String findLanguage(URL url);
122
123
/**
124
* Detects the MIME type of a file
125
* @param file the file to analyze
126
* @return MIME type string, or null if detection fails
127
*/
128
public static String findMimeType(File file);
129
130
/**
131
* Detects the MIME type of a URL resource
132
* @param url the URL to analyze
133
* @return MIME type string, or null if detection fails
134
*/
135
public static String findMimeType(URL url);
136
```
137
138
**Usage Examples:**
139
140
```java
141
// Automatic language detection
142
File pythonFile = new File("script.py");
143
String detectedLanguage = Source.findLanguage(pythonFile); // "python"
144
145
File unknownFile = new File("mystery_script");
146
String language = Source.findLanguage(unknownFile);
147
if (language != null) {
148
Source source = Source.newBuilder(language, unknownFile).build();
149
} else {
150
// Fallback or manual specification
151
Source source = Source.newBuilder("python", unknownFile).build();
152
}
153
154
// MIME type detection
155
String mimeType = Source.findMimeType(pythonFile); // "text/x-python"
156
157
// URL-based detection
158
URL scriptUrl = new URL("https://raw.githubusercontent.com/user/repo/main/script.py");
159
String urlLanguage = Source.findLanguage(scriptUrl); // "python"
160
String urlMimeType = Source.findMimeType(scriptUrl); // "text/x-python"
161
162
// Combined detection and source creation
163
File sourceFile = new File("algorithms.py");
164
String detectedLang = Source.findLanguage(sourceFile);
165
if ("python".equals(detectedLang)) {
166
Source source = Source.newBuilder(detectedLang, sourceFile)
167
.mimeType(Source.findMimeType(sourceFile))
168
.build();
169
170
Value result = context.eval(source);
171
}
172
```
173
174
### Source Metadata
175
176
Access metadata and content information from Source objects.
177
178
```java { .api }
179
/**
180
* Gets the language identifier for this source
181
* @return the language identifier
182
*/
183
public String getLanguage();
184
185
/**
186
* Gets the name of this source
187
* @return the source name
188
*/
189
public String getName();
190
191
/**
192
* Gets the path of this source (if file-based)
193
* @return the file path, or null if not file-based
194
*/
195
public String getPath();
196
197
/**
198
* Gets the URI of this source
199
* @return the source URI
200
*/
201
public URI getURI();
202
203
/**
204
* Gets the MIME type of this source
205
* @return the MIME type, or null if not specified
206
*/
207
public String getMimeType();
208
209
/**
210
* Checks if this source has character-based content
211
* @return true if the source contains text
212
*/
213
public boolean hasCharacters();
214
215
/**
216
* Checks if this source has byte-based content
217
* @return true if the source contains binary data
218
*/
219
public boolean hasBytes();
220
221
/**
222
* Gets the character content of this source
223
* @return CharSequence containing the source text
224
* @throws UnsupportedOperationException if source has no characters
225
*/
226
public CharSequence getCharacters();
227
228
/**
229
* Gets the byte content of this source
230
* @return ByteSequence containing the source bytes
231
* @throws UnsupportedOperationException if source has no bytes
232
*/
233
public ByteSequence getBytes();
234
235
/**
236
* Gets a Reader for the source content
237
* @return Reader for streaming the source content
238
* @throws UnsupportedOperationException if source has no characters
239
*/
240
public Reader getReader();
241
242
/**
243
* Gets the length of the source content
244
* @return number of characters in the source
245
*/
246
public int getLength();
247
248
/**
249
* Gets the number of lines in the source
250
* @return line count
251
*/
252
public int getLineCount();
253
254
/**
255
* Checks if this source is marked as interactive
256
* @return true if source is for interactive evaluation
257
*/
258
public boolean isInteractive();
259
```
260
261
**Usage Examples:**
262
263
```java
264
// Source metadata inspection
265
Source source = Source.newBuilder("python",
266
"# Python script for data analysis\nimport pandas as pd\nprint('Hello')",
267
"analysis.py")
268
.mimeType("text/x-python")
269
.uri(URI.create("file:///projects/analysis.py"))
270
.build();
271
272
// Basic metadata
273
String language = source.getLanguage(); // "python"
274
String name = source.getName(); // "analysis.py"
275
String mimeType = source.getMimeType(); // "text/x-python"
276
URI uri = source.getURI(); // file:///projects/analysis.py
277
278
// Content inspection
279
boolean hasText = source.hasCharacters(); // true
280
boolean hasBinary = source.hasBytes(); // false (for text sources)
281
282
if (hasText) {
283
CharSequence content = source.getCharacters();
284
int length = source.getLength(); // Number of characters
285
int lines = source.getLineCount(); // Number of lines
286
287
System.out.println("Source length: " + length + " characters");
288
System.out.println("Source lines: " + lines);
289
System.out.println("Content preview: " + content.toString().substring(0, 50));
290
}
291
292
// Reader-based access for large sources
293
try (Reader reader = source.getReader()) {
294
BufferedReader buffered = new BufferedReader(reader);
295
String firstLine = buffered.readLine();
296
System.out.println("First line: " + firstLine);
297
}
298
299
// File path information (for file-based sources)
300
File pythonFile = new File("scripts/calculator.py");
301
Source fileSource = Source.newBuilder("python", pythonFile).build();
302
String filePath = fileSource.getPath(); // "scripts/calculator.py"
303
```
304
305
### Source Building and Configuration
306
307
Configure Source objects with advanced options using the builder pattern.
308
309
```java { .api }
310
/**
311
* Builder class for constructing configured Source objects
312
*/
313
public static final class Source.Builder {
314
/**
315
* Sets the MIME type for this source
316
* @param mimeType the MIME type string
317
* @return this builder
318
*/
319
public Builder mimeType(String mimeType);
320
321
/**
322
* Sets the URI for this source
323
* @param uri the source URI
324
* @return this builder
325
*/
326
public Builder uri(URI uri);
327
328
/**
329
* Marks this source as cached for performance
330
* @param cached true to enable caching
331
* @return this builder
332
*/
333
public Builder cached(boolean cached);
334
335
/**
336
* Marks this source as interactive (REPL-style)
337
* @param interactive true for interactive mode
338
* @return this builder
339
*/
340
public Builder interactive(boolean interactive);
341
342
/**
343
* Marks this source as internal (not user code)
344
* @param internal true for internal sources
345
* @return this builder
346
*/
347
public Builder internal(boolean internal);
348
349
/**
350
* Sets the character encoding for file-based sources
351
* @param encoding the character encoding
352
* @return this builder
353
*/
354
public Builder encoding(Charset encoding);
355
356
/**
357
* Sets content directly as byte array
358
* @param bytes the source content as bytes
359
* @return this builder
360
*/
361
public Builder content(byte[] bytes);
362
363
/**
364
* Sets content directly as string
365
* @param content the source content
366
* @return this builder
367
*/
368
public Builder content(String content);
369
370
/**
371
* Builds the configured Source object
372
* @return new Source instance
373
*/
374
public Source build();
375
}
376
```
377
378
**Usage Examples:**
379
380
```java
381
// Advanced source configuration
382
Source configuredSource = Source.newBuilder("python", "print('Hello')", "hello.py")
383
.mimeType("text/x-python")
384
.uri(URI.create("memory:///hello.py"))
385
.cached(true)
386
.interactive(false)
387
.internal(false)
388
.build();
389
390
// Interactive source for REPL
391
Source replSource = Source.newBuilder("python", "x = 42", "<stdin>")
392
.interactive(true)
393
.build();
394
395
// File source with custom encoding
396
Source encodedSource = Source.newBuilder("python", new File("utf8_script.py"))
397
.encoding(StandardCharsets.UTF_8)
398
.cached(true)
399
.build();
400
401
// Binary content source
402
byte[] pythonBytecode = loadPythonBytecode(); // Custom method
403
Source bytecodeSource = Source.newBuilder("python", "", "compiled.pyc")
404
.content(pythonBytecode)
405
.mimeType("application/x-python-bytecode")
406
.build();
407
408
// Network source with caching
409
URL networkScript = new URL("https://cdn.example.com/utils.py");
410
Source networkSource = Source.newBuilder("python", networkScript)
411
.cached(true) // Cache for performance
412
.build();
413
414
// Internal library source
415
String internalLib = """
416
# Internal utility functions
417
def _internal_helper(value):
418
return value * 2
419
""";
420
421
Source internalSource = Source.newBuilder("python", internalLib, "<internal>")
422
.internal(true) // Mark as internal
423
.build();
424
425
// Template-based source generation
426
String template = "result = calculate(%s, %s)";
427
String pythonCode = String.format(template, 10, 20);
428
Source templateSource = Source.newBuilder("python", pythonCode, "generated.py")
429
.uri(URI.create("generated://template/calculate"))
430
.build();
431
```
432
433
### Source Sections and Debugging
434
435
Work with source sections for error reporting and debugging support.
436
437
```java { .api }
438
/**
439
* Creates a source section representing a portion of this source
440
* @param startIndex character index where section starts
441
* @param length number of characters in section
442
* @return SourceSection representing the specified range
443
*/
444
public SourceSection createSection(int startIndex, int length);
445
446
/**
447
* Creates a source section by line and column numbers
448
* @param startLine starting line (1-based)
449
* @param startColumn starting column (1-based)
450
* @param endLine ending line (1-based)
451
* @param endColumn ending column (1-based)
452
* @return SourceSection representing the specified range
453
*/
454
public SourceSection createSection(int startLine, int startColumn, int endLine, int endColumn);
455
456
/**
457
* Creates a source section for a specific line
458
* @param lineNumber the line number (1-based)
459
* @return SourceSection representing the entire line
460
*/
461
public SourceSection createSection(int lineNumber);
462
```
463
464
**Usage Examples:**
465
466
```java
467
String pythonCode = """
468
def fibonacci(n):
469
if n <= 1:
470
return n
471
return fibonacci(n-1) + fibonacci(n-2)
472
473
result = fibonacci(10)
474
print("Result:", result)
475
""";
476
477
Source source = Source.create("python", pythonCode);
478
479
// Create section for function definition (lines 1-4)
480
SourceSection funcSection = source.createSection(1, 1, 4, 40);
481
482
// Create section for specific line
483
SourceSection resultLine = source.createSection(6); // "result = fibonacci(10)"
484
485
// Create section by character index
486
SourceSection printSection = source.createSection(
487
pythonCode.indexOf("print"),
488
"print(\"Result:\", result)".length()
489
);
490
491
// Use sections for error reporting
492
try {
493
Value result = context.eval(source);
494
} catch (PolyglotException e) {
495
SourceSection errorLocation = e.getSourceLocation();
496
if (errorLocation != null && errorLocation.getSource().equals(source)) {
497
System.err.println("Error at line " + errorLocation.getStartLine() +
498
", column " + errorLocation.getStartColumn());
499
System.err.println("Code: " + errorLocation.getCharacters());
500
}
501
}
502
```
503
504
## Types
505
506
```java { .api }
507
/**
508
* Represents a sequence of bytes for binary source content
509
*/
510
public interface ByteSequence {
511
/**
512
* Gets the length of the byte sequence
513
* @return number of bytes
514
*/
515
int length();
516
517
/**
518
* Gets the byte at specified index
519
* @param index the byte index
520
* @return byte value at index
521
*/
522
byte byteAt(int index);
523
524
/**
525
* Creates a subsequence of bytes
526
* @param startIndex starting index (inclusive)
527
* @param endIndex ending index (exclusive)
528
* @return ByteSequence representing the subsequence
529
*/
530
ByteSequence subSequence(int startIndex, int endIndex);
531
532
/**
533
* Converts to byte array
534
* @return byte array containing the sequence
535
*/
536
byte[] toByteArray();
537
}
538
539
/**
540
* Represents a section within a source for error reporting and debugging
541
*/
542
public final class SourceSection {
543
/**
544
* Checks if this section is available
545
* @return true if section information is available
546
*/
547
public boolean isAvailable();
548
549
/**
550
* Gets the source containing this section
551
* @return the Source object
552
*/
553
public Source getSource();
554
555
/**
556
* Gets the starting line number (1-based)
557
* @return starting line number
558
*/
559
public int getStartLine();
560
561
/**
562
* Gets the ending line number (1-based)
563
* @return ending line number
564
*/
565
public int getEndLine();
566
567
/**
568
* Gets the starting column (1-based)
569
* @return starting column number
570
*/
571
public int getStartColumn();
572
573
/**
574
* Gets the ending column (1-based)
575
* @return ending column number
576
*/
577
public int getEndColumn();
578
579
/**
580
* Gets the character index where section starts
581
* @return starting character index
582
*/
583
public int getCharIndex();
584
585
/**
586
* Gets the character index where section ends
587
* @return ending character index
588
*/
589
public int getCharEndIndex();
590
591
/**
592
* Gets the length of this section in characters
593
* @return section length
594
*/
595
public int getCharLength();
596
597
/**
598
* Gets the text content of this section
599
* @return CharSequence containing the section text
600
*/
601
public CharSequence getCharacters();
602
}
603
```