boa icon indicating copy to clipboard operation
boa copied to clipboard

Easy file-tests macros

Open wolfv opened this issue 5 years ago • 15 comments

Some ideas for easier writing tests. Currently people do stuff like

- test -f $PREFIX/include/mamba/test.hpp  # [unix]
- if not %LIBRARY_PREFIX%\include\mamba\test.hpp exit 1 # [win]

which is super error prone and hard to get right.

Ideas for "files" macros:

  • site-packages("mamba") -> checks that pythonX.X/site-packages/ exists and has contents (at least one init.py)
  • pymodule("mamba") -> checks that pythonX.X/site-packages/ exists and has contents (at least one init.py)
  • lib("libmamba", soversion="...") -> check that at least libmamba.so / libamamba.dylib is found in lib/, additionally check for so-versions that link to that, or for windows, check that bin/libmamba.dll and lib/libmamba.lib are there
  • include("mamba") -> check that include folder include/mamba/ exists
  • include("mamba/test.hpp") -> check that file include/mamba/test.hpp` exists in package
  • `bin("mamba")

I am unsure about the following ones:

  • cmake_find("mamba") -> make sure that find_package("mamba") would work
  • pkgconfig("mamba") -> make sure that pkgconfig mamba works

There are probably some good ideas to support other languages and their install prefixes. I don't know where R installs to?!

We can also use qualifiers to disallow any files outside those matched by the macros, except maybe files in /share or some other data-centric directory. That would give pretty strict control over the package content.

wolfv avatar Nov 20 '20 14:11 wolfv

We probably want to express this as something like

- exists:
    site-packages: 
      - mamba
    pymodule:
      - mamba
    file:
       - $LIBRARY_PREFIX/some/file
    glob:
      - "**/another/file"

This has the nice advantage that we can include it easily in our json schema and get completions / validations at the json schema level for correctness of the specifiction

mariusvniekerk avatar Nov 20 '20 14:11 mariusvniekerk

I agree that @mariusvniekerk suggestion seems to be more straightforward

marcelotrevisani avatar Nov 20 '20 14:11 marcelotrevisani

I believe would be better to rename site-packages to python_modules, maybe?

marcelotrevisani avatar Nov 20 '20 14:11 marcelotrevisani

  • I like the idea of the cmake_find and pkgconfig
  • I'm not sure an existence macro for site-packages/pymodule is a common enough use case. Most packages should have imports specified already from which you can guess which files should exist.

chrisburr avatar Nov 20 '20 14:11 chrisburr

@chrisburr how do they specify the imports?

CJ-Wright avatar Nov 20 '20 14:11 CJ-Wright

@chrisburr the idea would be to also check for files that should not be in the package (basically the inverse) and either strongly warn or error out if something is in there that shouldn't be. But we could totally implicitly use the imports tests to check that.

@CJ-Wright thats another test field where one can check that a python lib gets imported fine.

wolfv avatar Nov 20 '20 14:11 wolfv

@wolfv There is always the option of using:

- exists:
    file:
       - $SP_DIR/mamba/__init__.py

for the one or two exceptions where importing isn't possible because it needs to have a propitiatory shared library available or something.

chrisburr avatar Nov 20 '20 14:11 chrisburr

I think we'd need more than just checking that a single file is imported, we'd need to check that all expected files are imported properly. In the past conda-forge's recipes haven't handled this well, leading to a bunch of issues on that front (and why I went and used the files themselves rather than the import tests to determine what modules are available)

CJ-Wright avatar Nov 20 '20 15:11 CJ-Wright

@CJ-Wright I'm not sure quite what you're referencing? In the example:

test:
  imports:
    - mamba

then roughly maps to the command python -c 'import mamba'. Is it that you want to explicitly check all submodules as well? i.e.

test:
  imports:
    - mamba
    - mamba._version
    - mamba.mamba
    - mamba.mamba_env
    - mamba.repoquery
    - mamba.utils 

chrisburr avatar Nov 20 '20 16:11 chrisburr

I believe we should not test all submodules, or at least if the maintainer wants to they can do it using a separated command because a lot of packages they accidentally package the test as well, and on top of there are some projects which have optional dependencies, so it may result in some errors in one of the imports due to the missing of one optional dependency

marcelotrevisani avatar Nov 20 '20 16:11 marcelotrevisani

Sorry, maybe I have the wrong context. I thought this was being brought up to help address the file clobbering problem, by testing that only the expected files were available and no other files got in. If this is not the goal then not testing submodules is fine, but if we are going to address the clobber issue we need to test all the files.

CJ-Wright avatar Nov 20 '20 16:11 CJ-Wright

Well, IMO if you define a pymodule or import then you "own" that "prefix". It would also say that you are not allowed to have any other pymodules (e.g. you are not allowed to accidentally add requests). This way we could help developers prevent accidental clobbers (not deliberate ones, though).

So if you add pymodule("mamba") your package is allowed to put any files it wants under site-packages/mamba/**/* but not elsewhere.

Does that make more sense now, @CJ-Wright ? The current way of testing for positive or negative file existence in conda-build is really cumbersome and error prone.

wolfv avatar Nov 20 '20 16:11 wolfv

I think that makes sense, although you will need to have the ability for carve outs, for instance for matplotlib

CJ-Wright avatar Nov 20 '20 17:11 CJ-Wright

One other lint we could do when we have a more semantic way of testing for a shared library is to automatically strongly warn if there is no run-exports.

wolfv avatar Nov 21 '20 07:11 wolfv

cmake_find("mamba") -> make sure that find_package("mamba") would work

On CMake, it would be convenient to be able to both check the existence of a CMake package, and of the CMake imported targets, something like:

cmake_find("Eigen3", "Eigen3::Eigen")

This is particular convenient for packages that automatically disable some targets if the dependency is not correctly found.

traversaro avatar Nov 21 '20 12:11 traversaro