-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add check on package attachment to see if dependencies have udpated. These updates may cause runtime binary breaks in SeuratObject, but still allow SeuratObject to be loaded, so this check happens at attachment
- Loading branch information
1 parent
200b59b
commit d567ec8
Showing
1 changed file
with
34 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
d567ec8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit seems "wrong", from my perspective as a Matrix author.
User library trees are already by default partitioned by R's minor version. If I am running R
x.y.z
then I will never load packages installed under Ra.b.c
ifx.y != a.b
(unless I have somehow shot myself in the foot). Given that R does not introduce ABI changes in patch updates (x.y == a.b && z != c
), is there a real reason to be testing for and warning aboutx.y.z > a.b.c
?I similarly do not see how SeuratObject can be affected by the Matrix ABI when it does not use
LinkingTo: Matrix
. Are you referring to Matrix class definitions cached in the SeuratObject namespace, which can become stale with Matrix updates?But that indicates that your
NAMESPACE
is missingimportClassesFrom
directives:AFAIK, the only version mismatch that does affect SeuratObject is Matrix < 1.6-2 and Matrix >= 1.6-2, because Matrix 1.6-2 removes two unexported superclasses of
dgCMatrix
:mMatrix
andxMatrix
. Details about their definitions are unfortunately cached in, e.g.,getClassDef("Graph")@contains[c("mMatrix", "xMatrix")]
, and errors arise when the actual definitions are not found in the Matrix namespace. But instead of testing for that discrepancy in.onAttach
(why not.onLoad
??), you should change to usingImports: Matrix (>= 1.6-2)
once 1.6-2 is published by CRAN (today or tomorrow, probably).d567ec8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Mikael,
It very well could be wrong, but it was something simple to flag potential binary/cache incompatibilities
For the R test, we probably could get rid of it. However, R itself issues these warnings when loading a binary that was built using a newer version of R (eg. binary built under R 4.3.2 loaded under R 4.3.1), so I figured I'd do the reverse. I'm happy to remove it though
For the Matrix test, this one's important. I'm actually running into a case where the removal of the
dCsparseMatrix
class union from Matrix 1.6-2 is causing issues in SeuratObject binaries built with Matrix 1.6-1. Now, when trying to cast aGraph
(inherits fromdgCMatrix
) to another matrix representation (eg.TsparseMatrix
), we get errors. For exampleSpecifically, this is happening in
methods::.selectSuperClasses()
where it's trying to figure out ifdCsparseMatrix
is a virtual class (cached from Matrix 1.6-1.1,NULL
under Matrix 1.6-2) or notI haven't put the extra
importClassesFrom
in SeuratObject because the set of classes from Matrix seems to change frequently and it's an extra burden for me to maintain. I do bump the minimum required version of Matrix when SeuratObject gets an update, but don't regularly issue updates to SeuratObject that just bump the minimum required version of MatrixLastly, I put this in
.onAttach()
instead of.onLoad()
because I'm issuing the note throughpackageStartupMessage()
and I'm of the opinion that package startup messages should only be issued in.onAttach()
; I'm debating on whether or not this note should be moved to a warning and/or moved to.onLoad()
If you have any suggestions for this test (which I do want to keep in some capacity), I'd be happy to incorporate them
d567ec8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The difference between the classes that I listed in the
importClassesFrom
directive and the classesmMatrix
,xMatrix
, and (indeed, I'd forgotten to mention)dCsparseMatrix
is that the former are exported by Matrix and the latter were not. Exported classes (just as exported functions) cannot be removed haphazardly. So theimportClassesFrom
directive that I proposed would not cause problems down the line. Actually, it would prevent problems, because class definitions that you import are never cached: they are retrieved from Matrix at load time, not at install time.It is unfortunate that classes that we never exported (in this case
dCsparseMatrix
) were exposed to and inadvertently used by packages like SeuratObject. There were two ways for Matrix to overcome this limitation of S4:Option 2 was chosen because it required less maintenance for everyone involved in the long term; even Matrix itself was not using
mMatrix
,xMatrix
, anddCsparseMatrix
.Anyway ...
Of course, the choice of whether/how to keep the test is yours. Ideally, you would make the test more specific, to save your users and the people who maintain binaries of your package (CRAN, Debian, r-universe, ...) considerable headache (see, e.g., the discussion here about TMB's similarly unspecific test). One way to do that is to warn only for mismatch involving versions of Matrix known to cause problems (see, e.g., this recent commit by the TMB maintainer). But if you already plan to change to
Imports: Matrix (>= 1.6-2)
in your next release, then the resulting more specific test would not test anything at all, as 1.6-2 is the only version since 1.6-1 (the version on which you currently depend) known to cause problems.d567ec8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So importing the classes you mentioned above doesn't fully solve the problem, at least as far as the end-user is concerned. I have a branch of SeuratObject where I import those classes. I then built a Docker image where I
import-classes.tar.gz
)Using this image (called
objmat
), I then ran the yourintersect()
command to ensure that no classes were being cached and myGraph
->TsparseMatrix
conversion to see if I could trigger the errorThe internal class definition of
dCsparseMatrix
is still cached somewhere in SeuratObject. If I install Matrix 1.6-2, then SeuratObject (with or without the extra class imports), this error doesn't occur. Hopefully, if a user comes across an error like this, my note would have provided some guidance to the end-user about how to resolve the issue (reinstall SeuratObject from source)I'm happy to keep the updated imports, but I'm also going to keep the non-specific test as this is not the first time something like this has happened to SeuratObject (Matrix 1.5-3 removed
Csparse_validate()
, which caused similar S4 caching issues). I haven't decided if I'll adopt TMB's approach of switching to warnings during.onLoad()
or leaving it as a message in.onAttach()
(I feel my approach is less intrusive, albeit easier to miss)d567ec8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed.
dCsparseMatrix
was not exported by Matrix, and you cannot doimportClassesFrom(Matrix, <unexported class>)
.Right. The test is useful for as long as you continue to use
Imports: Matrix (>= 1.6-1)
instead ofImports: Matrix (>= 1.6-2)
.Yes, I remember vaguely. The underlying problem was that SeuratObject (at the time version 4.1.3) was missing
importClassesFrom(Matrix, CsparseMatrix)
in itsNAMESPACE
, so a staleCsparseMatrix
definition was cached and used.In general, I agree that Matrix needs to do a better job of detecting such quasi-breakage (quasi-, in the sense of requiring a re-installation rather than a patch) and reporting ahead of time to the respective maintainers. I am looking at ways to do so programmatically, so we can contact all affected maintainers ahead of our releases. In the mean time, it would be nice if the text in WRE about
importClassesFrom
would be adjusted to prevent situations like these. (I asked on R-devel a few months ago ...)d567ec8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The next update to SeuratObject will have require
Matrix (>= 1.6-2)
(or newer if you release before I do) as my policy is to always require the newest version of Matrix whenever SeuratObject is updated, but I don't have an ETA on that right now. I'm also going to leave the test as-is: as it only occurs during.onAttach()
and is signaled throughpackageStartupMessage()
, it should be easy to suppress if it causes any trouble. I've added the additional class imports in thedevelop
branch, so that will be part of the next release. If there's anything I can do to make SeuratObject a more reliable reverse dependency or report breakages due to S4 caching, please let me know