0
# Development Tools and Utilities
1
2
Utilities for PyCall.jl installation, system image building, testing infrastructure, and development workflow support including PyCall rebuild and Julia executable management for PyJulia development and deployment.
3
4
## Capabilities
5
6
### PyCall.jl Installation and Management
7
8
Install, configure, and rebuild PyCall.jl package for PyJulia operation.
9
10
```python { .api }
11
def install(julia="julia", color="auto", python=None, quiet=False):
12
"""
13
Install/configure Julia packages required by PyJulia.
14
15
Parameters:
16
- julia: Path to Julia executable (default: "julia")
17
- color: Color output setting ("auto"/"yes"/"no")
18
- python: Python executable path (default: current Python)
19
- quiet: Suppress output if True
20
21
Raises:
22
- PyCallInstallError: If PyCall.jl installation fails
23
"""
24
25
def build_pycall(julia="julia", python=sys.executable, **kwargs):
26
"""
27
Force rebuild PyCall.jl package.
28
29
Parameters:
30
- julia: Path to Julia executable
31
- python: Python executable to configure PyCall for
32
- **kwargs: Additional build options
33
"""
34
35
class PyCallInstallError(Exception):
36
"""Raised when PyCall.jl installation or configuration fails."""
37
```
38
39
### System Image Building
40
41
Build custom Julia system images for faster PyJulia startup and deployment.
42
43
```python { .api }
44
def build_sysimage(output, julia="julia", script=None, debug=False,
45
compiler_env="", base_sysimage=None):
46
"""
47
Build Julia system image for faster startup.
48
49
Parameters:
50
- output: Output path for system image file
51
- julia: Path to Julia executable
52
- script: Julia script to precompile into sysimage
53
- debug: Enable debug output
54
- compiler_env: Environment for PackageCompiler.jl
55
- base_sysimage: Base system image to build upon
56
57
Raises:
58
- KnownError: Expected errors during system image building
59
"""
60
61
class KnownError(Exception):
62
"""Expected errors that can occur during system image building."""
63
64
def script_path(name: str) -> str:
65
"""
66
Get path to bundled Julia script.
67
68
Parameters:
69
- name: Script name
70
71
Returns:
72
- Absolute path to script file
73
"""
74
75
def install_packagecompiler_cmd(julia: str, compiler_env: str) -> list:
76
"""Get PackageCompiler.jl install command."""
77
78
def build_sysimage_cmd(julia_py: str, julia: str, compile_args: list) -> list:
79
"""Get system image build command."""
80
```
81
82
### Testing Infrastructure
83
84
PyTest integration and testing utilities for PyJulia development.
85
86
```python { .api }
87
def pytest_addoption(parser):
88
"""Add PyJulia-specific pytest command line options."""
89
90
def pytest_sessionstart(session):
91
"""pytest session startup hook."""
92
93
def pytest_configure(config):
94
"""pytest configuration hook."""
95
96
def pytest_runtest_setup(item):
97
"""pytest test setup hook."""
98
99
# Testing fixtures
100
def julia():
101
"""Julia runtime fixture for testing."""
102
103
def juliainfo():
104
"""JuliaInfo fixture for testing."""
105
```
106
107
### Test Execution and Validation
108
109
Run PyJulia test suite and validate dependencies.
110
111
```python { .api }
112
def check_test_dependencies():
113
"""
114
Verify that required test dependencies are available.
115
116
Raises:
117
- ApplicationError: If required dependencies are missing
118
"""
119
120
def runtests(pytest_args: list, dry_run: bool = False):
121
"""
122
Run PyJulia test suite with pytest.
123
124
Parameters:
125
- pytest_args: Arguments to pass to pytest
126
- dry_run: Show what would be run without executing
127
"""
128
129
class ApplicationError(Exception):
130
"""Application-level errors during test execution."""
131
```
132
133
### Development Workflow Utilities
134
135
Tools for managing development workflows including conditional rebuilds and signal handling.
136
137
```python { .api }
138
def maybe_rebuild(rebuild: bool, julia: str = "julia"):
139
"""
140
Context manager for conditional PyCall.jl rebuild.
141
142
Parameters:
143
- rebuild: Whether to rebuild PyCall.jl
144
- julia: Path to Julia executable
145
"""
146
147
def with_rebuilt(rebuild: bool, julia: str, command: list):
148
"""
149
Execute command with optional PyCall rebuild.
150
151
Parameters:
152
- rebuild: Whether to rebuild before execution
153
- julia: Path to Julia executable
154
- command: Command to execute
155
"""
156
157
def ignoring(sig):
158
"""
159
Context manager for ignoring system signals.
160
161
Parameters:
162
- sig: Signal to ignore during execution
163
"""
164
```
165
166
### Output Stream Management
167
168
Redirect Julia output streams to Python for integrated logging and display.
169
170
```python { .api }
171
def redirect_output_streams():
172
"""Redirect Julia stdout/stderr streams to Python."""
173
174
def make_receiver(io):
175
"""
176
Create output stream receiver function for stream redirection.
177
178
Parameters:
179
- io: Python IO object to receive redirected output
180
181
Returns:
182
- Receiver function for Julia output
183
"""
184
```
185
186
### Julia Executable Discovery
187
188
Find and validate Julia executable paths and configurations.
189
190
```python { .api }
191
def julia_py_executable() -> str:
192
"""
193
Get path to julia-py executable script.
194
195
Returns:
196
- Absolute path to julia-py script
197
"""
198
```
199
200
### Temporary Directory Management
201
202
Utilities for creating and managing temporary directories during builds.
203
204
```python { .api }
205
def temporarydirectory(**kwargs):
206
"""
207
Context manager for temporary directory creation.
208
209
Parameters:
210
- **kwargs: Arguments passed to tempfile.TemporaryDirectory
211
212
Returns:
213
- Context manager yielding temporary directory path
214
"""
215
216
def check_call(cmd: list, **kwargs):
217
"""
218
Execute command with detailed logging.
219
220
Parameters:
221
- cmd: Command and arguments as list
222
- **kwargs: Additional subprocess arguments
223
"""
224
```
225
226
## Usage Examples
227
228
### PyCall.jl Installation
229
230
```python
231
from julia import install
232
from julia.tools import PyCallInstallError
233
234
try:
235
# Basic installation
236
install()
237
238
# Install with specific Julia executable
239
install(julia="/usr/local/bin/julia")
240
241
# Quiet installation
242
install(quiet=True)
243
244
# Install for specific Python version
245
install(python="/usr/bin/python3.9")
246
247
except PyCallInstallError as e:
248
print(f"PyCall installation failed: {e}")
249
```
250
251
### System Image Building
252
253
```python
254
from julia.sysimage import build_sysimage, KnownError
255
256
try:
257
# Build basic system image
258
build_sysimage("my_sysimage.so")
259
260
# Build with custom precompilation script
261
build_sysimage(
262
output="optimized.so",
263
script="precompile_script.jl",
264
debug=True
265
)
266
267
# Build with specific Julia version
268
build_sysimage(
269
output="custom.so",
270
julia="/path/to/julia",
271
compiler_env="JULIA_PKG_DEVDIR=/dev/packages"
272
)
273
274
except KnownError as e:
275
print(f"Expected error during build: {e}")
276
```
277
278
### Testing Setup
279
280
```python
281
from julia.runtests import runtests, check_test_dependencies
282
from julia.runtests import ApplicationError
283
284
try:
285
# Check test dependencies
286
check_test_dependencies()
287
288
# Run all tests
289
runtests([])
290
291
# Run specific test with verbose output
292
runtests(["-v", "test_core.py"])
293
294
# Dry run to see what tests would run
295
runtests(["--collect-only"], dry_run=True)
296
297
except ApplicationError as e:
298
print(f"Test execution failed: {e}")
299
```
300
301
### Development Workflow
302
303
```python
304
from julia.with_rebuilt import maybe_rebuild, with_rebuilt
305
306
# Conditional rebuild context
307
with maybe_rebuild(rebuild=True):
308
# Code that may need fresh PyCall build
309
from julia import Julia
310
jl = Julia()
311
jl.eval("println(\"Hello after rebuild!\")")
312
313
# Execute command with rebuild
314
with_rebuilt(
315
rebuild=True,
316
julia="/usr/local/bin/julia",
317
command=["python", "my_script.py"]
318
)
319
```
320
321
### Output Stream Redirection
322
323
```python
324
from julia.tools import redirect_output_streams, make_receiver
325
import sys
326
327
# Redirect Julia output to Python
328
redirect_output_streams()
329
330
# Create custom receiver for Julia output
331
receiver = make_receiver(sys.stdout)
332
333
# Now Julia output appears in Python stdout
334
from julia import Julia
335
jl = Julia()
336
jl.eval('println("This will appear in Python output")')
337
```
338
339
### Custom System Image Scripts
340
341
```python
342
from julia.sysimage import script_path, build_sysimage
343
344
# Get path to bundled precompilation script
345
precompile_script = script_path("precompile_common.jl")
346
347
# Build system image with bundled script
348
build_sysimage(
349
output="precompiled.so",
350
script=precompile_script,
351
debug=True
352
)
353
```
354
355
### Testing with Fixtures
356
357
```python
358
# In a pytest test file
359
import pytest
360
from julia.pytestplugin import julia, juliainfo
361
362
def test_julia_functionality(julia):
363
"""Test using Julia fixture."""
364
result = julia.eval("2 + 3")
365
assert result == 5
366
367
def test_julia_info(juliainfo):
368
"""Test using JuliaInfo fixture."""
369
assert juliainfo.version is not None
370
assert juliainfo.executable is not None
371
```
372
373
### Signal Handling During Operations
374
375
```python
376
from julia.with_rebuilt import ignoring
377
import signal
378
379
# Ignore SIGINT during critical operation
380
with ignoring(signal.SIGINT):
381
# Long-running operation that shouldn't be interrupted
382
from julia.sysimage import build_sysimage
383
build_sysimage("critical.so")
384
```
385
386
### Command Line Interface Integration
387
388
```python
389
# Main function for command-line tools
390
from julia.sysimage import main as sysimage_main
391
from julia.runtests import main as test_main
392
from julia.with_rebuilt import main as rebuilt_main
393
394
# These can be called from command line or programmatically
395
if __name__ == "__main__":
396
import sys
397
398
# Build system image from command line
399
sysimage_main(sys.argv[1:])
400
401
# Run tests from command line
402
test_main(sys.argv[1:])
403
404
# Execute with rebuild from command line
405
rebuilt_main(sys.argv[1:])
406
```
407
408
## Error Handling
409
410
Development tools provide specific exceptions for different failure modes:
411
412
```python
413
from julia.tools import PyCallInstallError
414
from julia.sysimage import KnownError
415
from julia.runtests import ApplicationError
416
417
try:
418
# Various development operations
419
install()
420
build_sysimage("test.so")
421
runtests([])
422
423
except PyCallInstallError as e:
424
print(f"PyCall installation issue: {e}")
425
except KnownError as e:
426
print(f"Expected build error: {e}")
427
except ApplicationError as e:
428
print(f"Application error: {e}")
429
except Exception as e:
430
print(f"Unexpected error: {e}")
431
```