Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Flexible instantiation #64

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

WIP: Flexible instantiation #64

wants to merge 2 commits into from

Conversation

jayvdb
Copy link
Contributor

@jayvdb jayvdb commented Aug 26, 2019

Adds StdioManager instantiation arg streams

@codecov-io
Copy link

codecov-io commented Aug 26, 2019

Codecov Report

Merging #64 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master    #64   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           3      3           
  Lines         101    121   +20     
=====================================
+ Hits          101    121   +20
Impacted Files Coverage Δ
src/stdio_mgr/stdio_mgr.py 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ec9f50f...fc4952c. Read the comment docs.

@@ -95,62 +101,32 @@ def getvalue(self):
return self._stream.getvalue().decode(self.encoding)


@attr.s(slots=False)
class TeeStdin(TextIOWrapper):
class Tee(TextIOWrapper):
Copy link
Owner

@bskinn bskinn Aug 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jayvdb I would want (at least) two implementations of teeing, ultimately, in order to accurately mimic the CLI experience: tee-on-read for stdin and tee-on-write for stderr. That way, everything that would get pushed to a real user's console, across in/out/err, would get stored in out in the same order that that user would see it in "real life".

I had originally only implemented TeeStdin b/c I didn't have specific need for teeing stderr in my initial use-cases for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, but beyond the scope of this. Raised #65 about a similar feature.

However it does suggest that Tee should be _Tee, and other parts of this WIP probably should be private (even if they are desirable in coala-utils; that shouldnt be a consideration here)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<nod>, agreed, out of scope here.

But yes, exactly, if you think it's not a crazy feature to have, then it would be good to keep that additional teeing eventuality in mind during separation of the mocking and teeing of stdin.

@@ -23,6 +23,6 @@ jobs:
script:
- python --version
- pip list
- pytest --cov=src -p no:warnings
- pytest --cov=src -p no:warnings -s
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this -s can be removed, because of the commented out assertion in StdioTuple.__new__.

the alternatives include:

  • not creating _INITIAL_SYS_STREAMS and re-add the assertion, which requires the caller to disable any incompatible wrappers before using stdio-mgr
  • detecting wrappers like pytest, and finding where they hid the real sys streams.
  • detecting incompatible wrappers in __new__ but only emit a warning, and let the user encounter real breakages somewhere else, possibly quite confusing. (this appears to be the io approach, as we saw with buffer=StringIO() not breaking during instantiation)
  • do no checking; user beware.

Copy link
Contributor Author

@jayvdb jayvdb Sep 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disabling pytest capturing from within the test suite is given a small note at the bottom of https://docs.pytest.org/en/latest/capture.html .

There was also talk of it being possible using markers pytest-dev/pytest#1599 (comment)

And it seems class scope disabling can be achieved using the pytest plugin manager pytest-dev/pytest#1599 (comment)

(If we are going to expect users to uncapture pytest, https://docs.pytest.org/en/latest/capture.html needs a rewrite to assist them.)


Upon exiting the context, the original stream objects are restored
within :mod:`sys`, and the temporary streams are closed.
class FakeStdioTuple(StdioTuple, _MultiCloseContextManager):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the _MultiCloseContextManager here has no effect. It is mostly thought experiment atm, and should be removed unless there is some benefit in keeping it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, the important part is that dual-inheritance is possible, so others could do it if they wanted to use _MultiCloseContextManager as a mixin.

@@ -380,3 +427,4 @@ def __exit__(self, exc_type, exc_value, traceback):


stdio_mgr = StdioManager
_INITIAL_SYS_STREAMS = StdioTuple([sys.stdin, sys.stdout, sys.stderr])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be sys.__stdin__, sys.__stdout__ & sys.__stderr__, which should be untouched and we can bypass/undo any wrapping done to sys.std*

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I hadn't thought about using those, but yeah -- definitely helpful.

It's not a carte-blanche thing, though. We can reference back to those in some cases -- but in general, there may be situations where we might want to restore to the prior sys.stdfoo, instead of the canonical sys.__stdfoo__, to avoid munging a surrounding stdio mock/wrap.

I think testing sys.stdfoo is sys.__stdfoo__ should be an unambiguous sign that we're working inside someone else's mocking/wrapping environment, though. Oh, well, not completely -- if something rummages about in the innards of sys.stdfoo instead of replacing the object references, then is comparison might still give True.

That actually may be an argument against trying to directly reach within sys.stdfoo to work with the internal buffer... if .stdfoo is .__stdfoo__, then we'd also be tinkering with the "canonical backup".

Copy link
Contributor Author

@jayvdb jayvdb Sep 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... if .stdfoo is .__stdfoo__, then we'd also be tinkering with the "canonical backup".

Yes, this is the dangerous territory that #78 is going in -- IMO the 'dont touch' is cause for concern, lots of it, especially in multi-threading as the tinkering being done isnt atomic, and locking is going to be hard. #78 may need to be opt-in for a while.

@bskinn bskinn mentioned this pull request Sep 16, 2019
16 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants