0
# Utility Functions
1
2
Nuitka provides a comprehensive set of cross-platform utilities for file operations, process execution, and system compatibility during the compilation process. These utilities handle the complex details of cross-platform development and provide consistent interfaces for common operations.
3
4
## Capabilities
5
6
### File Operations
7
8
Cross-platform file and directory manipulation utilities optimized for compilation workflows.
9
10
```python { .api }
11
def getFileList(directory: str, ignore_dirs=(), ignore_suffixes=()) -> list:
12
"""
13
Get list of files in directory recursively.
14
15
Traverses directory structure and returns all files,
16
filtering out common build artifacts and temporary files.
17
18
Args:
19
directory (str): Directory path to scan
20
ignore_dirs (tuple): Directory names to ignore
21
ignore_suffixes (tuple): File suffixes to ignore
22
23
Returns:
24
list: File paths relative to directory
25
26
Raises:
27
OSError: On directory access errors
28
"""
29
30
def copyFile(source_path: str, dest_path: str):
31
"""
32
Copy file with cross-platform compatibility.
33
34
Copies files while handling platform-specific attributes
35
and permissions correctly.
36
37
Args:
38
source_path (str): Source file path
39
dest_path (str): Destination file path
40
41
Raises:
42
OSError: On file operation errors
43
PermissionError: On insufficient permissions
44
"""
45
46
def makePath(path: str):
47
"""
48
Create directory with parent directories.
49
50
Creates directory structure ensuring all parent directories
51
exist, with proper error handling.
52
53
Args:
54
path (str): Directory path to create
55
56
Raises:
57
OSError: On directory creation errors
58
"""
59
60
def deleteFile(path: str, must_exist: bool):
61
"""
62
Remove file with error handling.
63
64
Safely removes files with proper cross-platform handling
65
of file locks and permissions.
66
67
Args:
68
path (str): Path to file to remove
69
must_exist (bool): Whether file must exist
70
71
Raises:
72
OSError: On file removal errors
73
"""
74
75
def getFileContents(filename: str, mode: str = "r", encoding=None):
76
"""
77
Read complete file contents.
78
79
Reads and returns the entire contents of a file with proper
80
encoding handling and error management.
81
82
Args:
83
filename (str): Path to file to read
84
mode (str): File open mode ('r', 'rb', etc.)
85
encoding: Text encoding (None for binary mode)
86
87
Returns:
88
str | bytes: File contents
89
90
Raises:
91
OSError: On file access errors
92
UnicodeDecodeError: On encoding issues
93
"""
94
```
95
96
**Usage Example:**
97
98
```python
99
from nuitka.utils.FileOperations import getFileList, copyFile, makePath
100
101
# Get all Python files in a project
102
python_files = getFileList("src/", ignore_dirs=("__pycache__",), ignore_suffixes=(".pyc",))
103
python_files = [f for f in python_files if f.endswith(".py")]
104
105
print(f"Found {len(python_files)} Python files")
106
107
# Create build directory and copy files
108
makePath("build/compiled")
109
for src_file in python_files:
110
dest_file = src_file.replace("src/", "build/compiled/")
111
makePath(os.path.dirname(dest_file))
112
copyFile(src_file, dest_file)
113
```
114
115
### Process Execution
116
117
Execute external commands and processes with comprehensive error handling and output capture.
118
119
```python { .api }
120
def check_call(*popenargs, **kwargs) -> int:
121
"""
122
Execute command and check return code.
123
124
Runs external commands and raises exception on non-zero
125
exit codes, with comprehensive logging and error capture.
126
127
Args:
128
*popenargs: Command and arguments to execute
129
**kwargs: Additional subprocess options
130
131
Returns:
132
int: Command exit code (0 for success)
133
134
Raises:
135
subprocess.CalledProcessError: On command execution failures
136
"""
137
138
def check_output(*popenargs, **kwargs) -> bytes:
139
"""
140
Execute command and return output.
141
142
Runs command and captures stdout output, with proper
143
encoding handling and error management.
144
145
Args:
146
*popenargs: Command and arguments
147
**kwargs: Additional subprocess options
148
149
Returns:
150
bytes: Command output (stdout)
151
152
Raises:
153
subprocess.CalledProcessError: On execution errors
154
"""
155
156
def getExecutablePath(filename: str, extra_dir=None) -> str | None:
157
"""
158
Find executable in system PATH.
159
160
Locates executable programs in the system PATH with
161
platform-specific handling (.exe extension on Windows).
162
163
Args:
164
filename (str): Program name to find
165
extra_dir (str): Additional directory to search
166
167
Returns:
168
str | None: Full path to executable or None if not found
169
"""
170
171
def isExecutableCommand(command: str) -> bool:
172
"""
173
Check if command is executable.
174
175
Tests whether a command is available and executable
176
in the current environment.
177
178
Args:
179
command (str): Command name to test
180
181
Returns:
182
bool: True if command is executable
183
"""
184
```
185
186
**Usage Example:**
187
188
```python
189
from nuitka.utils.Execution import check_call, check_output, getExecutablePath
190
191
# Check if required tools are available
192
gcc_path = getExecutablePath("gcc")
193
if gcc_path:
194
print(f"Found GCC compiler at: {gcc_path}")
195
196
# Get compiler version
197
version_output = check_output(["gcc", "--version"])
198
print(f"GCC version: {version_output.decode().split()[2]}")
199
200
# Compile a C file
201
check_call(["gcc", "-o", "output", "input.c"], cwd="build/")
202
print("Compilation successful")
203
else:
204
print("GCC compiler not found")
205
```
206
207
### Distribution Management
208
209
Detect and analyze Python package distributions and their metadata.
210
211
```python { .api }
212
def getDistributionFiles(distribution) -> list:
213
"""
214
Get files belonging to a distribution.
215
216
Retrieves all files that are part of an installed
217
Python package distribution.
218
219
Args:
220
distribution: Distribution object from pkg_resources or importlib
221
222
Returns:
223
list: File paths belonging to the distribution
224
225
Raises:
226
DistributionNotFound: If distribution cannot be found
227
"""
228
229
def getDistributionTopLevelPackageNames(distribution) -> list:
230
"""
231
Get top-level package names from distribution.
232
233
Extracts the main package names provided by a distribution,
234
which can be used to identify what modules are available.
235
236
Args:
237
distribution: Distribution object
238
239
Returns:
240
list: Top-level package names
241
"""
242
243
def checkDistributionMetadataRecord(package_dir: str, distribution):
244
"""
245
Check distribution metadata record.
246
247
Validates that distribution metadata matches the actual
248
installed files and their checksums.
249
250
Args:
251
package_dir (str): Package installation directory
252
distribution: Distribution object to check
253
254
Returns:
255
bool: True if metadata is consistent
256
257
Raises:
258
MetadataError: On metadata validation failures
259
"""
260
```
261
262
**Usage Example:**
263
264
```python
265
from nuitka.utils.Distributions import getDistributionFiles, getDistributionTopLevelPackageNames
266
import pkg_resources
267
268
# Analyze a package for compilation
269
try:
270
distribution = pkg_resources.get_distribution("requests")
271
272
# Get package files
273
files = getDistributionFiles(distribution)
274
print(f"Package files: {len(files)}")
275
276
# Get top-level packages
277
packages = getDistributionTopLevelPackageNames(distribution)
278
print(f"Top-level packages: {packages}")
279
280
except pkg_resources.DistributionNotFound:
281
print("Package requests not found")
282
```
283
284
### Path and System Utilities
285
286
Cross-platform path manipulation and system information utilities.
287
288
```python { .api }
289
def relpath(path: str, start: str = ".") -> str:
290
"""
291
Get relative path with cross-platform compatibility.
292
293
Computes relative path from start to target path with
294
proper handling of platform-specific path separators.
295
296
Args:
297
path (str): Target path
298
start (str): Starting path (default current directory)
299
300
Returns:
301
str: Relative path from start to target
302
"""
303
304
def getExternalUsePath(filename: str, only_dirname: bool = False) -> str:
305
"""
306
Get path suitable for external tool usage.
307
308
Converts internal path representation to format suitable
309
for passing to external tools and commands.
310
311
Args:
312
filename (str): Internal path
313
only_dirname (bool): Return only directory part
314
315
Returns:
316
str: External-compatible path
317
"""
318
319
def isRelativePath(path: str) -> bool:
320
"""
321
Check if path is relative.
322
323
Determines whether a path is relative or absolute
324
with cross-platform compatibility.
325
326
Args:
327
path (str): Path to check
328
329
Returns:
330
bool: True if path is relative
331
"""
332
333
def getNormalizedPath(path: str) -> str:
334
"""
335
Normalize path for consistency.
336
337
Normalizes path separators and resolves relative components
338
for consistent path handling across platforms.
339
340
Args:
341
path (str): Path to normalize
342
343
Returns:
344
str: Normalized path
345
"""
346
```
347
348
**Usage Example:**
349
350
```python
351
from nuitka.utils.FileOperations import relpath, getExternalUsePath, getNormalizedPath
352
353
# Path manipulation for cross-platform builds
354
source_path = "/project/src/module.py"
355
build_path = "/project/build/"
356
357
# Get relative path
358
rel_path = relpath(source_path, build_path)
359
print(f"Relative path: {rel_path}")
360
361
# Get external use path
362
ext_path = getExternalUsePath(source_path)
363
print(f"External path: {ext_path}")
364
365
# Normalize path
366
norm_path = getNormalizedPath("./src/../build/./output")
367
print(f"Normalized: {norm_path}")
368
```
369
370
## Environment and Platform Detection
371
372
### Platform Detection Functions
373
374
Essential platform and system detection utilities from nuitka.utils.Utils.
375
376
```python { .api }
377
def getOS() -> str:
378
"""
379
Get operating system name.
380
381
Returns standardized OS name for cross-platform compatibility.
382
383
Returns:
384
str: OS name ('Linux', 'Windows', 'Darwin', 'FreeBSD', etc.)
385
"""
386
387
def getArchitecture() -> str:
388
"""
389
Get system architecture.
390
391
Returns the system architecture for compilation targeting.
392
393
Returns:
394
str: Architecture name ('x86_64', 'x86', 'arm64', etc.)
395
"""
396
397
def isWin32Windows() -> bool:
398
"""
399
Check if running on Windows.
400
401
Returns:
402
bool: True if on Windows platform
403
"""
404
405
def isMacOS() -> bool:
406
"""
407
Check if running on macOS.
408
409
Returns:
410
bool: True if on macOS platform
411
"""
412
413
def isLinux() -> bool:
414
"""
415
Check if running on Linux.
416
417
Returns:
418
bool: True if on Linux platform
419
"""
420
421
def getLinuxDistribution() -> tuple[str, str, str]:
422
"""
423
Get Linux distribution information.
424
425
Returns:
426
tuple[str, str, str]: (name, version, codename)
427
"""
428
429
def getWindowsRelease() -> int | None:
430
"""
431
Get Windows release number.
432
433
Returns:
434
int | None: Windows version number or None if not Windows
435
"""
436
```
437
438
### Environment Variable Management
439
440
Utilities for managing environment variables during compilation.
441
442
```python
443
from nuitka.utils.Execution import withEnvironmentVarOverridden, withEnvironmentPathAdded
444
445
def configure_build_environment():
446
"""Configure environment for compilation."""
447
448
# Override specific environment variables
449
with withEnvironmentVarOverridden("CC", "gcc"):
450
with withEnvironmentVarOverridden("CXX", "g++"):
451
# Compilation happens with custom compiler settings
452
pass
453
454
# Add paths to environment
455
with withEnvironmentPathAdded("PATH", "/usr/local/bin", "/opt/tools/bin"):
456
# Tools in custom paths are now available
457
pass
458
```
459
460
### Cross-Platform File Operations
461
462
Handle platform-specific file operations safely.
463
464
```python
465
from nuitka.utils.FileOperations import (
466
isPathExecutable,
467
addFileExecutablePermission,
468
removeFileExecutablePermission
469
)
470
471
def manage_executable_files(file_path):
472
"""Manage executable permissions cross-platform."""
473
474
# Check if file is executable
475
if isPathExecutable(file_path):
476
print(f"{file_path} is executable")
477
else:
478
# Make file executable
479
addFileExecutablePermission(file_path)
480
print(f"Made {file_path} executable")
481
482
# Remove executable permission when needed
483
removeFileExecutablePermission(file_path)
484
```
485
486
## Advanced File Operations
487
488
### Atomic File Operations
489
490
Perform file operations atomically to avoid corruption.
491
492
```python
493
from nuitka.utils.FileOperations import replaceFileAtomic, withTemporaryFile
494
495
def safe_file_update(target_file, new_content):
496
"""Update file content atomically."""
497
498
# Create temporary file with new content
499
with withTemporaryFile(suffix=".tmp", delete=False) as temp_file:
500
temp_file.write(new_content)
501
temp_filename = temp_file.name
502
503
# Atomically replace target file
504
replaceFileAtomic(temp_filename, target_file)
505
print(f"Atomically updated {target_file}")
506
```
507
508
### Directory Tree Operations
509
510
Handle entire directory trees efficiently.
511
512
```python
513
from nuitka.utils.FileOperations import copyTree, removeDirectory
514
515
def manage_directory_trees():
516
"""Demonstrate directory tree operations."""
517
518
# Copy entire directory tree
519
copyTree("source_dir/", "dest_dir/")
520
521
# Remove directory tree safely
522
removeDirectory("old_build/", logger=None, ignore_errors=True,
523
extra_recommendation="Check permissions")
524
```
525
526
## Error Handling
527
528
### Robust Utility Functions
529
530
Create wrapper functions with comprehensive error handling.
531
532
```python
533
from nuitka.utils.FileOperations import getFileList, copyFile
534
import logging
535
536
def safe_file_operations():
537
"""Demonstrate safe file operations with error handling."""
538
logger = logging.getLogger(__name__)
539
540
def safe_get_file_list(directory):
541
"""Safely get file list with error handling."""
542
try:
543
return getFileList(directory)
544
except OSError as e:
545
logger.error(f"Failed to list files in {directory}: {e}")
546
return []
547
except PermissionError as e:
548
logger.error(f"Permission denied accessing {directory}: {e}")
549
return []
550
551
def safe_copy_with_retry(source, dest, max_retries=3):
552
"""Copy file with retry logic."""
553
import time
554
for attempt in range(max_retries):
555
try:
556
copyFile(source, dest)
557
return True
558
except OSError as e:
559
if attempt == max_retries - 1:
560
logger.error(f"Failed to copy {source} to {dest} after {max_retries} attempts: {e}")
561
return False
562
else:
563
logger.warning(f"Copy attempt {attempt + 1} failed, retrying: {e}")
564
time.sleep(1) # Wait before retry
565
566
return False
567
568
# Usage
569
files = safe_get_file_list("src/")
570
for file_path in files:
571
if file_path.endswith(".py"):
572
dest_path = file_path.replace("src/", "build/")
573
safe_copy_with_retry(file_path, dest_path)
574
```
575
576
## Types
577
578
```python { .api }
579
# File operation types
580
FilePath = str
581
DirectoryPath = str
582
FileList = list[str]
583
FileContents = str | bytes
584
585
# Process execution types
586
Command = list[str]
587
ExitCode = int
588
CommandOutput = bytes
589
Environment = dict[str, str]
590
591
# Distribution types
592
DistributionObject = Any # pkg_resources.Distribution or importlib equivalent
593
PackageFiles = list[str]
594
TopLevelPackages = list[str]
595
596
# Path types
597
RelativePath = str
598
AbsolutePath = str
599
NormalizedPath = str
600
ExternalPath = str
601
602
# Platform types
603
ExecutablePath = str | None
604
IsExecutable = bool
605
EnvironmentVar = str
606
```