diff --git a/python/examples/flight/client.py b/python/examples/flight/client.py index ed6ce54ce62ea..75976674bf2e6 100644 --- a/python/examples/flight/client.py +++ b/python/examples/flight/client.py @@ -48,6 +48,9 @@ def list_flights(args, client, connection_args={}): else: print("Unknown") + print(f"Data are {'ordered' if flight.ordered else 'not ordered'}") + print("App metadata:", flight.app_metadata) + print("Number of endpoints:", len(flight.endpoints)) print("Schema:") print(flight.schema) diff --git a/python/pyarrow/_flight.pyx b/python/pyarrow/_flight.pyx index 8289215de2e29..ba6cdf273ac22 100644 --- a/python/pyarrow/_flight.pyx +++ b/python/pyarrow/_flight.pyx @@ -31,7 +31,7 @@ from libcpp cimport bool as c_bool from pyarrow.lib cimport * from pyarrow.lib import (ArrowCancelled, ArrowException, ArrowInvalid, SignalStopHandler) -from pyarrow.lib import as_buffer, frombytes, tobytes +from pyarrow.lib import as_buffer, frombytes, timestamp, tobytes from pyarrow.includes.libarrow_flight cimport * from pyarrow.ipc import _get_legacy_format_default, _ReadPandasMixin import pyarrow.lib as lib @@ -704,7 +704,7 @@ cdef class FlightEndpoint(_Weakrefable): cdef: CFlightEndpoint endpoint - def __init__(self, ticket, locations): + def __init__(self, ticket, locations, expiration_time=None, app_metadata=""): """Create a FlightEndpoint from a ticket and list of locations. Parameters @@ -713,6 +713,12 @@ cdef class FlightEndpoint(_Weakrefable): the ticket needed to access this flight locations : list of string URIs locations where this flight is available + expiration_time : TimestampScalar, default None + Expiration time of this stream. If present, clients may assume + they can retry DoGet requests. Otherwise, clients should avoid + retrying DoGet requests. + app_metadata : bytes or str, default "" + Application-defined opaque metadata. Raises ------ @@ -724,18 +730,40 @@ cdef class FlightEndpoint(_Weakrefable): if isinstance(ticket, Ticket): self.endpoint.ticket.ticket = tobytes(ticket.ticket) - else: + elif isinstance(ticket, (str, bytes)): self.endpoint.ticket.ticket = tobytes(ticket) + else: + raise TypeError("Argument ticket must be a Ticket instance, string or bytes, " + "not '{}'".format(type(ticket))) for location in locations: if isinstance(location, Location): c_location = ( location).location - else: + elif isinstance(location, (str, bytes)): c_location = CLocation() check_flight_status( CLocation.Parse(tobytes(location)).Value(&c_location)) + else: + raise TypeError("Argument locations must contain Location instances, strings or bytes, " + "not '{}'".format(type(location))) self.endpoint.locations.push_back(c_location) + if expiration_time is not None: + if isinstance(expiration_time, lib.TimestampScalar): + # Convert into OS-dependent std::chrono::system_clock::time_point from + # std::chrono::time_point + # See Timestamp in cpp/src/arrow/flight/types.h + self.endpoint.expiration_time = TimePoint_to_system_time(TimePoint_from_ns( + expiration_time.cast(timestamp("ns")).value)) + else: + raise TypeError("Argument expiration_time must be a TimestampScalar, " + "not '{}'".format(type(expiration_time))) + + if not isinstance(app_metadata, (str, bytes)): + raise TypeError("Argument app_metadata must be a string or bytes, " + "not '{}'".format(type(app_metadata))) + self.endpoint.app_metadata = tobytes(app_metadata) + @property def ticket(self): """Get the ticket in this endpoint.""" @@ -743,9 +771,34 @@ cdef class FlightEndpoint(_Weakrefable): @property def locations(self): + """Get locations where this flight is available.""" return [Location.wrap(location) for location in self.endpoint.locations] + @property + def expiration_time(self): + """Get the expiration time of this stream. + + If present, clients may assume they can retry DoGet requests. + Otherwise, clients should avoid retrying DoGet requests. + + """ + cdef: + int64_t time_since_epoch + if self.endpoint.expiration_time.has_value(): + time_since_epoch = TimePoint_to_ns( + # Convert from OS-dependent std::chrono::system_clock::time_point into + # std::chrono::time_point + # See Timestamp in cpp/src/arrow/flight/types.h + TimePoint_from_system_time(self.endpoint.expiration_time.value())) + return lib.scalar(time_since_epoch, timestamp("ns", "UTC")) + return None + + @property + def app_metadata(self): + """Get application-defined opaque metadata.""" + return self.endpoint.app_metadata + def serialize(self): """Get the wire-format representation of this type. @@ -770,7 +823,9 @@ cdef class FlightEndpoint(_Weakrefable): def __repr__(self): return (f"") + f"locations={self.locations!r} " + f"expiration_time={self.expiration_time} " + f"app_metadata={self.app_metadata}>") def __eq__(self, FlightEndpoint other): return self.endpoint == other.endpoint @@ -844,7 +899,7 @@ cdef class FlightInfo(_Weakrefable): return obj def __init__(self, Schema schema, FlightDescriptor descriptor, endpoints, - total_records, total_bytes): + total_records=None, total_bytes=None, ordered=False, app_metadata=""): """Create a FlightInfo object from a schema, descriptor, and endpoints. Parameters @@ -855,10 +910,14 @@ cdef class FlightInfo(_Weakrefable): the descriptor for this flight. endpoints : list of FlightEndpoint a list of endpoints where this flight is available. - total_records : int - the total records in this flight, or -1 if unknown - total_bytes : int - the total bytes in this flight, or -1 if unknown + total_records : int, default None + the total records in this flight, -1 or None if unknown. + total_bytes : int, default None + the total bytes in this flight, -1 or None if unknown. + ordered : boolean, default False + Whether endpoints are in the same order as the data. + app_metadata : bytes or str, default "" + Application-defined opaque metadata. """ cdef: shared_ptr[CSchema] c_schema = pyarrow_unwrap_schema(schema) @@ -874,8 +933,10 @@ cdef class FlightInfo(_Weakrefable): check_flight_status(CreateFlightInfo(c_schema, descriptor.descriptor, c_endpoints, - total_records, - total_bytes, &self.info)) + total_records if total_records is not None else -1, + total_bytes if total_bytes is not None else -1, + ordered, + tobytes(app_metadata), &self.info)) @property def total_records(self): @@ -887,6 +948,25 @@ cdef class FlightInfo(_Weakrefable): """The size in bytes of the data in this flight, or -1 if unknown.""" return self.info.get().total_bytes() + @property + def ordered(self): + """Whether endpoints are in the same order as the data.""" + return self.info.get().ordered() + + @property + def app_metadata(self): + """ + Application-defined opaque metadata. + + There is no inherent or required relationship between this and the + app_metadata fields in the FlightEndpoints or resulting FlightData + messages. Since this metadata is application-defined, a given + application could define there to be a relationship, but there is + none required by the spec. + + """ + return self.info.get().app_metadata() + @property def schema(self): """The schema of the data in this flight.""" @@ -950,7 +1030,9 @@ cdef class FlightInfo(_Weakrefable): f"descriptor={self.descriptor} " f"endpoints={self.endpoints} " f"total_records={self.total_records} " - f"total_bytes={self.total_bytes}>") + f"total_bytes={self.total_bytes} " + f"ordered={self.ordered} " + f"app_metadata={self.app_metadata}>") cdef class FlightStreamChunk(_Weakrefable): diff --git a/python/pyarrow/includes/chrono.pxd b/python/pyarrow/includes/chrono.pxd new file mode 100644 index 0000000000000..e5d22d19751d7 --- /dev/null +++ b/python/pyarrow/includes/chrono.pxd @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# distutils: language = c++ + + +cdef extern from "" namespace "std::chrono::system_clock": + cdef cppclass time_point: + pass diff --git a/python/pyarrow/includes/libarrow_flight.pxd b/python/pyarrow/includes/libarrow_flight.pxd index c4cf5830c4128..d2bc3c9d0da23 100644 --- a/python/pyarrow/includes/libarrow_flight.pxd +++ b/python/pyarrow/includes/libarrow_flight.pxd @@ -19,6 +19,7 @@ from pyarrow.includes.common cimport * from pyarrow.includes.libarrow cimport * +from pyarrow.includes.chrono cimport time_point cdef extern from "arrow/flight/api.h" namespace "arrow" nogil: @@ -134,6 +135,8 @@ cdef extern from "arrow/flight/api.h" namespace "arrow" nogil: CTicket ticket vector[CLocation] locations + optional[time_point] expiration_time + c_string app_metadata bint operator==(CFlightEndpoint) CResult[c_string] SerializeToString() @@ -146,6 +149,8 @@ cdef extern from "arrow/flight/api.h" namespace "arrow" nogil: CFlightInfo(CFlightInfo info) int64_t total_records() int64_t total_bytes() + c_bool ordered() + c_string app_metadata() CResult[shared_ptr[CSchema]] GetSchema(CDictionaryMemo* memo) CFlightDescriptor& descriptor() const vector[CFlightEndpoint]& endpoints() @@ -608,6 +613,8 @@ cdef extern from "arrow/python/flight.h" namespace "arrow::py::flight" nogil: vector[CFlightEndpoint] endpoints, int64_t total_records, int64_t total_bytes, + c_bool ordered, + const c_string& app_metadata, unique_ptr[CFlightInfo]* out) cdef CStatus CreateSchemaResult" arrow::py::flight::CreateSchemaResult"( diff --git a/python/pyarrow/includes/libarrow_python.pxd b/python/pyarrow/includes/libarrow_python.pxd index 96725c9c3862b..da5bca5edd584 100644 --- a/python/pyarrow/includes/libarrow_python.pxd +++ b/python/pyarrow/includes/libarrow_python.pxd @@ -17,6 +17,7 @@ # distutils: language = c++ +from pyarrow.includes.chrono cimport time_point from pyarrow.includes.common cimport * from pyarrow.includes.libarrow cimport * @@ -244,6 +245,9 @@ cdef extern from "arrow/python/api.h" namespace "arrow::py::internal" nogil: CTimePoint TimePoint_from_s(double val) CTimePoint TimePoint_from_ns(int64_t val) + CTimePoint TimePoint_from_system_time(time_point val) + time_point TimePoint_to_system_time(CTimePoint val) + CResult[c_string] TzinfoToString(PyObject* pytzinfo) CResult[PyObject*] StringToTzinfo(c_string) diff --git a/python/pyarrow/src/arrow/python/datetime.h b/python/pyarrow/src/arrow/python/datetime.h index 9b21eeb434217..3de5ea69fd9da 100644 --- a/python/pyarrow/src/arrow/python/datetime.h +++ b/python/pyarrow/src/arrow/python/datetime.h @@ -144,6 +144,20 @@ inline TimePoint TimePoint_from_ns(int64_t val) { return TimePoint(TimePoint::duration(val)); } +ARROW_PYTHON_EXPORT +// Note: Needed by FlightEndpoint.expiration_time, which is an OS-dependent +// std::chrono::system_clock::time_point +inline std::chrono::system_clock::time_point TimePoint_to_system_time(TimePoint val) { + return std::chrono::time_point_cast(val); +} + +ARROW_PYTHON_EXPORT +// Note: Needed by FlightEndpoint.expiration_time, which is an OS-dependent +// std::chrono::system_clock::time_point +inline TimePoint TimePoint_from_system_time(std::chrono::system_clock::time_point val) { + return std::chrono::time_point_cast(val); +} + ARROW_PYTHON_EXPORT inline int64_t PyDelta_to_s(PyDateTime_Delta* pytimedelta) { return (PyDateTime_DELTA_GET_DAYS(pytimedelta) * 86400LL + diff --git a/python/pyarrow/src/arrow/python/flight.cc b/python/pyarrow/src/arrow/python/flight.cc index bf7af27ac726e..ce5e6dfa94e3b 100644 --- a/python/pyarrow/src/arrow/python/flight.cc +++ b/python/pyarrow/src/arrow/python/flight.cc @@ -368,11 +368,12 @@ void PyClientMiddleware::CallCompleted(const Status& call_status) { Status CreateFlightInfo(const std::shared_ptr& schema, const arrow::flight::FlightDescriptor& descriptor, const std::vector& endpoints, - int64_t total_records, int64_t total_bytes, + int64_t total_records, int64_t total_bytes, bool ordered, + const std::string& app_metadata, std::unique_ptr* out) { - ARROW_ASSIGN_OR_RAISE(auto result, - arrow::flight::FlightInfo::Make(*schema, descriptor, endpoints, - total_records, total_bytes)); + ARROW_ASSIGN_OR_RAISE(auto result, arrow::flight::FlightInfo::Make( + *schema, descriptor, endpoints, total_records, + total_bytes, ordered, app_metadata)); *out = std::unique_ptr( new arrow::flight::FlightInfo(std::move(result))); return Status::OK(); diff --git a/python/pyarrow/src/arrow/python/flight.h b/python/pyarrow/src/arrow/python/flight.h index 5243258495778..57d21976bb7ae 100644 --- a/python/pyarrow/src/arrow/python/flight.h +++ b/python/pyarrow/src/arrow/python/flight.h @@ -337,7 +337,8 @@ ARROW_PYFLIGHT_EXPORT Status CreateFlightInfo(const std::shared_ptr& schema, const arrow::flight::FlightDescriptor& descriptor, const std::vector& endpoints, - int64_t total_records, int64_t total_bytes, + int64_t total_records, int64_t total_bytes, bool ordered, + const std::string& app_metadata, std::unique_ptr* out); /// \brief Create a SchemaResult from schema. diff --git a/python/pyarrow/tests/test_flight.py b/python/pyarrow/tests/test_flight.py index f0ceba37d6933..b3103c4be8c6d 100644 --- a/python/pyarrow/tests/test_flight.py +++ b/python/pyarrow/tests/test_flight.py @@ -27,6 +27,7 @@ import time import traceback import json +from datetime import datetime try: import numpy as np @@ -152,8 +153,7 @@ def list_flights(self, context, criteria): yield flight.FlightInfo( pa.schema([]), flight.FlightDescriptor.for_path('/foo'), - [], - -1, -1 + [] ) def do_get(self, context, ticket): @@ -251,10 +251,14 @@ def get_flight_info(self, context, descriptor): flight.FlightEndpoint( b'', [flight.Location.for_grpc_tcp('localhost', 5005)], + pa.scalar("2023-04-05T12:34:56.789012345").cast(pa.timestamp("ns")), + "endpoint app metadata" ), ], - -1, - -1, + 1, + 42, + True, + "info app metadata" ) def get_schema(self, context, descriptor): @@ -387,8 +391,7 @@ def list_flights(self, context, criteria): yield flight.FlightInfo( pa.schema([]), flight.FlightDescriptor.for_path('/foo'), - [], - -1, -1 + [] ) raise flight.FlightInternalError("foo") @@ -876,14 +879,18 @@ def test_repr(): descriptor_repr = "" endpoint_repr = (" " - "locations=[]>") + "locations=[] " + "expiration_time=2023-04-05 12:34:56+00:00 " + "app_metadata=b'endpoint app metadata'>") info_repr = ( " " "endpoints=[] " - "total_records=-1 " - "total_bytes=-1>") + "total_records=1 " + "total_bytes=42 " + "ordered=True " + "app_metadata=b'test app metadata'>") location_repr = "" result_repr = "" schema_result_repr = "" @@ -893,9 +900,15 @@ def test_repr(): assert repr(flight.ActionType("foo", "bar")) == action_type_repr assert repr(flight.BasicAuth("user", "pass")) == basic_auth_repr assert repr(flight.FlightDescriptor.for_command("foo")) == descriptor_repr - assert repr(flight.FlightEndpoint(b"foo", [])) == endpoint_repr + endpoint = flight.FlightEndpoint( + b"foo", [], pa.scalar("2023-04-05T12:34:56").cast(pa.timestamp("s")), + b"endpoint app metadata" + ) + assert repr(endpoint) == endpoint_repr info = flight.FlightInfo( - pa.schema([]), flight.FlightDescriptor.for_path(), [], -1, -1) + pa.schema([]), flight.FlightDescriptor.for_path(), [], + 1, 42, True, b"test app metadata" + ) assert repr(info) == info_repr assert repr(flight.Location("grpc+tcp://localhost:1234")) == location_repr assert repr(flight.Result(b"foo")) == result_repr @@ -907,25 +920,97 @@ def test_repr(): with pytest.raises(TypeError): flight.Action("foo", None) + with pytest.raises(TypeError): + flight.FlightEndpoint(object(), []) + with pytest.raises(TypeError): + flight.FlightEndpoint("foo", ["grpc://test", b"grpc://test", object()]) + with pytest.raises(TypeError): + flight.FlightEndpoint("foo", [], expiration_time="2023-04-05T01:02:03") + with pytest.raises(TypeError): + flight.FlightEndpoint("foo", [], expiration_time=datetime(2023, 4, 5, 1, 2, 3)) + with pytest.raises(TypeError): + flight.FlightEndpoint("foo", [], app_metadata=object()) + def test_eq(): items = [ + lambda: (flight.Action("foo", b""), flight.Action("bar", b"")), lambda: (flight.Action("foo", b""), flight.Action("foo", b"bar")), lambda: (flight.ActionType("foo", "bar"), flight.ActionType("foo", "baz")), lambda: (flight.BasicAuth("user", "pass"), flight.BasicAuth("user2", "pass")), + lambda: (flight.BasicAuth("user", "pass"), + flight.BasicAuth("user", "pass2")), lambda: (flight.FlightDescriptor.for_command("foo"), flight.FlightDescriptor.for_path("foo")), lambda: (flight.FlightEndpoint(b"foo", []), - flight.FlightEndpoint(b"", [])), + flight.FlightEndpoint(b"bar", [])), + lambda: ( + flight.FlightEndpoint( + b"foo", [flight.Location("grpc+tcp://localhost:1234")]), + flight.FlightEndpoint( + b"foo", [flight.Location("grpc+tls://localhost:1234")]) + ), + lambda: ( + flight.FlightEndpoint( + b"foo", [], pa.scalar("2023-04-05T12:34:56").cast(pa.timestamp("s"))), + flight.FlightEndpoint( + b"foo", [], + pa.scalar("2023-04-05T12:34:56.789").cast(pa.timestamp("ms")))), + lambda: (flight.FlightEndpoint(b"foo", [], app_metadata=b''), + flight.FlightEndpoint(b"foo", [], app_metadata=b'meta')), + lambda: ( + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), []), + flight.FlightInfo( + pa.schema([("ints", pa.int64())]), + flight.FlightDescriptor.for_path(), [])), + lambda: ( + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), []), + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_command(b"foo"), [])), lambda: ( flight.FlightInfo( pa.schema([]), - flight.FlightDescriptor.for_path(), [], -1, -1), + flight.FlightDescriptor.for_path(), + [flight.FlightEndpoint(b"foo", [])]), flight.FlightInfo( pa.schema([]), - flight.FlightDescriptor.for_command(b"foo"), [], -1, 42)), + flight.FlightDescriptor.for_path(), + [flight.FlightEndpoint(b"bar", [])])), + lambda: ( + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], total_records=-1), + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], total_records=1)), + lambda: ( + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], total_bytes=-1), + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], total_bytes=42)), + lambda: ( + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], ordered=False), + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], ordered=True)), + lambda: ( + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], app_metadata=b""), + flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], app_metadata=b"meta")), lambda: (flight.Location("grpc+tcp://localhost:1234"), flight.Location("grpc+tls://localhost:1234")), lambda: (flight.Result(b"foo"), flight.Result(b"bar")), @@ -937,11 +1022,33 @@ def test_eq(): for gen in items: lhs1, rhs1 = gen() lhs2, rhs2 = gen() + assert lhs1 == lhs1 assert lhs1 == lhs2 + assert lhs2 == lhs1 + assert rhs1 == rhs1 assert rhs1 == rhs2 + assert rhs2 == rhs1 assert lhs1 != rhs1 +def test_flight_info_defaults(): + fi1 = flight.FlightInfo(pa.schema([]), flight.FlightDescriptor.for_path(), []) + fi2 = flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], total_records=-1, total_bytes=-1) + fi3 = flight.FlightInfo( + pa.schema([]), + flight.FlightDescriptor.for_path(), [], total_records=None, total_bytes=None) + + assert fi1.total_records == -1 + assert fi2.total_records == -1 + assert fi3.total_records == -1 + + assert fi1.total_bytes == -1 + assert fi2.total_bytes == -1 + assert fi3.total_bytes == -1 + + def test_flight_server_location_argument(): locations = [ None, @@ -1062,12 +1169,30 @@ def test_flight_get_info(): with GetInfoFlightServer() as server: client = FlightClient(('localhost', server.port)) info = client.get_flight_info(flight.FlightDescriptor.for_command(b'')) - assert info.total_records == -1 - assert info.total_bytes == -1 + assert info.total_records == 1 + assert info.total_bytes == 42 + assert info.ordered + assert info.app_metadata == b"info app metadata" assert info.schema == pa.schema([('a', pa.int32())]) assert len(info.endpoints) == 2 assert len(info.endpoints[0].locations) == 1 + assert info.endpoints[0].expiration_time is None + assert info.endpoints[0].app_metadata == b"" assert info.endpoints[0].locations[0] == flight.Location('grpc://test') + # on macOS, system_clock::duration is milliseconds + # on Windows, system_clock::duration is 100 nanoseconds + # on Linux, system_clock::duration is nanoseconds + ts = None + if pa._platform.system() == 'Darwin': + ts = "2023-04-05T12:34:56.789012000+00:00" + elif pa._platform.system() == 'Windows': + ts = "2023-04-05T12:34:56.789012300+00:00" + elif pa._platform.system() == 'Linux': + ts = "2023-04-05T12:34:56.789012345+00:00" + if ts is not None: + assert info.endpoints[1].expiration_time == \ + pa.scalar(ts).cast(pa.timestamp("ns", "UTC")) + assert info.endpoints[1].app_metadata == b"endpoint app metadata" assert info.endpoints[1].locations[0] == \ flight.Location.for_grpc_tcp('localhost', 5005) @@ -1707,21 +1832,29 @@ def test_roundtrip_types(): flight.FlightEndpoint( b'', [flight.Location.for_grpc_tcp('localhost', 5005)], + pa.scalar("2023-04-05T12:34:56.789012345").cast(pa.timestamp("ns")), + b'endpoint app metadata' ), ], - -1, - -1, + 1, + 42, + True, + b'test app metadata' ) info2 = flight.FlightInfo.deserialize(info.serialize()) assert info.schema == info2.schema assert info.descriptor == info2.descriptor assert info.total_bytes == info2.total_bytes assert info.total_records == info2.total_records + assert info.ordered == info2.ordered + assert info.app_metadata == info2.app_metadata assert info.endpoints == info2.endpoints endpoint = flight.FlightEndpoint( ticket, - ['grpc://test', flight.Location.for_grpc_tcp('localhost', 5005)] + ['grpc://test', flight.Location.for_grpc_tcp('localhost', 5005)], + pa.scalar("2023-04-05T12:34:56").cast(pa.timestamp("s")), + b'endpoint app metadata' ) assert endpoint == flight.FlightEndpoint.deserialize(endpoint.serialize()) @@ -2366,8 +2499,7 @@ def get_flight_info(self, context, descriptor): return flight.FlightInfo( pa.schema([]), descriptor, - [], - -1, -1 + [] ) class HeadersTrailersMiddlewareFactory(ClientMiddlewareFactory): diff --git a/python/pyarrow/tests/test_flight_async.py b/python/pyarrow/tests/test_flight_async.py index f3cd1bbb58e2f..197c78cc07365 100644 --- a/python/pyarrow/tests/test_flight_async.py +++ b/python/pyarrow/tests/test_flight_async.py @@ -29,9 +29,7 @@ class ExampleServer(flight.FlightServerBase): simple_info = flight.FlightInfo( pyarrow.schema([("a", "int32")]), flight.FlightDescriptor.for_command(b"simple"), - [], - -1, - -1, + [] ) def get_flight_info(self, context, descriptor):