rpy-bridge 0.3.4__py3-none-any.whl → 0.3.6__py3-none-any.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.
- rpy_bridge/rpy2_utils.py +271 -50
- {rpy_bridge-0.3.4.dist-info → rpy_bridge-0.3.6.dist-info}/METADATA +4 -4
- rpy_bridge-0.3.6.dist-info/RECORD +8 -0
- rpy_bridge-0.3.4.dist-info/RECORD +0 -8
- {rpy_bridge-0.3.4.dist-info → rpy_bridge-0.3.6.dist-info}/WHEEL +0 -0
- {rpy_bridge-0.3.4.dist-info → rpy_bridge-0.3.6.dist-info}/licenses/LICENSE +0 -0
- {rpy_bridge-0.3.4.dist-info → rpy_bridge-0.3.6.dist-info}/top_level.txt +0 -0
rpy_bridge/rpy2_utils.py
CHANGED
|
@@ -29,7 +29,7 @@ import subprocess
|
|
|
29
29
|
import sys
|
|
30
30
|
import warnings
|
|
31
31
|
from pathlib import Path
|
|
32
|
-
from typing import TYPE_CHECKING, Any, Union
|
|
32
|
+
from typing import TYPE_CHECKING, Any, Iterable, Union
|
|
33
33
|
|
|
34
34
|
import numpy as np
|
|
35
35
|
import pandas as pd
|
|
@@ -58,6 +58,47 @@ except ImportError:
|
|
|
58
58
|
logger = logging.getLogger("rpy-bridge")
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
# --- Remove default handler to override global default ---
|
|
62
|
+
logger.remove()
|
|
63
|
+
|
|
64
|
+
# --- Add a "sink" for RFunctionCaller logs ---
|
|
65
|
+
_rfc_logger = logger.bind(tag="[RFunctionCaller]")
|
|
66
|
+
_rfc_logger.add(
|
|
67
|
+
sys.stderr,
|
|
68
|
+
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}", # Only show message
|
|
69
|
+
level="INFO",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _log_r_call(func_name: str, source_info: str):
|
|
74
|
+
"""
|
|
75
|
+
Log an R function call, showing only '[RFunctionCaller] Called ...'
|
|
76
|
+
"""
|
|
77
|
+
_rfc_logger.opt(depth=1, record=False).info(
|
|
78
|
+
"[rpy-bridge.RFunctionCaller] Called R function '{}' from {}",
|
|
79
|
+
func_name,
|
|
80
|
+
source_info,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# ---------------------------------------------------------------------
|
|
85
|
+
# Path resolution
|
|
86
|
+
# ---------------------------------------------------------------------
|
|
87
|
+
def _normalize_scripts(
|
|
88
|
+
scripts: Union[str, Path, Iterable[Union[str, Path]], None],
|
|
89
|
+
) -> list[Path]:
|
|
90
|
+
if scripts is None:
|
|
91
|
+
return []
|
|
92
|
+
if isinstance(scripts, (str, Path)):
|
|
93
|
+
return [Path(scripts).resolve()]
|
|
94
|
+
try:
|
|
95
|
+
return [Path(s).resolve() for s in scripts]
|
|
96
|
+
except TypeError:
|
|
97
|
+
raise TypeError(
|
|
98
|
+
f"Invalid type for 'scripts': {type(scripts)}. Must be str, Path, or list/iterable thereof."
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
61
102
|
# ---------------------------------------------------------------------
|
|
62
103
|
# R detection and rpy2 installation
|
|
63
104
|
# ---------------------------------------------------------------------
|
|
@@ -104,31 +145,49 @@ def find_r_home() -> str | None:
|
|
|
104
145
|
return None
|
|
105
146
|
|
|
106
147
|
|
|
107
|
-
if
|
|
148
|
+
# Determine if we're running in CI / testing
|
|
149
|
+
CI_TESTING = (
|
|
150
|
+
os.environ.get("GITHUB_ACTIONS") == "true" or os.environ.get("TESTING") == "1"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
R_HOME = os.environ.get("R_HOME")
|
|
154
|
+
if not R_HOME:
|
|
108
155
|
R_HOME = find_r_home()
|
|
109
156
|
if not R_HOME:
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
157
|
+
if CI_TESTING:
|
|
158
|
+
logger.warning(
|
|
159
|
+
"R not found; skipping all R-dependent setup in CI/testing environment."
|
|
160
|
+
)
|
|
161
|
+
R_HOME = None # Explicitly None to signal "no R available"
|
|
162
|
+
else:
|
|
163
|
+
raise RuntimeError("R not found. Please install R or add it to PATH.")
|
|
164
|
+
else:
|
|
165
|
+
os.environ["R_HOME"] = R_HOME
|
|
166
|
+
|
|
167
|
+
logger.info(
|
|
168
|
+
f"[rpy-bridge] R_HOME = {R_HOME if R_HOME else 'not detected; R-dependent code skipped'}"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Only configure platform-specific library paths if R is available
|
|
172
|
+
if R_HOME:
|
|
173
|
+
if sys.platform == "darwin":
|
|
174
|
+
lib_path = os.path.join(R_HOME, "lib")
|
|
175
|
+
if lib_path not in os.environ.get("DYLD_FALLBACK_LIBRARY_PATH", ""):
|
|
176
|
+
os.environ["DYLD_FALLBACK_LIBRARY_PATH"] = (
|
|
177
|
+
f"{lib_path}:{os.environ.get('DYLD_FALLBACK_LIBRARY_PATH','')}"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
elif sys.platform.startswith("linux"):
|
|
181
|
+
lib_path = os.path.join(R_HOME, "lib")
|
|
182
|
+
ld_path = os.environ.get("LD_LIBRARY_PATH", "")
|
|
183
|
+
if lib_path not in ld_path.split(":"):
|
|
184
|
+
os.environ["LD_LIBRARY_PATH"] = f"{lib_path}:{ld_path}"
|
|
126
185
|
|
|
127
|
-
elif sys.platform.startswith("
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
186
|
+
elif sys.platform.startswith("win"):
|
|
187
|
+
bin_path = os.path.join(R_HOME, "bin", "x64")
|
|
188
|
+
path_env = os.environ.get("PATH", "")
|
|
189
|
+
if bin_path not in path_env.split(os.pathsep):
|
|
190
|
+
os.environ["PATH"] = f"{bin_path}{os.pathsep}{path_env}"
|
|
132
191
|
|
|
133
192
|
|
|
134
193
|
# ---------------------------------------------------------------------
|
|
@@ -212,24 +271,24 @@ def activate_renv(path_to_renv: Path) -> None:
|
|
|
212
271
|
renviron_file = project_dir / ".Renviron"
|
|
213
272
|
if renviron_file.is_file():
|
|
214
273
|
os.environ["R_ENVIRON_USER"] = str(renviron_file)
|
|
215
|
-
logger.info(f"R_ENVIRON_USER set to: {renviron_file}")
|
|
274
|
+
logger.info(f"[rpy-bridge] R_ENVIRON_USER set to: {renviron_file}")
|
|
216
275
|
|
|
217
276
|
rprofile_file = project_dir / ".Rprofile"
|
|
218
277
|
if rprofile_file.is_file():
|
|
219
278
|
robjects.r(f'source("{rprofile_file.as_posix()}")')
|
|
220
|
-
logger.info(f".Rprofile sourced: {rprofile_file}")
|
|
279
|
+
logger.info(f"[rpy-bridge] .Rprofile sourced: {rprofile_file}")
|
|
221
280
|
|
|
222
281
|
try:
|
|
223
282
|
robjects.r("suppressMessages(library(renv))")
|
|
224
283
|
except Exception:
|
|
225
|
-
logger.info("Installing renv package in project library...")
|
|
284
|
+
logger.info("[rpy-bridge] Installing renv package in project library...")
|
|
226
285
|
robjects.r(
|
|
227
286
|
f'install.packages("renv", repos="https://cloud.r-project.org", lib="{renv_dir / "library"}")'
|
|
228
287
|
)
|
|
229
288
|
robjects.r("library(renv)")
|
|
230
289
|
|
|
231
290
|
robjects.r(f'renv::load("{project_dir.as_posix()}")')
|
|
232
|
-
logger.info(f"renv environment loaded for project: {project_dir}")
|
|
291
|
+
logger.info(f"[rpy-bridge] renv environment loaded for project: {project_dir}")
|
|
233
292
|
|
|
234
293
|
|
|
235
294
|
# ---------------------------------------------------------------------
|
|
@@ -248,35 +307,54 @@ class NamespaceWrapper:
|
|
|
248
307
|
return self._env[func_name]
|
|
249
308
|
raise AttributeError(f"Function '{func_name}' not found in R namespace")
|
|
250
309
|
|
|
310
|
+
def list_functions(self):
|
|
311
|
+
"""
|
|
312
|
+
Return a list of callable functions in this namespace.
|
|
313
|
+
"""
|
|
314
|
+
return [k for k, v in self._env.items() if callable(v)]
|
|
315
|
+
|
|
251
316
|
|
|
252
317
|
# ---------------------------------------------------------------------
|
|
253
318
|
# RFunctionCaller
|
|
254
319
|
# ---------------------------------------------------------------------
|
|
255
320
|
class RFunctionCaller:
|
|
256
321
|
"""
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
scripts:
|
|
268
|
-
Path or list of Paths.
|
|
269
|
-
Each path may be:
|
|
270
|
-
- an R script (.R file)
|
|
271
|
-
- a directory containing R scripts (all *.R files are sourced)
|
|
272
|
-
- scripts in subdirectories are not automatically sourced
|
|
322
|
+
Primary interface for calling R functions from Python.
|
|
323
|
+
|
|
324
|
+
``RFunctionCaller`` loads one or more R scripts into isolated namespaces
|
|
325
|
+
and provides a unified ``call()`` method for executing:
|
|
326
|
+
|
|
327
|
+
* Functions defined in sourced R scripts
|
|
328
|
+
* Base R functions (e.g. ``sum``, ``mean``)
|
|
329
|
+
* Functions from installed R packages (via ``package::function``)
|
|
330
|
+
|
|
331
|
+
In most workflows, users only need to interact with this class.
|
|
273
332
|
|
|
333
|
+
Parameters
|
|
334
|
+
----------
|
|
335
|
+
path_to_renv : Path or None, optional
|
|
336
|
+
Path to an R project that uses ``renv``. This may be either the project
|
|
337
|
+
root or the ``renv/`` directory itself. If provided, the renv
|
|
338
|
+
environment is activated before any scripts are sourced.
|
|
339
|
+
|
|
340
|
+
scripts : str, Path, list[str | Path], or None, optional
|
|
341
|
+
One or more ``.R`` files or directories containing ``.R`` files.
|
|
342
|
+
Each script is sourced into its own namespace.
|
|
343
|
+
|
|
344
|
+
packages : str or list[str], optional
|
|
345
|
+
R packages to load (and install if missing) before calling functions.
|
|
346
|
+
|
|
347
|
+
Notes
|
|
348
|
+
-----
|
|
349
|
+
* Python objects are automatically converted to R objects.
|
|
350
|
+
* R return values are converted back to Python equivalents.
|
|
351
|
+
* Missing values (``None``, ``pd.NA``) are mapped to R ``NA``.
|
|
274
352
|
"""
|
|
275
353
|
|
|
276
354
|
def __init__(
|
|
277
355
|
self,
|
|
278
356
|
path_to_renv: Path | None = None,
|
|
279
|
-
scripts: Path | list[Path] | None = None,
|
|
357
|
+
scripts: str | Path | list[str | Path] | None = None,
|
|
280
358
|
packages: str | list[str] | None = None,
|
|
281
359
|
**kwargs, # catch unexpected keywords
|
|
282
360
|
):
|
|
@@ -297,6 +375,13 @@ class RFunctionCaller:
|
|
|
297
375
|
"'script_path' ignored because 'scripts' argument is also provided."
|
|
298
376
|
)
|
|
299
377
|
|
|
378
|
+
self.scripts = _normalize_scripts(scripts)
|
|
379
|
+
|
|
380
|
+
# --- Check all scripts exist immediately ---
|
|
381
|
+
for script_path in self.scripts:
|
|
382
|
+
if not script_path.exists():
|
|
383
|
+
raise FileNotFoundError(f"R script path not found: {script_path}")
|
|
384
|
+
|
|
300
385
|
# Raise error if other unexpected kwargs remain
|
|
301
386
|
if kwargs:
|
|
302
387
|
raise TypeError(
|
|
@@ -391,8 +476,10 @@ class RFunctionCaller:
|
|
|
391
476
|
|
|
392
477
|
for script_path in r_files:
|
|
393
478
|
ns_name = script_path.stem
|
|
394
|
-
logger.info(
|
|
395
|
-
|
|
479
|
+
logger.opt(depth=2).info(
|
|
480
|
+
"[rpy-bridge.RFunctionCaller] Loading R script '{}' as namespace '{}'",
|
|
481
|
+
script_path.name,
|
|
482
|
+
ns_name,
|
|
396
483
|
)
|
|
397
484
|
|
|
398
485
|
r("env <- new.env(parent=globalenv())")
|
|
@@ -415,7 +502,7 @@ class RFunctionCaller:
|
|
|
415
502
|
}
|
|
416
503
|
|
|
417
504
|
logger.info(
|
|
418
|
-
f"Registered {len(self._namespaces[ns_name])} functions in namespace '{ns_name}'"
|
|
505
|
+
f"[rpy-bridge.RFunctionCaller] Registered {len(self._namespaces[ns_name])} functions in namespace '{ns_name}'"
|
|
419
506
|
)
|
|
420
507
|
|
|
421
508
|
self._scripts_loaded[idx] = True
|
|
@@ -454,6 +541,105 @@ class RFunctionCaller:
|
|
|
454
541
|
|
|
455
542
|
return x
|
|
456
543
|
|
|
544
|
+
def list_namespaces(self) -> list[str]:
|
|
545
|
+
"""
|
|
546
|
+
Return the names of all loaded script namespaces.
|
|
547
|
+
|
|
548
|
+
Returns
|
|
549
|
+
-------
|
|
550
|
+
list[str]
|
|
551
|
+
Names of sourced R script namespaces.
|
|
552
|
+
"""
|
|
553
|
+
self._ensure_r_loaded()
|
|
554
|
+
return list(self._namespaces.keys())
|
|
555
|
+
|
|
556
|
+
def list_namespace_functions(self, namespace: str) -> list[str]:
|
|
557
|
+
"""
|
|
558
|
+
Return all callable functions in a specific namespace.
|
|
559
|
+
"""
|
|
560
|
+
self._ensure_r_loaded()
|
|
561
|
+
if namespace not in self._namespaces:
|
|
562
|
+
raise ValueError(f"Namespace '{namespace}' not found")
|
|
563
|
+
return [k for k, v in self._namespaces[namespace].items() if callable(v)]
|
|
564
|
+
|
|
565
|
+
def _get_package_functions(self, pkg: str) -> list[str]:
|
|
566
|
+
"""
|
|
567
|
+
Return a list of callable functions from a loaded R package.
|
|
568
|
+
"""
|
|
569
|
+
r = self.robjects.r
|
|
570
|
+
try:
|
|
571
|
+
all_objs = list(r[f'ls("package:{pkg}")'])
|
|
572
|
+
funcs = [
|
|
573
|
+
name
|
|
574
|
+
for name in all_objs
|
|
575
|
+
if r(f'is.function(get("{name}", envir=asNamespace("{pkg}")))')[0]
|
|
576
|
+
]
|
|
577
|
+
return funcs
|
|
578
|
+
except Exception:
|
|
579
|
+
logger.warning(f"Failed to list functions for package '{pkg}'")
|
|
580
|
+
return []
|
|
581
|
+
|
|
582
|
+
def list_all_functions(
|
|
583
|
+
self, include_packages: bool = False
|
|
584
|
+
) -> dict[str, list[str]]:
|
|
585
|
+
"""
|
|
586
|
+
Return all callable R functions grouped by script namespace and package.
|
|
587
|
+
"""
|
|
588
|
+
self._ensure_r_loaded()
|
|
589
|
+
all_funcs = {}
|
|
590
|
+
|
|
591
|
+
# --- Script namespaces ---
|
|
592
|
+
for ns_name, ns_env in self._namespaces.items():
|
|
593
|
+
funcs = [name for name, val in ns_env.items() if callable(val)]
|
|
594
|
+
all_funcs[ns_name] = funcs
|
|
595
|
+
|
|
596
|
+
# --- Loaded R packages ---
|
|
597
|
+
if include_packages:
|
|
598
|
+
r = self.robjects.r
|
|
599
|
+
try:
|
|
600
|
+
pkgs = r("loadedNamespaces()")
|
|
601
|
+
for pkg in pkgs:
|
|
602
|
+
funcs = self._get_package_functions(pkg)
|
|
603
|
+
if not funcs:
|
|
604
|
+
# Add a placeholder note
|
|
605
|
+
funcs = [
|
|
606
|
+
"[See official documentation for functions, datasets, and objects]"
|
|
607
|
+
]
|
|
608
|
+
all_funcs[pkg] = funcs
|
|
609
|
+
except Exception:
|
|
610
|
+
pass
|
|
611
|
+
|
|
612
|
+
return all_funcs
|
|
613
|
+
|
|
614
|
+
def print_function_tree(
|
|
615
|
+
self, include_packages: bool = False, max_display: int = 10
|
|
616
|
+
):
|
|
617
|
+
"""
|
|
618
|
+
Pretty-print available R functions grouped by namespace.
|
|
619
|
+
|
|
620
|
+
Parameters
|
|
621
|
+
----------
|
|
622
|
+
include_packages : bool, default False
|
|
623
|
+
Whether to include functions from loaded R packages.
|
|
624
|
+
|
|
625
|
+
max_display : int, default 10
|
|
626
|
+
Maximum number of functions displayed per namespace.
|
|
627
|
+
|
|
628
|
+
Notes
|
|
629
|
+
-----
|
|
630
|
+
This method is intended for interactive exploration and debugging.
|
|
631
|
+
"""
|
|
632
|
+
all_funcs = self.list_all_functions(include_packages=include_packages)
|
|
633
|
+
|
|
634
|
+
for ns_name, funcs in all_funcs.items():
|
|
635
|
+
if not funcs:
|
|
636
|
+
continue
|
|
637
|
+
print(f"{ns_name}/")
|
|
638
|
+
for f in sorted(funcs)[:max_display]:
|
|
639
|
+
print(f" {f}")
|
|
640
|
+
if len(funcs) > max_display:
|
|
641
|
+
print(" ...")
|
|
642
|
+
|
|
457
643
|
# -----------------------------------------------------------------
|
|
458
644
|
# Python -> R conversion
|
|
459
645
|
# -----------------------------------------------------------------
|
|
@@ -562,8 +748,10 @@ class RFunctionCaller:
|
|
|
562
748
|
try:
|
|
563
749
|
r(f'suppressMessages(library("{pkg}", character.only=TRUE))')
|
|
564
750
|
except Exception:
|
|
565
|
-
logger.info(f"Package '{pkg}' not found.")
|
|
566
|
-
logger.warning(
|
|
751
|
+
logger.info(f"[rpy-bridge.RFunctionCaller] Package '{pkg}' not found.")
|
|
752
|
+
logger.warning(
|
|
753
|
+
f"[rpy-bridge.RFunctionCaller] Installing missing R package: {pkg}"
|
|
754
|
+
)
|
|
567
755
|
r(f'install.packages("{pkg}", repos="https://cloud.r-project.org")')
|
|
568
756
|
r(f'suppressMessages(library("{pkg}", character.only=TRUE))')
|
|
569
757
|
|
|
@@ -571,6 +759,38 @@ class RFunctionCaller:
|
|
|
571
759
|
# Public: call an R function
|
|
572
760
|
# -----------------------------------------------------------------
|
|
573
761
|
def call(self, func_name: str, *args, **kwargs):
|
|
762
|
+
"""
|
|
763
|
+
Call an R function.
|
|
764
|
+
|
|
765
|
+
The function may be defined in:
|
|
766
|
+
* a sourced R script
|
|
767
|
+
* an installed R package (using ``package::function`` syntax)
|
|
768
|
+
* base R
|
|
769
|
+
|
|
770
|
+
Parameters
|
|
771
|
+
----------
|
|
772
|
+
func_name : str
|
|
773
|
+
Name of the R function to call. Package functions should be specified
|
|
774
|
+
as ``package::function``.
|
|
775
|
+
|
|
776
|
+
*args
|
|
777
|
+
Positional arguments passed to the R function.
|
|
778
|
+
|
|
779
|
+
**kwargs
|
|
780
|
+
Named arguments passed to the R function.
|
|
781
|
+
|
|
782
|
+
Returns
|
|
783
|
+
-------
|
|
784
|
+
object
|
|
785
|
+
The result of the R function, converted to a Python object.
|
|
786
|
+
|
|
787
|
+
Examples
|
|
788
|
+
--------
|
|
789
|
+
>>> rfc.call("sum", [1, 2, 3])
|
|
790
|
+
>>> rfc.call("dplyr::n_distinct", [1, 2, 2, 3])
|
|
791
|
+
>>> rfc.call("add_and_scale", 2, 3, scale=10)
|
|
792
|
+
"""
|
|
793
|
+
|
|
574
794
|
self._ensure_r_loaded()
|
|
575
795
|
|
|
576
796
|
func = None
|
|
@@ -629,7 +849,8 @@ class RFunctionCaller:
|
|
|
629
849
|
f"Error calling R function '{func_name}' from {source_info}: {e}"
|
|
630
850
|
) from e
|
|
631
851
|
|
|
632
|
-
|
|
852
|
+
_log_r_call(func_name, source_info)
|
|
853
|
+
|
|
633
854
|
return self._r2py(result)
|
|
634
855
|
|
|
635
856
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rpy-bridge
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Summary: Python-to-R interoperability engine with environment management, type-safe conversions, data normalization, and safe R function execution.
|
|
5
5
|
Author-email: Victoria Cheung <victoriakcheung@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -150,12 +150,12 @@ uv sync
|
|
|
150
150
|
from pathlib import Path
|
|
151
151
|
from rpy_bridge import RFunctionCaller
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
rfc = RFunctionCaller(
|
|
154
154
|
path_to_renv=Path("/path/to/project"),
|
|
155
|
-
|
|
155
|
+
script=Path("/path/to/script.R"),
|
|
156
156
|
)
|
|
157
157
|
|
|
158
|
-
summary_df =
|
|
158
|
+
summary_df = rfc.call("summarize_cohort", cohort_df)
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
---
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
rpy_bridge/__init__.py,sha256=VDCx-CiTBJO0cMp59v-gyJGBVYHjLjATTIdtYxBsK5Q,875
|
|
2
|
+
rpy_bridge/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
rpy_bridge/rpy2_utils.py,sha256=1W1Lgt0HI3TGs20GugHceFih1uLTTilz_pmkzNkPujY,37516
|
|
4
|
+
rpy_bridge-0.3.6.dist-info/licenses/LICENSE,sha256=JwbWVcSfeoLfZ2M_ZiyygKVDvhBDW3zbqTWwXOJwmrA,1276
|
|
5
|
+
rpy_bridge-0.3.6.dist-info/METADATA,sha256=Apvq8djqUFDsq84IfPuTTDDkW7rrZaxJz0DykM9tSBQ,9580
|
|
6
|
+
rpy_bridge-0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
rpy_bridge-0.3.6.dist-info/top_level.txt,sha256=z9UZ77ZuUPoLqMDQEpP4btstsaM1IpXb9Cn9yBVaHmU,11
|
|
8
|
+
rpy_bridge-0.3.6.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
rpy_bridge/__init__.py,sha256=VDCx-CiTBJO0cMp59v-gyJGBVYHjLjATTIdtYxBsK5Q,875
|
|
2
|
-
rpy_bridge/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
rpy_bridge/rpy2_utils.py,sha256=3xTxEOpT2xk6lFhY39stIwPs_oJmvQK5PowFxz6gSWg,30046
|
|
4
|
-
rpy_bridge-0.3.4.dist-info/licenses/LICENSE,sha256=JwbWVcSfeoLfZ2M_ZiyygKVDvhBDW3zbqTWwXOJwmrA,1276
|
|
5
|
-
rpy_bridge-0.3.4.dist-info/METADATA,sha256=XsKvCmOoWVqqC_xvZD3ckvApPWjfmC5xZ0g2QXRk8Fg,9591
|
|
6
|
-
rpy_bridge-0.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
-
rpy_bridge-0.3.4.dist-info/top_level.txt,sha256=z9UZ77ZuUPoLqMDQEpP4btstsaM1IpXb9Cn9yBVaHmU,11
|
|
8
|
-
rpy_bridge-0.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|