On 05/08/2013 10:25 AM, Simon Urbanek wrote:
On May 7, 2013, at 11:35 PM, Peter Meilstrup wrote:
Encountered an error in scripting, which can be reproduced using Rscript as
follows:
$ Rscript -e "library(httr); handle('http://cran.r-project.org')"
Error in getCurlHandle(cookiefile = cookie_path, .defaults = list()) :
could not find function "getClass"
Calls: handle -> getCurlHandle
or by starting R without the methods package attached:
$ R_DEFAULT_PACKAGES=base R
[snip]
library(httr)
handle('http://cran.fhcrc.org/')
Error in getCurlHandle(cookiefile = cookie_path, .defaults = list()) :
could not find function "getClass"
As far as I can tell the error occurs when getCurlHandle .Calls a C
function which then calls SET_CLASS, which (I guess) requires
methods::setClass to be in the search path.
Now 'httr' Imports 'RCurl' which Depends on 'methods'. So I think
`library(httr)` should end up attaching 'methods' to the search path, but
it seems 'methods' is just imported to RCurl's namespace.
I think this is a problem since the Depends line is indicating that
'methods' must be attached for RCurl to work, whether or not RCurl itself
is being attached.
For the record, I see the same problem with other packages that use S4 - very
often it trips packages that don't use S4 but import a package that does. The
analysis is correct - if a package B just imports a function from another
package A which in turn relies on something in Depends, it breaks, because A is
not on the search path and thus A doesn't have access to the dependencies it
needs. I don't know that was the intended design. I see two way to fix this
1) make sure Depends: are always put on the search path even if the package is
not attached
2) automatically generate imports for all packages in Depends:
The main problem is that B is helpless - only a change in A can make it work.
Fix for A is to explicitly add import(methods) even though it's already in
Depends:. Note that R CMD check doesn't detect this.
As described, this is a 'package maintainer' problem -- fix package A. Also,
this isn't unique to methods, other packages routinely Depend: on something that
should instead be Import:'ed.
But I think Peter's case is different, because the C implementations of
SEXP R_do_MAKE_CLASS(const char *what);
SEXP R_getClassDef (const char *what);
need to be called from inside the package environment, but there is no way to
pass the package environment through the interface above.
Maybe the partial patch (attached) points to a solution? It changes the
interface (though would only break a couple of Bioconductor packages in a minor
way) (I think there's a missing PROTECT in there too.)
Cheers,
Simon
______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
--
Computational Biology / Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N.
PO Box 19024 Seattle, WA 98109
Location: Arnold Building M1 B861
Phone: (206) 667-2793
Index: src/include/Rinternals.h
===================================================================
--- src/include/Rinternals.h (revision 62721)
+++ src/include/Rinternals.h (working copy)
@@ -891,8 +891,8 @@
int R_has_slot(SEXP obj, SEXP name);
/* class definition, new objects (objects.c) */
-SEXP R_do_MAKE_CLASS(const char *what);
-SEXP R_getClassDef (const char *what);
+SEXP R_do_MAKE_CLASS(const char *what, SEXP rho);
+SEXP R_getClassDef (const char *what, SEXP rho);
SEXP R_do_new_object(SEXP class_def);
/* supporting a C-level version of is(., .) : */
int R_check_class_and_super(SEXP x, const char **valid, SEXP rho);
Index: src/include/Rdefines.h
===================================================================
--- src/include/Rdefines.h (revision 62721)
+++ src/include/Rdefines.h (working copy)
@@ -139,7 +139,8 @@
#define GET_SLOT(x, what) R_do_slot(x, what)
#define SET_SLOT(x, what, value) R_do_slot_assign(x, what, value)
-#define MAKE_CLASS(what) R_do_MAKE_CLASS(what)
+#define MAKE_CLASS(what) R_do_MAKE_CLASS(what, R_GlobalEnv)
+#define GET_CLASS_DEF(what) R_getClassDef(what, R_GlobalEnv)
/* NEW_OBJECT is recommended; NEW is for green book compatibility */
#define NEW_OBJECT(class_def) R_do_new_object(class_def)
#define NEW(class_def) R_do_new_object(class_def)
Index: src/main/objects.c
===================================================================
--- src/main/objects.c (revision 62721)
+++ src/main/objects.c (working copy)
@@ -864,7 +864,7 @@
#ifdef _be_too_picky_
if(IS_S4_OBJECT(x) && nwhat == 1 && !isvec &&
- !isNull(R_getClassDef(translateChar(STRING_ELT(what, 0)))))
+ !isNull(R_getClassDef(translateChar(STRING_ELT(what, 0))))) /* FIXME: needs rho */
warning(_("use 'is()' instead of 'inherits()' on S4 objects"));
#endif
@@ -937,7 +937,7 @@
s_selectSuperCl = install(".selectSuperClasses");
}
- PROTECT(classExts = R_do_slot(R_getClassDef(class), s_contains));
+ PROTECT(classExts = R_do_slot(R_getClassDef(class, rho), s_contains));
PROTECT(_call = lang3(s_selectSuperCl, classExts,
/* dropVirtual = */ ScalarLogical(1)));
superCl = eval(_call, rho);
@@ -1470,7 +1470,7 @@
return value;
}
-SEXP R_do_MAKE_CLASS(const char *what)
+SEXP R_do_MAKE_CLASS(const char *what, SEXP rho)
{
static SEXP s_getClass = NULL;
SEXP e, call;
@@ -1480,13 +1480,13 @@
PROTECT(call = allocVector(LANGSXP, 2));
SETCAR(call, s_getClass);
SETCAR(CDR(call), mkString(what));
- e = eval(call, R_GlobalEnv);
+ e = eval(call, rho);
UNPROTECT(1);
return(e);
}
/* this very similar, but gives NULL instead of an error for a non-existing class */
-SEXP R_getClassDef(const char *what)
+SEXP R_getClassDef(const char *what, SEXP rho)
{
static SEXP s_getClassDef = NULL;
SEXP e, call;
@@ -1496,7 +1496,7 @@
PROTECT(call = allocVector(LANGSXP, 2));
SETCAR(call, s_getClassDef);
SETCAR(CDR(call), mkString(what));
- e = eval(call, R_GlobalEnv);
+ e = eval(call, rho);
UNPROTECT(1);
return(e);
}
@@ -1520,12 +1520,13 @@
translateChar(asChar(e)));
}
e = R_do_slot(class_def, s_className);
- value = duplicate(R_do_slot(class_def, s_prototype));
+ PROTECT(value = duplicate(R_do_slot(class_def, s_prototype)));
if(TYPEOF(value) == S4SXP || getAttrib(e, R_PackageSymbol) != R_NilValue)
{ /* Anything but an object from a base "class" (numeric, matrix,..) */
setAttrib(value, R_ClassSymbol, e);
SET_S4_OBJECT(value);
}
+ UNPROTECT(1);
return value;
}
______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel