Hacker News new | ask | show | jobs
by masklinn 1593 days ago

    @pytest.fixture
    def libfact():
        yield CDLL("./fact.so")
FWIW that's pretty confusing as it gives the impression the library is reloaded for every test, but iirc dlopen() will just return a handle to the existing one. I don't think ctypes has a good way to unload dlls so it should probably be `fixture(scope='session')`.

That gets more relevant when on-the-fly compilation is added to the mix, spawning a compiler for every test is a complete waste of time.

2 comments

You can use tempfiles and (on OSX) use the private API of ctypes to dlclose to close the handle. Different call on Windows I think. Something like

  import _ctypes
  import shutil
  import tempfile

  @pytest.fixture
  def libfact():
      tmp = tempfile.NamedTemporaryFile(delete=True)
      shutil.copy2("./fact.so", tmp.name)
      lib = CDLL(tmp.name)
      yield lib
      _ctypes.dlclose(lib.handle)
EDIT: fixed error mentioned in reply.
Did you mean to have the `tmp.name` as the library passed into `CDDL`? If not, what’s the purpose of the copy?
Yes! Thank you. Fixed it.
If you're using Linux, I would recommend using TemporaryFile instead of NamedTemporaryFile. It takes advantage of the O_TMPFILE flag, which guarantees that the kernel will clean up the file for you when the process exits:

  import shutil
  import tempfile

  @pytest.fixture
  def libfact():
      tmp = tempfile.TemporaryFile()
      tmp_name = f"/dev/fd/{tmp.name}"
      shutil.copy2("./fact.so", tmp_name)
      lib = CDLL(tmp_name)
      yield lib
It's better than relying on your application to clean up the file for you. With application-level cleanup hooks, you're still vulnerable to a resource leak if the process gets a SIGKILL or crashes or otherwise ends before your hooks run.
Does this even work? The documentation states that one should not rely on TemporaryFile having a name. Otherwise why would NamedTemporaryFile exist?

For the rare occurrence of sigkill before cleanup, I think your /tmp has ample of space to keep a few more kb until the next reboot. Servers running tests probably restart more often than desktops nowadays, when wrapped in containers.

That's a good observation. Towards the end the fixture is dropped in favour of a module-like object, which spaws the compiler once per test run. One could enhance this to skip compilation in the sandbox process to avoid unnecessary compilations.