Skip to content

Commit f81d8a3

Browse files
author
Christopher Doris
committed
improved error messages and support for --home
1 parent 1894606 commit f81d8a3

File tree

1 file changed

+42
-43
lines changed

1 file changed

+42
-43
lines changed

pysrc/juliacall/__init__.py

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33

44
__version__ = '0.9.1'
55

6-
from ctypes import pointer, c_int, POINTER, c_char_p
7-
from typing import Any
8-
96
_newmodule = None
107

118
def newmodule(name):
@@ -50,52 +47,53 @@ def init():
5047
import sys
5148
import subprocess
5249

53-
def option(name, default=None):
50+
def option(name, default=None, xkey=None, envkey=None):
5451
"""Get an option.
5552
5653
Options can be set as command line arguments '-X juliacall_{name}={value}' or as
5754
environment variables 'PYTHON_JULIACALL_{NAME}={value}'.
5855
"""
59-
k = 'juliacall_'+name.lower()
56+
k = xkey or 'juliacall_'+name.lower()
6057
v = sys._xoptions.get(k)
6158
if v is not None:
62-
return v
63-
k = 'PYTHON_JULIACALL_'+name.upper()
59+
return v, f'-X{k}={v}'
60+
k = envkey or 'PYTHON_JULIACALL_'+name.upper()
6461
v = os.getenv(k)
6562
if v is not None:
66-
return v
67-
return default
63+
return v, f'{k}={v}'
64+
return default, f'<default>={v}'
6865

69-
def choice(name, choices, default=None):
70-
v = option(name)
66+
def choice(name, choices, default=None, **kw):
67+
v, s = option(name, **kw)
7168
if v is None:
72-
return default
69+
return default, s
7370
if v in choices:
7471
if isinstance(choices, dict):
75-
return choices[v]
72+
return choices[v], s
7673
else:
77-
return v
74+
return v, s
7875
raise ValueError(
79-
f'invalid value for option: JULIACALL_{name.upper()}={v}, expecting one of {", ".join(choices)}')
76+
f'{s}: expecting one of {", ".join(choices)}')
8077

81-
def path_option(name, default=None):
82-
path = option(name)
78+
def path_option(name, default=None, check_exists=False, **kw):
79+
path, s = option(name, **kw)
8380
if path is not None:
84-
return os.path.abspath(path)
85-
return default
81+
if check_exists and not os.path.exists(path):
82+
raise ValueError(f'{s}: path does not exist')
83+
return os.path.abspath(path), s
84+
return default, s
8685

87-
def int_option(name, *, accept_auto=False):
88-
val = option(name)
86+
def int_option(name, *, accept_auto=False, **kw):
87+
val, s = option(name, **kw)
8988
if val is None:
90-
return None
89+
return None, s
9190
if accept_auto and val == "auto":
92-
return "auto"
91+
return "auto", s
9392
try:
9493
int(val)
95-
return val
94+
return val, s
9695
except ValueError:
97-
raise ValueError(f'invalid value for option: JULIACALL_{name.upper()}={val}, '
98-
f'expecting an int'+' or auto' if accept_auto else "")
96+
raise ValueError(f'{s}: expecting an int'+(' or auto' if accept_auto else ""))
9997

10098
def args_from_config():
10199
argv = ["--"+opt[4:].replace("_", "-")+"="+val for opt, val in CONFIG.items()
@@ -105,28 +103,28 @@ def args_from_config():
105103
argv = [s.encode("utf-8") for s in argv]
106104

107105
argc = len(argv)
108-
c = c_int(argc)
109-
v = POINTER(c_char_p)((c_char_p * len(argv))(*argv))
110-
return c, v
106+
argc = c.c_int(argc)
107+
argv = c.POINTER(c.c_char_p)((c.c_char_p * len(argv))(*argv))
108+
return argc, argv
111109

112110
# Determine if we should skip initialising.
113-
CONFIG['init'] = choice('init', ['yes', 'no'], default='yes') == 'yes'
111+
CONFIG['init'] = choice('init', ['yes', 'no'], default='yes')[0] == 'yes'
114112
if not CONFIG['init']:
115113
return
116114

117115
# Parse some more options
118-
CONFIG['opt_bindir'] = path_option('bindir')
119-
CONFIG['opt_check_bounds'] = choice('check_bounds', ['yes', 'no', 'auto'])
120-
CONFIG['opt_compile'] = choice('compile', ['yes', 'no', 'all', 'min'])
121-
CONFIG['opt_compiled_modules'] = choice('compiled_modules', ['yes', 'no'])
122-
CONFIG['opt_depwarn'] = choice('depwarn', ['yes', 'no', 'error'])
123-
CONFIG['opt_inline'] = choice('inline', ['yes', 'no'])
124-
CONFIG['opt_min_optlevel'] = choice('min_optlevel', ['0', '1', '2', '3'])
125-
CONFIG['opt_optimize'] = choice('optimize', ['0', '1', '2', '3'])
126-
CONFIG['opt_procs'] = int_option('procs', accept_auto=True)
127-
CONFIG['opt_sysimage'] = path_option('sysimage')
128-
CONFIG['opt_threads'] = int_option('threads', accept_auto=True)
129-
CONFIG['opt_warn_overwrite'] = choice('warn_overwrite', ['yes', 'no'])
116+
CONFIG['opt_home'] = path_option('home', check_exists=True, envkey='PYTHON_JULIACALL_BINDIR')[0]
117+
CONFIG['opt_check_bounds'] = choice('check_bounds', ['yes', 'no', 'auto'])[0]
118+
CONFIG['opt_compile'] = choice('compile', ['yes', 'no', 'all', 'min'])[0]
119+
CONFIG['opt_compiled_modules'] = choice('compiled_modules', ['yes', 'no'])[0]
120+
CONFIG['opt_depwarn'] = choice('depwarn', ['yes', 'no', 'error'])[0]
121+
CONFIG['opt_inline'] = choice('inline', ['yes', 'no'])[0]
122+
CONFIG['opt_min_optlevel'] = choice('min_optlevel', ['0', '1', '2', '3'])[0]
123+
CONFIG['opt_optimize'] = choice('optimize', ['0', '1', '2', '3'])[0]
124+
CONFIG['opt_procs'] = int_option('procs', accept_auto=True)[0]
125+
CONFIG['opt_sysimage'] = path_option('sysimage', check_exists=True)[0]
126+
CONFIG['opt_threads'] = int_option('threads', accept_auto=True)[0]
127+
CONFIG['opt_warn_overwrite'] = choice('warn_overwrite', ['yes', 'no'])[0]
130128

131129
# Stop if we already initialised
132130
if CONFIG['inited']:
@@ -155,7 +153,8 @@ def args_from_config():
155153
lib.jl_init__threading.argtypes = []
156154
lib.jl_init__threading.restype = None
157155
argc, argv = args_from_config()
158-
lib.jl_parse_opts(pointer(argc), pointer(argv))
156+
lib.jl_parse_opts(c.pointer(argc), c.pointer(argv))
157+
assert argc.value == 0
159158
lib.jl_init__threading()
160159
lib.jl_eval_string.argtypes = [c.c_char_p]
161160
lib.jl_eval_string.restype = c.c_void_p

0 commit comments

Comments
 (0)