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 CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.62.10'
16
- __version_tuple__ = version_tuple = (0, 62, 10)
15
+ __version__ = version = '2.18.0'
16
+ __version_tuple__ = version_tuple = (2, 18, 0)
@@ -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
- # qpretrieve defines the keyword argument `filter_size_interpretation`
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
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
- from . import rsetup, wrapr # noqa: F401
3
- from .wrapr import Rlme4, bootstrapped_median_distributions # noqa: F401
4
- from .rsetup import ( # noqa: F401
5
- set_r_lib_path, get_r_path, get_r_version, require_lme4, set_r_path)
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
- logger = logging.getLogger(__name__)
5
+ from .rlibs import (
6
+ RUnavailableError, rpy2, rpy2_is_version_3, import_r_submodules)
8
7
 
9
- _has_lme4 = None
10
- _has_r = None
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
- def get_r_path():
23
- """Return the path of the R executable"""
24
- # Maybe the user set the executable already?
25
- r_exec = os.environ.get("R_EXEC")
26
- if r_exec is not None:
27
- r_exec = pathlib.Path(r_exec)
28
- if r_exec.is_file():
29
- return r_exec
30
-
31
- # Try to get the executable using which
32
- r_exec = shutil.which("R")
33
- if r_exec is not None:
34
- r_exec = pathlib.Path(r_exec)
35
- return r_exec
36
-
37
- # Try to determine the path to the executable from R_HOME
38
- r_home = os.environ.get("R_HOME")
39
- if r_home and not pathlib.Path(r_home).is_dir():
40
- logger.warning(f"R_HOME Directory does not exist: {r_home}")
41
- r_home = None
42
-
43
- if r_home is None:
44
- raise RNotFoundError(
45
- "Cannot find R, please set the `R_HOME` environment variable "
46
- "or use `set_r_path`.")
47
-
48
- r_home = pathlib.Path(r_home)
49
-
50
- # search for the R executable
51
- for rr in [
52
- r_home / "bin" / "R",
53
- r_home / "bin" / "x64" / "R",
54
- ]:
55
- if rr.is_file():
56
- return rr
57
- rr_win = rr.with_name("R.exe")
58
- if rr_win.is_file():
59
- return rr_win
60
- else:
61
- raise RNotFoundError(
62
- f"Could not find R binary in '{r_home}'")
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 get_r_script_path():
66
- """Return the path to the Rscript executable"""
67
- return get_r_path().with_name("Rscript")
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
- """Return the full R version string"""
72
- require_r()
73
- cmd = (str(get_r_path()), "--version")
74
- logger.debug(f"Looking for R version with: {' '.join(cmd)}")
75
- r_version = run_command(
76
- cmd,
77
- env={"R_LIBS_USER": os.environ.get("R_LIBS_USER", "")},
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
- global _has_lme4
94
- if _has_lme4:
95
- return True
96
- require_r()
97
- for pkg in ["lme4", "statmod", "nloptr"]:
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 = get_r_path().is_file()
117
- except RNotFoundError:
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 require_lme4():
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` from the http://cran.rstudio.org mirror.
163
+ given in :const:`lib_path`.
130
164
  """
131
- install_command = ("install.packages("
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
- run_command(cmd=(get_r_path(), "-e", install_command),
139
- env={"R_LIBS_USER": os.environ.get("R_LIBS_USER", "")},
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 require_r():
144
- """Make sure R is installed an R HOME is set"""
145
- if not has_r():
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
- kwargs.setdefault("text", True)
167
- kwargs.setdefault("stderr", sp.STDOUT)
168
- if env is not None:
169
- if "env" in kwargs:
170
- env.update(kwargs.pop("env"))
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("WARNING"):
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
- os.environ["R_EXEC"] = str(pathlib.Path(r_path).resolve())
207
+ import_r_submodules()