-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
source-stripe: pass type checks #35587
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
This stack of pull requests is managed by Graphite. Learn more about stacking. Join @alafanechere and the rest of your teammates on |
c26d216
to
21c7982
Compare
21c7982
to
ea5f477
Compare
|
f2af3c6
to
742f3fc
Compare
532cb62
to
80301c2
Compare
80301c2
to
28290e0
Compare
28290e0
to
8f97834
Compare
89569e2
to
55b5330
Compare
55b5330
to
db92c9c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One concern about isinstance
being used. For the rest, this is nit or me trying to understand things
@@ -29,8 +30,9 @@ def _check_availability_for_sync_mode( | |||
sync_mode: SyncMode, | |||
logger: logging.Logger, | |||
source: Optional["Source"], | |||
stream_state: Optional[Mapping[str, Any]], | |||
stream_state: Optional[Mapping[Any, Any]], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This typing change seems odd to me. Why is this needed? get_first_stream_slice
should expect a Mapping[str, Any]
and it seems like the only place this is used
@@ -90,7 +92,12 @@ def handle_http_error( | |||
raise error | |||
doc_ref = self._visit_docs_message(logger, source) | |||
reason = f"The endpoint {error.response.url} returned {status_code}: {error.response.reason}. {error_message}. {doc_ref} " | |||
response_error_message = stream.parse_response_error_message(error.response) | |||
# TODO alafanechere |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't because of the inheritance we have in place right now. This comment describes the situation
@@ -24,7 +23,7 @@ | |||
from airbyte_cdk.sources.streams.concurrent.state_converters.datetime_stream_state_converter import EpochValueConcurrentStreamStateConverter | |||
from airbyte_cdk.sources.streams.http.auth import TokenAuthenticator | |||
from airbyte_cdk.utils.traced_exception import AirbyteTracedException | |||
from airbyte_protocol.models import SyncMode | |||
from airbyte_protocol.models import SyncMode # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we document why we have this type ignore? I'm unclear as to why we would ignore this
self, | ||
catalog: Optional[ConfiguredAirbyteCatalog], | ||
config: Optional[Mapping[str, Any]], | ||
state: Union[list[Any], MutableMapping[str, Any], None], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we keep TState here? I'm not very knowledgeable as to how MyPy handles TypeVar
@@ -83,13 +88,14 @@ def __init__(self, catalog: Optional[ConfiguredAirbyteCatalog], config: Optional | |||
self._streams_configured_as_full_refresh = set() | |||
|
|||
@staticmethod | |||
def validate_and_fill_with_defaults(config: MutableMapping[str, Any]) -> MutableMapping[str, Any]: | |||
def validate_and_fill_with_defaults(config: Mapping[str, Any]) -> Mapping[str, Any]: | |||
mutable_config = dict(config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't MutableMapping allow for modifying the config? In practice, it is probably a dict anyway here
@@ -213,19 +219,20 @@ def get_parent_stream(self, stream_state: Mapping[str, Any]) -> StripeStream: | |||
|
|||
class CreatedCursorIncrementalStripeStream(StripeStream): | |||
# Stripe returns most recently created objects first, so we don't want to persist state until the entire stream has been read | |||
state_checkpoint_interval = math.inf | |||
# TODO: alafanechere - confirm None is correct instead of math.inf | |||
state_checkpoint_interval = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can confirm because of this
) -> MutableMapping[str, Any]: | ||
params = super(CreatedCursorIncrementalStripeStream, self).request_params(stream_state, stream_slice, next_page_token) | ||
assert isinstance(stream_slice, dict), "stream_slice must be a dictionary" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this a bit dangerous as we could want to change this to any class that support the interface __get__
and this would start failing. Is there are reason why we need to validate that it is an instance of a dict?
@@ -511,15 +523,17 @@ def __init__(self, *args, **kwargs): | |||
start_date=self.start_date, | |||
) | |||
|
|||
def path(self, stream_slice: Mapping[str, Any] = None, **kwargs): | |||
def path(self, stream_slice: Optional[Mapping[str, Any]] = None, **kwargs: Any) -> str: | |||
assert isinstance(stream_slice, dict), "stream_slice must be a dictionary" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this a bit dangerous as we could want to change this to any class that support the interface __get__
and this would start failing. Is there are reason why we need to validate that it is an instance of a dict?
slice_ | rec | ||
for rec in parent_records | ||
for slice_ in incremental_slices | ||
if isinstance(slice_, dict) and isinstance(rec, dict) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this a bit dangerous as we could want to change this to any class that support the interface __get__
and this would start failing. Is there are reason why we need to validate that it is an instance of a dict?
@Jgerardopine, would you like to take over the PR as an onboarding task for Eric? It will need more work, but I think the comments here are very useful for someone learning the architecture, and @maxi297 is the reviewer. @alafanechere, hope that's fine by you! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alafanechere is this PR still relevant?
I doubt it. Tooling is not actively working on this, feel free to close or
take over.
|
What
Closes https://github.com/airbytehq/airbyte-internal-issues/issues/6349
We want to make
mypy
pass on a strategic connector. I pickedsource-stripe
How
poetry run mypy source_stripe --disallow-untyped-defs
It took me less than a day to make the type check pass.
Notes for reviewers
I'm unsure of 3 changes and would appreciate a connector expert some suggestion:
HttpStream
on a object typed asStream
. Can we makeHttpAvailabilityStrategy
handleHttpStream
instead ofStream
?HttpStream.path
but this method is not doing anything as it's not implemented in the abstract class.math.inf
(which is afloat
) was set forstate_checkpoint_interval
. I believe settingNone
is more correct but I'm not 💯 sure.