I expect _global_ here refers to the language-level semantics, not internal interpreter semantics.
Python's module system results in no implicit modifications to Python-level state between modules — at least, for a well-developed module. Since Python is so dynamic, you can of course jerry-rig all sorts of global consequences if you really want to. But without dynamic magic, all state is namespaced to the imported module, and must be explicitly given names within the importer, with no global consequences for parallel modules.
In your os.getcwd() example, the state is scoped to the importer module, so it's not an example of global interpreter state.
I don't know what Ruby's module system looks like, so I don't know for sure if that is the point the GP is making. It seems to me that you are in agreement, just disagree with the meaning of "global" in this context.
Ruby's modules are namespaces (well objects that are deeply similar to class objects, but not identical), but Ruby files aren't modules, they are executed in the global environment, and may (or may not) define (or redefine, modules are mutable) modules, and any such modules may or may not have any relationship to the file name and relative path location.
But by this interpretation, the description of #include is incorrect, and `require` wouldn't be analogous to `#include`. That #included code appears at the highest scope in a file is a coding convention, not a fact about the preprocessor. That's just the place where people like to put their #include directives.
The reason they do that, of course, is that they want to be able to access #included code from the highest scope in their file. But once that's the requirement, we're back to saying that this is the goal of all module systems, and all of them will modify the global namespace in this way.
> all state is namespaced to the imported module, and must be explicitly given names within the importer, with no global consequences for parallel modules.
This is just false; state appears within the interpreter in the form of registering the imported module under the provided name. You are free to register a name that's already in use, in which case you will lose the ability to refer to the module that was registered with the same name earlier. Becoming unreachable is ordinarily considered a "consequence"; you can find people complaining that this has happened to them.
Why does the problem arise? Because importing means making changes to the state of the interpreter.
Python's module system results in no implicit modifications to Python-level state between modules — at least, for a well-developed module. Since Python is so dynamic, you can of course jerry-rig all sorts of global consequences if you really want to. But without dynamic magic, all state is namespaced to the imported module, and must be explicitly given names within the importer, with no global consequences for parallel modules.
In your os.getcwd() example, the state is scoped to the importer module, so it's not an example of global interpreter state.
I don't know what Ruby's module system looks like, so I don't know for sure if that is the point the GP is making. It seems to me that you are in agreement, just disagree with the meaning of "global" in this context.