dclab 0.62.10__cp313-cp313-macosx_10_13_x86_64.whl → 2.18.0__cp313-cp313-macosx_10_13_x86_64.whl
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.
Potentially problematic release.
This version of dclab might be problematic. Click here for more details.
- dclab/_version.py +2 -2
- dclab/definitions/meta_const.py +1 -11
- dclab/downsampling.cpython-313-darwin.so +0 -0
- dclab/external/skimage/_find_contours_cy.cpython-313-darwin.so +0 -0
- dclab/external/skimage/_pnpoly.cpython-313-darwin.so +0 -0
- dclab/external/skimage/_shared/geometry.cpython-313-darwin.so +0 -0
- dclab/http_utils.py +2 -12
- dclab/lme4/__init__.py +4 -4
- dclab/lme4/rlibs.py +93 -0
- dclab/lme4/rsetup.py +153 -150
- dclab/lme4/wrapr.py +129 -93
- dclab/rtdc_dataset/check.py +6 -74
- dclab/rtdc_dataset/copier.py +19 -73
- dclab/rtdc_dataset/core.py +2 -12
- dclab/rtdc_dataset/export.py +12 -16
- dclab/rtdc_dataset/feat_basin.py +3 -30
- dclab/rtdc_dataset/fmt_hdf5/base.py +2 -7
- dclab/rtdc_dataset/fmt_hdf5/events.py +3 -3
- dclab/rtdc_dataset/fmt_hierarchy/base.py +1 -0
- dclab/rtdc_dataset/fmt_hierarchy/events.py +3 -4
- dclab/rtdc_dataset/linker.py +124 -0
- dclab/rtdc_dataset/writer.py +2 -2
- dclab/util.py +0 -6
- {dclab-0.62.10.dist-info → dclab-2.18.0.dist-info}/METADATA +4 -2
- {dclab-0.62.10.dist-info → dclab-2.18.0.dist-info}/RECORD +29 -28
- {dclab-0.62.10.dist-info → dclab-2.18.0.dist-info}/WHEEL +1 -1
- dclab/lme4/lme4_template.R +0 -94
- {dclab-0.62.10.dist-info → dclab-2.18.0.dist-info}/LICENSE +0 -0
- {dclab-0.62.10.dist-info → dclab-2.18.0.dist-info}/entry_points.txt +0 -0
- {dclab-0.62.10.dist-info → dclab-2.18.0.dist-info}/top_level.txt +0 -0
dclab/_version.py
CHANGED
dclab/definitions/meta_const.py
CHANGED
|
@@ -161,17 +161,7 @@ CFG_METADATA = {
|
|
|
161
161
|
["subtract mean", fbool, "Subtract mean before processing"],
|
|
162
162
|
# pipeline_kws
|
|
163
163
|
["filter name", str, "Fourier filter used"],
|
|
164
|
-
#
|
|
165
|
-
# for determining the filter size in Fourier space. In DC, we
|
|
166
|
-
# need a well-defined value for the filter size. The most logical
|
|
167
|
-
# choice is to interpret the filter size as "frequency index", which
|
|
168
|
-
# is independent of the image shape and yields a good approximation
|
|
169
|
-
# of the actual resolution one can expect. The default value
|
|
170
|
-
# ("sideband distance") is a good choice for general QPI analysis,
|
|
171
|
-
# but there is no meaningful information one could extract from it
|
|
172
|
-
# by just looking at the number. Thus, the "filter size" that we
|
|
173
|
-
# see here corresponds to a filter size set in qpretrieve where
|
|
174
|
-
# `filter_size_interpretation="frequency index"`.
|
|
164
|
+
# Corresponds to `filter_size_interpretation="frequency index"`
|
|
175
165
|
["filter size", float, "Fourier filter size [1/pix]"],
|
|
176
166
|
["scale to filter", fboolorfloat, "Scale QPI data to filter size"],
|
|
177
167
|
# x, y coordinates, don't set if you wish None to be the default
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
dclab/http_utils.py
CHANGED
|
@@ -27,14 +27,6 @@ REGEXP_HTTP_URL = re.compile(
|
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
class ETagNotInResponseHeaderWarning(UserWarning):
|
|
31
|
-
"""Used for cases where the requests.Response does not contain an ETag"""
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class ConnectionTimeoutWarning(UserWarning):
|
|
35
|
-
"""Used when a connection fails or times out"""
|
|
36
|
-
|
|
37
|
-
|
|
38
30
|
class HTTPFile(io.IOBase):
|
|
39
31
|
def __init__(self, url, chunk_size=2**18, keep_chunks=200):
|
|
40
32
|
"""Chunk-cached access to a URL supporting range requests
|
|
@@ -86,8 +78,7 @@ class HTTPFile(io.IOBase):
|
|
|
86
78
|
etag = resp.headers.get("etag", "").strip("'").strip('"')
|
|
87
79
|
if len(etag) < 5:
|
|
88
80
|
etag = None
|
|
89
|
-
warnings.warn(f"Got empty ETag header for {self.url}"
|
|
90
|
-
ETagNotInResponseHeaderWarning)
|
|
81
|
+
warnings.warn(f"Got empty ETag header for {self.url}")
|
|
91
82
|
self._etag = etag
|
|
92
83
|
|
|
93
84
|
@property
|
|
@@ -247,8 +238,7 @@ class ResoluteRequestsSession(requests.Session):
|
|
|
247
238
|
requests.exceptions.ConnectTimeout,
|
|
248
239
|
requests.urllib3.exceptions.ConnectionError,
|
|
249
240
|
requests.urllib3.exceptions.ReadTimeoutError) as e:
|
|
250
|
-
warnings.warn(f"Encountered {e} for {args} {kwargs}"
|
|
251
|
-
ConnectionTimeoutWarning)
|
|
241
|
+
warnings.warn(f"Encountered {e} for {args} {kwargs}")
|
|
252
242
|
continue
|
|
253
243
|
else:
|
|
254
244
|
break
|
dclab/lme4/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""A wrapper around R with the lme4 package"""
|
|
2
|
-
|
|
3
|
-
from .
|
|
4
|
-
from .
|
|
5
|
-
|
|
2
|
+
# flake8: noqa: F401
|
|
3
|
+
from . import rlibs, rsetup, wrapr
|
|
4
|
+
from .wrapr import Rlme4, bootstrapped_median_distributions
|
|
5
|
+
from .rsetup import get_r_path, get_r_version, install_lme4, set_r_path
|
dclab/lme4/rlibs.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import os
|
|
3
|
+
import warnings
|
|
4
|
+
|
|
5
|
+
from ..external.packaging import parse as parse_version
|
|
6
|
+
|
|
7
|
+
#: Minimum R version
|
|
8
|
+
#: This is actually a dependency for rpy2, because the API changed then
|
|
9
|
+
#: (ffi.error: symbol 'R_tryCatchError' not found in library).
|
|
10
|
+
R_MIN_VERSION = "3.6.0"
|
|
11
|
+
|
|
12
|
+
#: Minimum rpy2 version
|
|
13
|
+
RPY2_MIN_VERSION = "2.9.4"
|
|
14
|
+
|
|
15
|
+
R_SUBMODULES = [
|
|
16
|
+
"rpy2.robjects.packages",
|
|
17
|
+
"rpy2.situation",
|
|
18
|
+
"rpy2.robjects.vectors",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
R_SUBMODULES_3 = [
|
|
22
|
+
"rpy2.rinterface_lib.callbacks",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class RPY2UnavailableError(BaseException):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class RPY2ImportError(RPY2UnavailableError):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class RPY2OutdatedError(RPY2UnavailableError):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class RUnavailableError(BaseException):
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class ROutdatedError(RUnavailableError):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class MockRPackage:
|
|
47
|
+
def __init__(self, exception):
|
|
48
|
+
self.exception = exception
|
|
49
|
+
|
|
50
|
+
def __getattr__(self, item):
|
|
51
|
+
raise self.exception
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def import_r_submodules():
|
|
55
|
+
importlib.import_module("rpy2.situation")
|
|
56
|
+
r_home = rpy2.situation.get_r_home()
|
|
57
|
+
if r_home is not None:
|
|
58
|
+
if os.environ.get("R_HOME", None) is None:
|
|
59
|
+
# set R_HOME globally (https://github.com/rpy2/rpy2/issues/796)
|
|
60
|
+
os.environ["R_HOME"] = r_home
|
|
61
|
+
if rpy2_is_version_3:
|
|
62
|
+
mods = R_SUBMODULES + R_SUBMODULES_3
|
|
63
|
+
else:
|
|
64
|
+
mods = R_SUBMODULES
|
|
65
|
+
try:
|
|
66
|
+
for sm in mods:
|
|
67
|
+
importlib.import_module(sm)
|
|
68
|
+
except rpy2.rinterface_lib.openrlib.ffi.error as exc:
|
|
69
|
+
# This error happens when the installed R version is too old:
|
|
70
|
+
# "ffi.error: symbol 'R_tryCatchError' not found in library"
|
|
71
|
+
raise ROutdatedError(
|
|
72
|
+
f"Encountered '{exc.__class__.__name__}: {exc}'. "
|
|
73
|
+
f"Please make sure you have 'R>={R_MIN_VERSION}'!")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
rpy2 = importlib.import_module("rpy2")
|
|
78
|
+
if parse_version(rpy2.__version__) < parse_version(RPY2_MIN_VERSION):
|
|
79
|
+
raise RPY2OutdatedError(f"Please install 'rpy2>={RPY2_MIN_VERSION}'!")
|
|
80
|
+
except ImportError:
|
|
81
|
+
rpy2 = MockRPackage(
|
|
82
|
+
RPY2ImportError(f"Please install 'rpy2>={RPY2_MIN_VERSION}'!"))
|
|
83
|
+
rpy2_is_version_3 = False
|
|
84
|
+
except BaseException as e:
|
|
85
|
+
rpy2 = MockRPackage(e)
|
|
86
|
+
rpy2_is_version_3 = False
|
|
87
|
+
else:
|
|
88
|
+
rpy2_is_version_3 = parse_version(rpy2.__version__) >= parse_version("3.0")
|
|
89
|
+
try:
|
|
90
|
+
import_r_submodules()
|
|
91
|
+
except RUnavailableError as e:
|
|
92
|
+
warnings.warn("There is an issue with the linked R version: "
|
|
93
|
+
+ f"{e.__class__.__name__}: {e}")
|
dclab/lme4/rsetup.py
CHANGED
|
@@ -1,156 +1,185 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
|
-
import pathlib
|
|
4
|
-
import shutil
|
|
5
3
|
import subprocess as sp
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
from .rlibs import (
|
|
6
|
+
RUnavailableError, rpy2, rpy2_is_version_3, import_r_submodules)
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class CommandFailedError(BaseException):
|
|
14
|
-
"""Used when `run_command` encounters an error"""
|
|
15
|
-
pass
|
|
8
|
+
# Disable rpy2 logger because of unnecessary prints to stdout
|
|
9
|
+
logging.getLogger("rpy2.rinterface_lib.callbacks").disabled = True
|
|
16
10
|
|
|
17
11
|
|
|
18
12
|
class RNotFoundError(BaseException):
|
|
19
13
|
pass
|
|
20
14
|
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
16
|
+
class AutoRConsole(object):
|
|
17
|
+
"""Helper class for catching R console output"""
|
|
18
|
+
lock = False
|
|
19
|
+
perform_lock = rpy2_is_version_3
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
"""
|
|
23
|
+
By default, this console always returns "yes" when asked a
|
|
24
|
+
question. If you need something different, you can subclass
|
|
25
|
+
and override `consoleread` fucntion. The console stream is
|
|
26
|
+
recorded in `self.stream`.
|
|
27
|
+
"""
|
|
28
|
+
self.stream = [["init", "Starting RConsole class\n"]]
|
|
29
|
+
if AutoRConsole.perform_lock:
|
|
30
|
+
if AutoRConsole.lock:
|
|
31
|
+
raise ValueError("Only one RConsole instance allowed!")
|
|
32
|
+
AutoRConsole.lock = True
|
|
33
|
+
self.original_funcs = {
|
|
34
|
+
"consoleread": rpy2.rinterface_lib.callbacks.consoleread,
|
|
35
|
+
"consolewrite_print":
|
|
36
|
+
rpy2.rinterface_lib.callbacks.consolewrite_print,
|
|
37
|
+
"consolewrite_warnerror":
|
|
38
|
+
rpy2.rinterface_lib.callbacks.consolewrite_warnerror,
|
|
39
|
+
}
|
|
40
|
+
rpy2.rinterface_lib.callbacks.consoleread = self.consoleread
|
|
41
|
+
rpy2.rinterface_lib.callbacks.consolewrite_print = \
|
|
42
|
+
self.consolewrite_print
|
|
43
|
+
rpy2.rinterface_lib.callbacks.showmessage = \
|
|
44
|
+
self.consolewrite_print
|
|
45
|
+
|
|
46
|
+
rpy2.rinterface_lib.callbacks.consolewrite_warnerror = \
|
|
47
|
+
self.consolewrite_warnerror
|
|
48
|
+
# Set locale (to get always English messages)
|
|
49
|
+
rpy2.robjects.r('Sys.setlocale("LC_MESSAGES", "C")')
|
|
50
|
+
rpy2.robjects.r('Sys.setlocale("LC_CTYPE", "C")')
|
|
51
|
+
|
|
52
|
+
def __enter__(self):
|
|
53
|
+
return self
|
|
54
|
+
|
|
55
|
+
def __exit__(self, *args):
|
|
56
|
+
if AutoRConsole.perform_lock:
|
|
57
|
+
AutoRConsole.lock = False
|
|
58
|
+
rpy2.rinterface_lib.callbacks.consoleread = \
|
|
59
|
+
self.original_funcs["consoleread"]
|
|
60
|
+
rpy2.rinterface_lib.callbacks.consolewrite_print = \
|
|
61
|
+
self.original_funcs["consolewrite_print"]
|
|
62
|
+
rpy2.rinterface_lib.callbacks.consolewrite_warnerror = \
|
|
63
|
+
self.original_funcs["consolewrite_warnerror"]
|
|
64
|
+
|
|
65
|
+
def close(self):
|
|
66
|
+
"""Remove the rpy2 monkeypatches"""
|
|
67
|
+
self.__exit__()
|
|
68
|
+
|
|
69
|
+
def consoleread(self, prompt):
|
|
70
|
+
"""Read user input, returns "yes" by default"""
|
|
71
|
+
self.write_to_stream("consoleread", prompt + "YES")
|
|
72
|
+
return "yes"
|
|
73
|
+
|
|
74
|
+
def consolewrite_print(self, s):
|
|
75
|
+
self.write_to_stream("consolewrite_print", s)
|
|
76
|
+
|
|
77
|
+
def consolewrite_warnerror(self, s):
|
|
78
|
+
self.write_to_stream("consolewrite_warnerror", s)
|
|
79
|
+
|
|
80
|
+
def write_to_stream(self, topic, s):
|
|
81
|
+
prev_topic = self.stream[-1][0]
|
|
82
|
+
same_topic = prev_topic == topic
|
|
83
|
+
unfinished_line = self.stream[-1][1][-1] not in ["\n", "\r"]
|
|
84
|
+
if same_topic and unfinished_line:
|
|
85
|
+
# append to previous line
|
|
86
|
+
self.stream[-1][1] += s
|
|
87
|
+
else:
|
|
88
|
+
self.stream.append([topic, s])
|
|
89
|
+
|
|
90
|
+
def get_prints(self):
|
|
91
|
+
prints = []
|
|
92
|
+
for line in self.stream:
|
|
93
|
+
if line[0] == "consolewrite_print":
|
|
94
|
+
prints.append(line[1].strip())
|
|
95
|
+
return prints
|
|
96
|
+
|
|
97
|
+
def get_warnerrors(self):
|
|
98
|
+
warnerrors = []
|
|
99
|
+
for line in self.stream:
|
|
100
|
+
if line[0] == "consolewrite_warnerror":
|
|
101
|
+
warnerrors.append(line[1].strip())
|
|
102
|
+
return warnerrors
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def check_r():
|
|
106
|
+
"""Make sure R is installed an R HOME is set"""
|
|
107
|
+
if not has_r():
|
|
108
|
+
raise RNotFoundError("Cannot find R, please set its path with the "
|
|
109
|
+
+ "`set_r_path` function.")
|
|
63
110
|
|
|
64
111
|
|
|
65
|
-
def
|
|
66
|
-
"""
|
|
67
|
-
|
|
112
|
+
def get_r_path():
|
|
113
|
+
"""Get the path of the R executable/binary from rpy2"""
|
|
114
|
+
r_home = rpy2.situation.get_r_home()
|
|
115
|
+
return rpy2.situation.get_r_exec(r_home)
|
|
68
116
|
|
|
69
117
|
|
|
70
118
|
def get_r_version():
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
79
|
-
r_version = r_version.split(os.linesep)
|
|
80
|
-
if r_version[0].startswith("WARNING"):
|
|
81
|
-
r_version = r_version[1]
|
|
82
|
-
else:
|
|
83
|
-
r_version = r_version[0]
|
|
84
|
-
logger.info(f"R version found: {r_version}")
|
|
85
|
-
# get the actual version string
|
|
86
|
-
if r_version.startswith("R version "):
|
|
87
|
-
r_version = r_version.split(" ", 2)[2]
|
|
88
|
-
return r_version.strip()
|
|
119
|
+
check_r()
|
|
120
|
+
ver_string = rpy2.situation.r_version_from_subprocess().strip()
|
|
121
|
+
if ver_string:
|
|
122
|
+
# get the actual version string
|
|
123
|
+
if ver_string.startswith("R version "):
|
|
124
|
+
ver_string = ver_string.split(" ")[2]
|
|
125
|
+
return ver_string
|
|
89
126
|
|
|
90
127
|
|
|
91
128
|
def has_lme4():
|
|
92
129
|
"""Return True if the lme4 package is installed"""
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
res = run_command(
|
|
99
|
-
(str(get_r_path()), "-q", "-e", f"system.file(package='{pkg}')"),
|
|
100
|
-
env={"R_LIBS_USER": os.environ.get("R_LIBS_USER", "")},
|
|
101
|
-
)
|
|
102
|
-
if not res.split("[1]")[1].count(pkg):
|
|
103
|
-
avail = False
|
|
104
|
-
break
|
|
105
|
-
else:
|
|
106
|
-
avail = _has_lme4 = True
|
|
107
|
-
return avail
|
|
130
|
+
check_r()
|
|
131
|
+
lme4_there = rpy2.robjects.packages.isinstalled("lme4")
|
|
132
|
+
statmod_there = rpy2.robjects.packages.isinstalled("statmod")
|
|
133
|
+
nloptr_there = rpy2.robjects.packages.isinstalled("nloptr")
|
|
134
|
+
return lme4_there and statmod_there and nloptr_there
|
|
108
135
|
|
|
109
136
|
|
|
110
137
|
def has_r():
|
|
111
138
|
"""Return True if R is available"""
|
|
112
|
-
global _has_r
|
|
113
|
-
if _has_r:
|
|
114
|
-
return True
|
|
115
139
|
try:
|
|
116
|
-
hasr =
|
|
117
|
-
except
|
|
140
|
+
hasr = rpy2.situation.get_r_home() is not None
|
|
141
|
+
except RUnavailableError:
|
|
118
142
|
hasr = False
|
|
119
|
-
if hasr:
|
|
120
|
-
_has_r = True
|
|
121
143
|
return hasr
|
|
122
144
|
|
|
123
145
|
|
|
124
|
-
def
|
|
146
|
+
def import_lme4():
|
|
147
|
+
check_r()
|
|
148
|
+
if has_lme4():
|
|
149
|
+
lme4pkg = rpy2.robjects.packages.importr("lme4")
|
|
150
|
+
else:
|
|
151
|
+
raise ValueError(
|
|
152
|
+
"The R package 'lme4' is not installed, please install it via "
|
|
153
|
+
+ "`dclab.lme4.rsetup.install_lme4()` or by executing "
|
|
154
|
+
+ "in a shell: R -e " + '"install.packages(' + "'lme4', "
|
|
155
|
+
+ "repos='http://cran.rstudio.org')" + '"')
|
|
156
|
+
return lme4pkg
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def install_lme4():
|
|
125
160
|
"""Install the lme4 package (if not already installed)
|
|
126
161
|
|
|
127
|
-
Besides ``lme4``, this also installs ``nloptr`` and ``statmod``.
|
|
128
162
|
The packages are installed to the user data directory
|
|
129
|
-
given in :const:`lib_path
|
|
163
|
+
given in :const:`lib_path`.
|
|
130
164
|
"""
|
|
131
|
-
|
|
132
|
-
"c('statmod','nloptr','lme4'),"
|
|
133
|
-
"repos='http://cran.rstudio.org'"
|
|
134
|
-
")"
|
|
135
|
-
)
|
|
136
|
-
require_r()
|
|
165
|
+
check_r()
|
|
137
166
|
if not has_lme4():
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
167
|
+
# import R's utility package
|
|
168
|
+
utils = rpy2.robjects.packages.importr('utils')
|
|
169
|
+
# select the first mirror in the list
|
|
170
|
+
utils.chooseCRANmirror(ind=1)
|
|
171
|
+
# install lme4 to user data directory (say yes to user dir install)
|
|
172
|
+
with AutoRConsole() as rc:
|
|
173
|
+
# install statmod and nloptr first
|
|
174
|
+
# (Doesn't R have package dependencies?!)
|
|
175
|
+
utils.install_packages(
|
|
176
|
+
rpy2.robjects.vectors.StrVector(["statmod", "nloptr", "lme4"]))
|
|
177
|
+
return rc
|
|
141
178
|
|
|
142
179
|
|
|
143
|
-
def
|
|
144
|
-
"""
|
|
145
|
-
if
|
|
146
|
-
raise RNotFoundError("Cannot find R, please set its path with the "
|
|
147
|
-
"`set_r_path` function or set the `RHOME` "
|
|
148
|
-
"environment variable.")
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def run_command(cmd, **kwargs):
|
|
152
|
-
"""Run a command via subprocess"""
|
|
153
|
-
if hasattr(sp, "STARTUPINFO"):
|
|
180
|
+
def set_r_path(r_path):
|
|
181
|
+
"""Set the path of the R executable/binary for rpy2"""
|
|
182
|
+
if hasattr(sp, 'STARTUPINFO'):
|
|
154
183
|
# On Windows, subprocess calls will pop up a command window by
|
|
155
184
|
# default when run from Pyinstaller with the ``--noconsole``
|
|
156
185
|
# option. Avoid this distraction.
|
|
@@ -163,42 +192,16 @@ def run_command(cmd, **kwargs):
|
|
|
163
192
|
si = None
|
|
164
193
|
env = None
|
|
165
194
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
kwargs["env"] = env
|
|
172
|
-
kwargs["startupinfo"] = si
|
|
173
|
-
|
|
174
|
-
# Convert paths to strings
|
|
175
|
-
cmd = [str(cc) for cc in cmd]
|
|
176
|
-
|
|
177
|
-
try:
|
|
178
|
-
tmp = sp.check_output(cmd, **kwargs)
|
|
179
|
-
except sp.CalledProcessError as e:
|
|
180
|
-
raise CommandFailedError(f"The command '{' '.join(cmd)}' failed with "
|
|
181
|
-
f"exit code {e.returncode}: {e.output}")
|
|
182
|
-
|
|
183
|
-
return tmp.strip()
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
def set_r_lib_path(r_lib_path):
|
|
187
|
-
"""Add given directory to the R_LIBS_USER environment variable"""
|
|
188
|
-
paths = os.environ.get("R_LIBS_USER", "").split(os.pathsep)
|
|
189
|
-
paths = [p for p in paths if p]
|
|
190
|
-
paths.append(str(r_lib_path).strip())
|
|
191
|
-
os.environ["R_LIBS_USER"] = os.pathsep.join(list(set(paths)))
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
def set_r_path(r_path):
|
|
195
|
-
"""Set the path of the R executable/binary"""
|
|
196
|
-
tmp = run_command((str(r_path), "RHOME"))
|
|
195
|
+
tmp = sp.check_output((r_path, 'RHOME'),
|
|
196
|
+
startupinfo=si,
|
|
197
|
+
env=env,
|
|
198
|
+
text=True,
|
|
199
|
+
)
|
|
197
200
|
|
|
198
201
|
r_home = tmp.split(os.linesep)
|
|
199
|
-
if r_home[0].startswith(
|
|
202
|
+
if r_home[0].startswith('WARNING'):
|
|
200
203
|
res = r_home[1]
|
|
201
204
|
else:
|
|
202
205
|
res = r_home[0].strip()
|
|
203
206
|
os.environ["R_HOME"] = res
|
|
204
|
-
|
|
207
|
+
import_r_submodules()
|