-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add type hints to APIs #1297
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
Add type hints to APIs #1297
Conversation
84bc493
to
5fffd75
Compare
Would those aiohttp/yarl cases be handled by something like the following in a
That way if hints are found they're used, but if they're not they're not. |
@briancurtin That would work but every user would then have to make that configuration themselves which is a bummer. |
That seems a level deeper than I'm familiar with this going, though maybe I just misunderstand some of the layering here. If you're a consumer of |
@briancurtin Yeah that's the case for mypy, especially with Users would either have to use the above config you provided or use |
Data point: I've integrated this branch into a project using Eland which is partially type-checked and received no issues from |
40ccbb3
to
c0a42c1
Compare
I rebased this branch on master and collapsed everything into three commits. The first two are deeply reviewable since they're written by hand but the last one should be high-level reviewable since it's all generated code. |
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.
Thanks a lot for this effort. Its great to see a project that is typed and python here. I don't have anything to add other than thank you and I will be taking these ideas back to my teams python projects as well. Keep up the great work!
c0a42c1
to
5868b50
Compare
96: Pin elasticsearch to latest version 7.14.1 r=duckinator a=pyup-bot This PR pins [elasticsearch[async]](https://pypi.org/project/elasticsearch) to the latest release **7.14.1**. <details> <summary>Changelog</summary> ### 7.14.1 ``` Client - Client is compatible with Elasticsearch 7.14.1 ``` ### 7.14.0 ``` Client Added - Added check that client is connected to an Elasticsearch cluster. If the client isn't connected to a supported Elasticsearch cluster the `UnsupportedProductError` exception will be raised. APIs Search - Added the `terms_enum` **beta** API - Removed the `query_and_fetch` and `dfs_query_and_fetch` options in the `search_type` parameter to the `msearch`, `msearch_template` and `search_template` APIs Index Lifecycle Management - Added the `ilm.migrate_to_data_tiers` API Machine Learning - Added the `ml.reset_job` API Security - Added the `security.saml_authenticate` API - Added the `security.saml_complete_logout` API - Added the `security.saml_invalidate` API - Added the `security.saml_logout` API - Added the `security.saml_prepare_authentication` API - Added the `security.saml_service_provider_metadata` API SQL - Added the `sql.delete_async` API - Added the `sql.get_async` API - Added the `sql.get_async_status` API Snapshots - Added the `include_repository` parameter to `snapshot.get` API - Added the `rarely_abort_writes` parameter to the `snapshot.repository_analyze` API ``` ### 7.14.0a1 ``` Client Added - Added check that client is connected to an Elasticsearch cluster. If the client isn't connected to Elasticsearch a `NotElasticsearchError` exception will be raised. APIs Search - Added the `terms_enum` **beta** API - Removed the `query_and_fetch` and `dfs_query_and_fetch` options in the `search_type` parameter to the `msearch`, `msearch_template` and `search_template` APIs Index Lifecycle Management - Added the `ilm.migrate_to_data_tiers` API Machine Learning - Added the `ml.reset_job` API Security - Added the `security.saml_authenticate` API - Added the `security.saml_complete_logout` API - Added the `security.saml_invalidate` API - Added the `security.saml_logout` API - Added the `security.saml_prepare_authentication` API - Added the `security.saml_service_provider_metadata` API Snapshots - Added the `include_repository` parameter to `snapshot.get` API - Added the `rarely_abort_writes` parameter to the `snapshot.repository_analyze` API ``` ### 7.13.4 ``` Client - Client is compatible with Elasticsearch 7.13.4 ``` ### 7.13.3 ``` Client Fixed - `NameError` would be raised on Python 2.7 and 3.4 when a connection error would have otherwise been raised. ``` ### 7.13.2 ```⚠️ **This release has been yanked on PyPI due to a regression in Python <3.5, please use another version.** Client Fixed - `Transport.perform_request()` now properly reraises `RecursionError` (Contributed by hmilkovi) - `AIOHttpConnection` no longer sends `Accept-Encoding: gzip, deflate` when `http_compress=None`. Instead now sends no `Accept-Encoding` header. APIs Snapshot - Added the `snapshot.repository_analyze` API ``` ### 7.13.1 ``` Client - Client is compatible with Elasticsearch 7.13.1 ``` ### 7.13.0 ``` Client Added - Added support for compatibility header for Elasticsearch. If the environment variable `ELASTIC_CLIENT_APIVERSIONING=1` is set the client will send the headers Accept and Content-Type with the following value: `application/vnd.elasticsearch+json;compatible-with=7`. APIs Cat - Added the `include_unloaded_segments` parameter to the `cat.nodes` API Snapshot Features - Added the `features.reset_features` **experimental** API Fleet - Added the `fleet.global_checkpoints` **expiremental** API Ingest - Added the `ingest.geo_ip_stats` API Machine Learning - Added the `ml.delete_trained_model_alias` API - Added the `ml.preview_data_frame_analytics` API - Added the `ml.put_trained_model_alias` API - Changed the `ml.delete_data_frame_analytics`, `ml.delete_trained_model`, `ml.explain_data_frame_analytics`, `ml.get_data_fram_analytics`, `ml.get_data_frame_analytics_stats`, `ml.get_trained_models`, `ml.get_trained_models_stats`, `ml.put_trained_model`, `ml.start_data_frame_analytics`, `ml.stop_data_frame_analytics`, `ml.update_data_frame_analytics` APIs from **beta** to **stable**. Nodes - Added `include_unloaded_segments` parameter to `node.stats` API Searchable Snapshots - Added the `searchable_snapshots.cache_stats` **experimental** API Security - Added the `security.clear_cached_service_tokens` **beta** API - Added the `security.create_service_token` **beta** API - Added the `security.delete_service_token` **beta** API - Added the `security.get_service_accounts` **beta** API - Added the `security.get_service_credentials` **beta** API Shutdown - Added the `shutdown.delete_node` **experiemental** API - Added the `shutdown.get_node` **experimental** API - Added the `shutdown.put_node` **experimental** API Snapshots - Added the `index_details` parameter to `snapshot.get` API Text Structure - Changed the `text_structure.find_structure` API from **experimental** to **stable** ``` ### 7.12.1 ``` APIs Text Structure - Changed the `text_structure.find_text_structure` API from **experimental** to **stable** ``` ### 7.12.0 ``` APIs Autoscaling - Changed `autoscaling.delete_autoscaling_policy`, `autoscaling.get_autoscaling_policy`, and `autoscaling.put_autoscaling_policy` APIs from **experimental** to **stable** EQL - Added `eql.get_status` API Logash - Added `logstash.delete_pipeline`, `logstash.get_pipeline`, and `logstash.put_pipeline` APIs Machine Learning - Removed the **experimental** `ml.find_text_structure` API Searchable Snapshots - Added `storage` parameter to the `searchable_snapshots.mount` API - Added `level` parameter to the `searchable_snapshots.stats` API Search - Added the `min_compatible_shard_node` parameter to `search()` Text Structure - Added **experimental** `text_structure.find_text_structure` API ``` ### 7.11.0 ``` Client Added * Added the ``X-Elastic-Client-Meta`` HTTP header and the ``meta_header`` parameter for controlling the header (1473) * Added ``ElasticsearchWarning`` which is raised when the ``Warning`` HTTP header is returned from Elasticsearch. `ElasticsearchDeprecationWarning` is now an alias for this warning type (1495) APIs Async Search - Added the `async_search.status` API Autoscaling - Added the `autoscaling.get_autoscaling_capacity` **experimental** API - Removed the `autoscaling.get_autoscaling_decision` **experimental** API Cat - Changed `cat.tasks` API parameters `node_id` and `parent_task` to `nodes` and `parent_task_id` Cluster - Changed `cluster.delete_component_template`, `cluster.exists_component_template`, and `cluster.get_component_template`, `cluster.put_component_template` APIs from **experimental** to **stable** EQL - Changed `eql.delete`, `eql.get`, `eql.search` APIs from **beta** to **stable** Indices - Added `indices.migrate_to_data_stream` API - Added `indices.promote_data_stream` API - Added `expand_wildcards` parameter to the `indices.delete_data_stream` and `indices.get_data_stream` APIs - Changed `indices.delete_index_template`, `indices.exists_index_template`, `indices.get_index_template`, `indices.put_index_template`, `indices.simulate_index_template`, and `indices.simulate_template` APIs moved from **experimental** to **stable** Machine Learning - Added `ml.upgrade_job_snapshot` API - Added `exclude_generated` parameter to `ml.get_data_frame_analytics`, `ml.get_datafeeds`, `ml.get_jobs`, and `ml.get_trained_models` APIs - Changed `ml.delete_data_frame_analytics`, `ml.delete_trained_model`, `ml.explain_data_frame_analytics`, `ml.get_data_frame_analytics`, `ml.get_data_frame_analytics_stats`, `ml.get_trained_models`, `ml.get_trained_models_stats`, `ml.put_data_frame_analytics`, `ml.put_trained_model`, `ml.start_data_frame_analytics`, `ml.stop_data_frame_analytics`, `ml.update_data_frame_analytics` APIs from **experimental** to **beta** Rollup - Added `rollup.rollup` API Transform - Added `exclude_generated` parameter to `transform.get_transform` API Watcher - Added `watcher.query_watches` API ``` ### 7.11.0b1 ``` Client Added * Added the ``X-Elastic-Client-Meta`` HTTP header and the ``meta_header`` parameter for controlling the header (1473) * Added ``ElasticsearchWarning`` which is raised when the ``Warning`` HTTP header is returned from Elasticsearch. `ElasticsearchDeprecationWarning` is now an alias for this warning type (1495) APIs Async Search - Added the `async_search.status` API Autoscaling - Added the `autoscaling.get_autoscaling_capacity` **experimental** API - Removed the `autoscaling.get_autoscaling_decision` **experimental** API Cat - Changed `cat.tasks` API parameters `node_id` and `parent_task` to `nodes` and `parent_task_id` Cluster - Changed `cluster.delete_component_template`, `cluster.exists_component_template`, and `cluster.get_component_template`, `cluster.put_component_template` APIs from **experimental** to **stable** EQL - Changed `eql.delete`, `eql.get`, `eql.search` APIs from **beta** to **stable** Indices - Added `indices.migrate_to_data_stream` API - Added `indices.promote_data_stream` API - Added `expand_wildcards` parameter to the `indices.delete_data_stream` and `indices.get_data_stream` APIs - Changed `indices.delete_index_template`, `indices.exists_index_template`, `indices.get_index_template`, `indices.put_index_template`, `indices.simulate_index_template`, and `indices.simulate_template` APIs moved from **experimental** to **stable** Machine Learning - Added `ml.upgrade_job_snapshot` API - Added `exclude_generated` parameter to `ml.get_data_frame_analytics`, `ml.get_datafeeds`, `ml.get_jobs`, and `ml.get_trained_models` APIs - Changed `ml.delete_data_frame_analytics`, `ml.delete_trained_model`, `ml.explain_data_frame_analytics`, `ml.get_data_frame_analytics`, `ml.get_data_frame_analytics_stats`, `ml.get_trained_models`, `ml.get_trained_models_stats`, `ml.put_data_frame_analytics`, `ml.put_trained_model`, `ml.start_data_frame_analytics`, `ml.stop_data_frame_analytics`, `ml.update_data_frame_analytics` APIs from **experimental** to **beta** Rollup - Added `rollup.rollup` API Transform - Added `exclude_generated` parameter to `transform.get_transform` API Watcher - Added `watcher.query_watches` API ``` ### 7.10.1 ``` Client Fixed * Fixed issue where the Scan helper would fail if a `scroll` response returned without a value for `_shards.skipped` ([1451](elastic/elasticsearch-py#1451)) * Fixed handling of IPv6 hosts with a port in the computed ``Connection.host`` property ([1460](elastic/elasticsearch-py#1460)) * Fixed documented task management API stability, should have been "experimental" ([1471](elastic/elasticsearch-py#1471)) Changed * Changed deprecated `collections.Mapping` in favor of `collections.abc.Mapping` for Python 3.9 ([1443](elastic/elasticsearch-py#1443)) ``` ### 7.10.0 ``` Client Added * Added support for Elasticsearch 7.10 APIs * Added basic type stubs for static type checking and IDE auto-complete of API parameters ([1297](elastic/elasticsearch-py#1297), [#1406](elastic/elasticsearch-py#1406)) * Added support for [Optimistic Concurrency Control options](https://www.elastic.co/guide/en/elasticsearch/reference/current/optimistic-concurrency-control.html) (``_if_seq_no``/``_if_primary_term``) to bulk helpers ([#1387](elastic/elasticsearch-py#1387)) * Added support for passing ``_source`` with ``"_op_type": "update"`` bulk helpers ([1387](elastic/elasticsearch-py#1387)) * Added API stability to doc-strings of API methods and documentation ([1410](elastic/elasticsearch-py#1410)) Removed * Removed explicit ``yarl`` dependency from ``[async]`` extra to avoid issue where pip would override ``aiohttp``'s pin of ``yarl``. This was not a problem if you install with ``--use-feature=2020-resolver``. Users should see no changes. ([1401](elastic/elasticsearch-py#1401)) Fixed * Fixed bug where ``Connection.log_request_failure()`` call would receive the compressed HTTP body rather than uncompressed when an error is raised for ``RequestsHttpConnection`` ([1394](elastic/elasticsearch-py#1394)) * Fixed a typo in AsyncTransport where ``sniff_timeout`` was used instead of ``sniffer_timeout`` ([1431](elastic/elasticsearch-py#1431), contributed by HarrySky) Basic APIs Snapshot * Added `snapshot.clone` method Index * Added `require_alias` parameter to multiple index APIs X-Pack APIs Point in Time * Added `close_point_in_time` and `open_point_in_time` methods Security * Added `security.clear_api_key_cache` and `security.grant_api_key` methods Machine Learning * Deprecated `allow_no_jobs` parameter of `cat.ml_jobs` and `ml.close_job`, `ml.get_job_stats`, `ml.get_jobs`, `ml.get_overall_buckets` methods in favor of `allow_no_match` parameter * Deprecated `allow_no_datafeeds` parameter of `ml.get_datafeed_stats`, `ml.get_datafeeds`, `ml.stop_datafeed` in favor of `allow_no_match` parameter * Deprecated `include_model_definition` parameter of `ml.get_trained_models` method in favor of `include` parameter ``` ### 7.10.0a2 ``` Added * Added support for Elasticsearch 7.10 APIs * Added basic type stubs for static type checking and IDE auto-complete of API parameters ([1297](elastic/elasticsearch-py#1297), [#1406](elastic/elasticsearch-py#1406)) * Added support for [Optimistic Concurrency Control options](https://www.elastic.co/guide/en/elasticsearch/reference/current/optimistic-concurrency-control.html) (``_if_seq_no``/``_if_primary_term``) to bulk helpers ([#1387](elastic/elasticsearch-py#1387)) * Added support for passing ``_source`` with ``"_op_type": "update"`` bulk helpers ([1387](elastic/elasticsearch-py#1387)) Removed * Removed explicit ``yarl`` dependency from ``[async]`` extra to avoid issue where pip would override ``aiohttp``'s pin of ``yarl``. This was not a problem if you install with ``--use-feature=2020-resolver``. Users should see no changes. ([1401](elastic/elasticsearch-py#1401)) Fixed * Fixed bug where ``Connection.log_request_failure()`` call would receive the compressed HTTP body rather than uncompressed when an error is raised for ``RequestsHttpConnection`` ([1394](elastic/elasticsearch-py#1394)) ``` ### 7.10.0a1 ``` Added * Added support for Elasticsearch 7.10 APIs * Added basic type stubs for static type checking and IDE auto-complete of API parameters ([1297](elastic/elasticsearch-py#1297)) * Added support for [Optimistic Concurrency Control options](https://www.elastic.co/guide/en/elasticsearch/reference/current/optimistic-concurrency-control.html) (``_if_seq_no``/``_if_primary_term``) to bulk helpers ([#1387](elastic/elasticsearch-py#1387)) * Added support for passing ``_source`` with ``"_op_type": "update"`` bulk helpers ([1387](elastic/elasticsearch-py#1387)) Removed * Removed explicit ``yarl`` dependency from ``[async]`` extra to avoid issue where pip would override ``aiohttp``'s pin of ``yarl``. This was not a problem if you install with ``--use-feature=2020-resolver``. Users should see no changes. ([1401](elastic/elasticsearch-py#1401)) Fixed * Fixed bug where ``Connection.log_request_failure()`` call would receive the compressed HTTP body rather than uncompressed when an error is raised for ``RequestsHttpConnection`` ([1394](elastic/elasticsearch-py#1394)) ``` </details> <details> <summary>Links</summary> - PyPI: https://pypi.org/project/elasticsearch - Changelog: https://pyup.io/changelogs/elasticsearch/ - Repo: https://github.com/elastic/elasticsearch-py </details> Co-authored-by: pyup-bot <[email protected]>
This will allow us to overcome the issue with query_params in that it cloaks the signature of each API function when it comes to query params. This means that IDEs will be able to show the full set of parameters for each API. Also nowadays Python libraries are moving towards type checking and the community will start desiring this functionality. It's nice when things work well out of the box. :)
Type Stubs / Python 2 compatible inline type hints
.py
files.Interesting Places to Look
Anything that's not generated
All of these APIs were typed by hand, would appreciate reviews here the most.
Generated APIs
client/
and_async/client/
) aren't very interesting beyond the following:Any
unless I explicitly know what the type should be.HEAD
as an HTTP method returnsbool
because it's guaranteed to byTransport
.format
,human
,filter_path
,request_timeout
, etc)have an appropriate type hint applied to them unless they're also used by the API (in the case of
format
).Optional[Any]
instead ofAny
? They aren't the same.Aiohttp Catch 22
Since we have
aiohttp
andyarl
as optional dependencies we enter a catch-22 situation when it comes to mypy.# type: ignore
to the line withimport aiohttp
then there is no problem whenaiohttp
isn't installed (because mypy can't find the type hints) but when it is installed mypy will then complain with "You don't need that# type: ignore
comment" becauseaiohttp
ships its own type hints and mypy isn't detecting any problems with them.# type: ignore
to the import we have the reversed problem where there's no issue whenaiohttp
is imported but now mypy will complain that no type hints can be found when using--strict
mode. (As users should!)Solved this by adding
_async/_extra_imports.py
which basically importsaiohttp
andyarl
and adds a file-wide# type: ignore
which mypy will never complain about. Feels like a work-around but tbh I'm unsure there's any way around this without requiring users to configure their mypy individually which I'd prefer not to require.Requests gets around this unfortunate situation by being distributed within
typeshed
so mypy is always able to find type hints regardless of whether the package is installed or not. Verified this by deleting it's typeshed entry and the errors started occuring for requests as well.Added
AsyncConnection
Basically an abstract class that makes
perform_request()
andclose
async functions. If in the futurethere's another async HTTP connection class or if users want to define their own.
Type hints for AsyncGenerators
An async generator can be written like so:
but within a pyi file typically you don't include a function body which means we'll be missing the
yield
but mypy then complains that calls to
async for x in async_gen()
have typeCoroutine
. Instead we should do this:now the type signature matches exactly what the function is, a non-async function that returns an async generator.
External Project Type Checking Tests
Under
test_elasticsearch/test_types
I have two files, one async and one sync which import and exercise the APIsto see what it feels like as an external user of the library when using mypy type checking. I run with
[async]
installedagainst both async and sync and then uninstall
aiohttp
and run mypy against the sync with--strict
enabled to ensurewe're not leaking type errors to our users.
TODO
AIOHttpConnection.__init__
Closes #736