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

Fixes issue with non-seekable sources breaking StreamEncryptor and StreamDecryptor handling #14

Merged
merged 14 commits into from Sep 28, 2017
Merged

Fixes issue with non-seekable sources breaking StreamEncryptor and StreamDecryptor handling #14

merged 14 commits into from Sep 28, 2017

Conversation

mattsb42-aws
Copy link
Member

@mattsb42-aws mattsb42-aws commented Sep 19, 2017

As detailed in #13 : non-seekable sources were found to break StreamEncryptor and StreamDecryptor handling. This PR contains changes required to address this issue as well as removing any need for source stream to be seekable when handling framed messages.

Test results: https://gist.github.com/mattsb42-aws/a1714da88d2ab83bf3e1ed6a1cec4b59 (Travis setup coming soon).

@mattsb42-aws mattsb42-aws requested a review from a team September 19, 2017 07:29
self._source_stream = source_stream
self._duplicate_api()

def _duplicate_api(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

Might just be that Python isn't my daily driver, but I want to ask about a few things:

  1. Intentionally dropping private-hinted methods: If the language idiom is that privacy is a hint, not a requirement, isn't there a risk that this will break callers of wrapped streams in funky ways? (I know this is also marked as internal, but if it's hints all the way down...)
  2. Naming is a bit squishy: you refer to attributes on the LHS and methods on the RHS, but it looks like you're getting everything not prefixed with _, not only methods
  3. Again this might be at least partially an idiom thing, but rather than trying to assume the methods and attributes of the source_stream, would it make sense to have PassThroughStream itself inherit from the base stream type (if such a thing practically exists) and have each of the defined stream methods delegate to the underlying source_stream? Or, if not, should it instead copy everything?

For example: say we get a stream object CoolStream that is itself customized and has a (for example) _report_bytes_() API that is called by the local implementation of write(). PassThroughStream copies write() but not _report_bytes(), so when write() is invoked, it unexpectedly fails. Alternatively, if PassThroughStream is say an IOBase (for example; might not be the right choice) that has all the standard stream methods, PassThroughStream.write() can call source_stream.write() and treat the wrapped stream as more of a black box. I think that would drop some edge cases but preserve intent/functionality here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch on the attributes/methods. Fixed that.

The problem with just subclassing io.BaseIO is that these are really meant to front file-like objects, not just streams (fixed that terminology in the comments too). File-like objects (of which streams are a subset) have a consistent API but it is also quite large, so I would rather avoid manually duplicating it.

Effectively what this is doing is duplicating the public API of _source_stream onto the instance of PassThroughStream in the form of pointers to the attributes on _source_stream. This makes it so that any public interactions with the instance of PassThroughStream behave exactly as they would if they were made to _source_stream directly. Behavior of calls inside _source_stream are unaffected, as they are still happening within the context of that (unmodified) object.

Aside from the obvious overrides, the only place where this should introduce any unexpected behavior is if someone is making calls to private-hinted attributes on _source_stream, and I think that is a safe place to draw the line, and it matches with the convention laid out in PEP8.

Copy link
Member Author

Choose a reason for hiding this comment

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

Per offline discussion: replacing PassThroughStream with ProxyObject from wrapt.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, sorry for my confusion on the API duplication, I did not remember that interaction correctly. wrapt is a good find, that turned out as a nice clean drop-in.

@mattsb42-aws
Copy link
Member Author

Minor update to change internal variable for TeeStream from __tee__ to __tee. I had originally gone with __tee__ to mirror the behavior of wrapt with __wrapped__, but after considering it I think that the private naming is better as is avoids any potential future dunder conflicts.

As a side note, the Travis builds are all failing because #16 isn't present in this PR.

Copy link
Contributor

@lizroth lizroth left a comment

Choose a reason for hiding this comment

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

Approving based on offline discussion that Travis config needs #16 which I am going to look at now

@mattsb42-aws mattsb42-aws merged commit 1874fab into aws:master Sep 28, 2017
@mattsb42-aws mattsb42-aws deleted the non_seekable_sources branch September 28, 2017 00:14
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.

None yet

2 participants