ben that's a highly counter-intuitive and non-standard, non-obvious way to
do it. to make it clear: you need to document, in everry instance where
those functions are used, that the ctx is added transparently and without
the caller's knowledge.
if it had been done as a class (even an auto-generated one), it would have
been obvious what was going on.
I'm unsure what isn't clear - 'what' is a non-obvious way to do 'what'?
Note that pylibftdi is primarily designed from a Python programmer's point of view rather than a libftdi / FTDI device user's point of view. It tries to take the most used / useful 20% of the library and make that really easy to use (e.g. using properties for bit bang access, emulating file objects, etc), even if that makes doing things with the other 80% more tricky / counter intuitive to someone coming from a libftdi background.
Other Python packages take the other approach and provide a direct mapping which exposes libftdi directly, and libftdi comes with it's own Python bindings if you want to use those.
In particular I don't want users of pylibftdi to need to know anything about ctypes or libftdi, but still to be able to access the functions of the library which don't need this. Almost all libftdi functions take a reference to the context as a first parameter, and exposing this parameter to the user would require a) holding a reference to the context (or knowing about the internals of pylibftdi.Device - both of which break encapsulation) and b) requiring them to import ctypes (because the context needs to be passed by reference - using ctypes' byref), when many (admittedly not all) functions take simple primitive values (strings, integers etc) as their parameters.
As for documentation, I can't see how anyone would find ftdi_fn in the first place except through the documentation in either the 'Advanced Usage' section or the function's docstring itself, these are referenced in the links I gave earlier.
Though perhaps you are suggesting the documentation doesn't serve other people developing pylibftdi, in which case you are probably right - I've not given that much attention. Perhaps the library should be further abstracted (the user-facing serial / RS232 API as a subclass of an DeviceBase class with a defined interface (ftdi_fn) such that fdll / ctx aren't exposed/used in the subclasses), I guess I just 'see' the code that way anyway. It's how the BitBangDevice class is written - it intentionally doesn't reference / know about the fdll or ctx attributes.
As for using a class - I'm not sure what you mean - the ftdi_fn property does return an instance of the FtdiForwarder class, which uses __getattr__ / functools.partial.