Everything API in Python
Do you know about the Everything browser? It is a free windows-based application that allows lightning fast searching of files on a system. As a TA that needs to constantly dig through 1000’s of game assets it is an absolute joy to use.
We often have a need for file dialogues like this in order to run batch processes on files. The trouble is, most methods of populating a file list in a UI rely on you iterating over a file structure manually, which on larger folders can take forever.
Luckily, Everything browser has an SDK. So long as the Everything service is running in the background, you have access in code to all of the features the Everything browser does. Sweet!
One problem: The SDK only natively supports C/C++. Most TA’s I know of create tools in python, is there a way to do that? The answer is yes, but it’s verbose and unwieldy.
To try and get around this, I’ve been experimenting with wrapping the C API up into a python package using pybind11 to allow you to run these commands much easier.
Making Everything API Python Bindings
Pybind11 is a C++ library for taking C/C++ code and compiling it into a python extension module, thus making it compatible with python scripts. There are several other libraries and modules that do this (ctypes, cffi, cython to name a few) but pybind11 was the easiest in terms of syntax for me to wrap my head around and set up. I recommend watching an introduction to it via one of several awesome talks, like this one:
Making the bindings using pybind11 was amazingly straightforward. First set up proper inclusions of the Everything SDK and pybind11 include/binary files, then just do a straight wrap of the Everything functions:
void Py_Everything_SetSearch(const std::wstring& searchTerm)
{
Everything_SetSearch(searchTerm.c_str());
}
//later on down the file
PYBIND11_MODULE(_PyEverything, m)
{
m.doc() = "Everything Python Bindings.";
//Functions
//Setting search state
m.def("SetSearch", &Py_Everything_SetSearch, py::arg("search_string"));
// + lots more binding of other SDK functions and constants below
}
Code language: C++ (cpp)
This greatly simplified the usage of the API since I no longer had to deal with the rather clunky ctypes module. The complexity was still there, but I didn’t have to deal with it on the python side, instead leaving that on the boundary with the better IDE debugging support.
import PyEverything
#set the search text to abc AND 123
PyEverything.SetSearch("abc 123")
#execute the query
PyEverything.Query(True)
#Get the full path and file name of the first visible result.
result = PyEverything.GetResultFullPathName(0)
Code language: Python (python)
Using it, it was possible to hook the API into a PySide2 GUI by creating a custom QAbstractItemModel. Once you have access to the filepaths in a model, the world is your oyster in terms of batching. When I get time, I’d like to also detail the approach for that. For now, here’s a screenshot:
The PyEverything project is hosted on github. It’s still pre-release and mostly untested, but there are wheels for python 3.7, 3.8, and 3.9. For anything else, there are instructions to build from source. Have fun!