This replaces the list+queue system that the inara plugin originally
used with a deque based one.
The main differences here are that the list the worker thread uses to
send to inara and the list that events are added to is the same, with
the worker thread making a duplicate and clearing the original each time
it sends events (losing events if it fails to upload three times).
The format of the data has changed as well, from simple tuples to
NamedTuple classes that provide some extra type safety and sanity when
accessing fields.
The event queue itself is actually multiple queues, one per
API/FID/CMDR_name triplicate, thus allowing multiple commander switches
while we're running without causing any weird issues
timeout_session provides two things, TimeoutAdapter, a HTTP adapter
subclass that automatically adds timeouts to all requests, and
new_session, which automatically creates a request.Session with the
adapter in the correct place.
* find_caller_frame() to do the frame walk.
* munge_module_name() to fix up for plugins.
NB: caller_attributes() now has a noqa on CCR001 as I don't think it
can sensibly be made any less complex. Pulling out the 'if frame:'
section just results in *that* new method then being labelled as too
complex.:244
* Settled on `plugins.internal` and `<plugins>.found` as the format.
* A PyCharm recommendation was to use 'cls' instead of 'self' on class
methods, so the class detection code needs to cater for that.
Technically a developer could use any string for the "myself" member
name, but we'll assume just these two.
* Found will always have at least one folder level within plugin_dir
* Internal should always have *no* folder within internal_plugin_dir,
but cater for it just in case in future.
1. This makes setting up logging everywhere slightly more involved.
2. If I then want to change, say, %(module)s value I'll end up needing
to stack walk again.
So this might be better done in a filter. But these commits for the
record, and to come back to if needs be.
* Log messages propagate up Parent.Child chains, so we don't need a
channel on the plugin logger.
* But it still needs the filter to define qualname and class for
formatting.