Python file reader/writer, with processing pipeline and context manager
This code looks very nice! I admire how clean and organized your code is. It appears that you tried to think through how to arrange it, and I really appreciate that.

There are really only a few areas that I see things could be improved: the speed of execution, the robustness of the code when a user attempts to supply invalid data, and the verbiage for readability when others must see this code.

Efficiency

I had to look it up, but I remember reading about how reducing all of your code that follows if __name__ == '__main__': into a single main() function is good practice. After searching around I remember where I read it, it was in the Python Cookbook (3rd edition) by O'Reilly Media. The authors David Beazley and Brian K. Jones wrote:


  A little-known fact is that code defined in the global scope like this runs slower than code defined in a function. The speed difference has to do with the implementation of local versus global variables (operations involving locals are faster) ... The speed difference depends heavily on the processing being performed, but in our experience, speedups of 15-30% are not uncommon


Robustness

I can see in a couple places where someone using this code may (whether accidentally or with malicious intent) break it and cause an error, or perhaps not cause an error but make it do something not designed. You may want to consider adding checks throughout your code, so that if say a value in a dict is of a type other than a string, then you know something is wrong and you shouldn't continue with the swap function. I realize adding Exception handling throughout or if/then branches will make for less clean and readable syntax, but it is an area where you may need to take this next if you plan to put this into a production environment.

Readability

Think about how this code will look if someone else has to get up in the middle of the night when something breaks, and half conscious and under duress, go through and figure out where a problem might be. (I think my friend and QA Guru Jon Gluck called it "Drunk Proofing" your code, so even the intoxicated who get a late night emergency call can fix the problem.)

As an example, consider the word "processing." This is a general enough word that you could use it almost anywhere in your code, and across multiple classes and functions even though different uses of this word may be completely unrelated. It reminds me of "college speak" for the word "do." Imagine replacing the word "process" (including "processing" and "processor" and "deprocessor" with the words "doing", "doer" and "undoer", respectively). I don't have a suggestion for what to replace the word process with, and maybe it truly is the best and only word to use here (just as 'handler' is often the best word to use in many cases), but just be careful. Be especially careful if you have used these same terms in other parts of your code that could cause significantly more confusion if someone attempts to wade through a stack trace to troubleshoot an error.

Caveat

Please understand that I think your code is quite beautiful, and frankly I'm not sure my code would look this good if I were tasked with the same project. Regardless, since you posted in code review asking for suggestions, I am trying to poke some holes in it, and make suggestions of where to go from here.

Great job, and keep it up!