Repository: apache/arrow-rs
Pull request #6765 (2024-11-20 22:52:22)

Minor: Update release schedule on README
# Which issue does this PR close?

- Related to https://github.com/apache/arrow-rs/issues/6342

# Rationale for this change
 
Update release calendar for predictable software delivery

# What changes are included in this PR?

<!--
There is no need to duplicate the description in the issue here but it is sometimes worth providing a summary of the individual changes in this PR.
-->

# Are there any user-facing changes?


<!--
If there are user-facing changes then we may require documentation to be updated before approving the PR.
-->

<!---
If there are any breaking changes to public APIs, please call them out.
-->



Patch:
diff --git a/README.md b/README.md
index 98c0a6615..3b16629d6 100644
--- a/README.md
+++ b/README.md
@@ -67,11 +67,11 @@ Planned Release Schedule
 
 | Approximate Date | Version  | Notes                                   |
 | ---------------- | -------- | --------------------------------------- |
-| Sep 2024         | `53.0.0` | Major, potentially breaking API changes |
-| Oct 2024         | `53.1.0` | Minor, NO breaking API changes          |
-| Oct 2024         | `53.2.0` | Minor, NO breaking API changes          |
 | Nov 2024         | `53.3.0` | Minor, NO breaking API changes          |
 | Dec 2024         | `54.0.0` | Major, potentially breaking API changes |
+| Jan 2025         | `54.1.0` | Minor, NO breaking API changes          |
+| Feb 2025         | `54.2.0` | Minor, NO breaking API changes          |
+| Mar 2025         | `55.0.0` | Major, potentially breaking API changes |
 
 [this ticket]: https://github.com/apache/arrow-rs/issues/5368
 [semantic versioning]: https://semver.org/
diff --git a/arrow-arith/LICENSE.txt b/arrow-arith/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-arith/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-arith/NOTICE.txt b/arrow-arith/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-arith/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-array/LICENSE.txt b/arrow-array/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-array/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-array/NOTICE.txt b/arrow-array/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-array/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-array/src/temporal_conversions.rs b/arrow-array/src/temporal_conversions.rs
index 8d238b3a1..23f950d55 100644
--- a/arrow-array/src/temporal_conversions.rs
+++ b/arrow-array/src/temporal_conversions.rs
@@ -37,8 +37,18 @@ pub const MILLISECONDS_IN_DAY: i64 = SECONDS_IN_DAY * MILLISECONDS;
 pub const MICROSECONDS_IN_DAY: i64 = SECONDS_IN_DAY * MICROSECONDS;
 /// Number of nanoseconds in a day
 pub const NANOSECONDS_IN_DAY: i64 = SECONDS_IN_DAY * NANOSECONDS;
-/// Number of days between 0001-01-01 and 1970-01-01
-pub const EPOCH_DAYS_FROM_CE: i32 = 719_163;
+
+/// Constant from chrono crate
+///
+/// Number of days between Januari 1, 1970 and December 31, 1 BCE which we define to be day 0.
+/// 4 full leap year cycles until December 31, 1600     4 * 146097 = 584388
+/// 1 day until January 1, 1601                                           1
+/// 369 years until Januari 1, 1970                      369 * 365 = 134685
+/// of which floor(369 / 4) are leap years          floor(369 / 4) =     92
+/// except for 1700, 1800 and 1900                                       -3 +
+///                                                                  --------
+///                                                                  719163
+pub const UNIX_EPOCH_DAY: i64 = 719_163;
 
 /// converts a `i32` representing a `date32` to [`NaiveDateTime`]
 #[inline]
@@ -134,6 +144,31 @@ pub fn timestamp_s_to_datetime(v: i64) -> Option<NaiveDateTime> {
     Some(DateTime::from_timestamp(v, 0)?.naive_utc())
 }
 
+/// Similar to timestamp_s_to_datetime but only compute `date`
+#[inline]
+pub fn timestamp_s_to_date(secs: i64) -> Option<NaiveDateTime> {
+    let days = secs.div_euclid(86_400) + UNIX_EPOCH_DAY;
+    if days < i32::MIN as i64 || days > i32::MAX as i64 {
+        return None;
+    }
+    let date = NaiveDate::from_num_days_from_ce_opt(days as i32)?;
+    Some(date.and_time(NaiveTime::default()).and_utc().naive_utc())
+}
+
+/// Similar to timestamp_s_to_datetime but only compute `time`
+#[inline]
+pub fn timestamp_s_to_time(secs: i64) -> Option<NaiveDateTime> {
+    let secs = secs.rem_euclid(86_400);
+    let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, 0)?;
+    Some(
+        DateTime::<Utc>::from_naive_utc_and_offset(
+            NaiveDateTime::new(NaiveDate::default(), time),
+            Utc,
+        )
+        .naive_utc(),
+    )
+}
+
 /// converts a `i64` representing a `timestamp(ms)` to [`NaiveDateTime`]
 #[inline]
 pub fn timestamp_ms_to_datetime(v: i64) -> Option<NaiveDateTime> {
@@ -274,10 +309,28 @@ pub fn as_duration<T: ArrowPrimitiveType>(v: i64) -> Option<Duration> {
 mod tests {
     use crate::temporal_conversions::{
         date64_to_datetime, split_second, timestamp_ms_to_datetime, timestamp_ns_to_datetime,
+        timestamp_s_to_date, timestamp_s_to_datetime, timestamp_s_to_time,
         timestamp_us_to_datetime, NANOSECONDS,
     };
     use chrono::DateTime;
 
+    #[test]
+    fn test_timestamp_func() {
+        let timestamp = 1234;
+        let datetime = timestamp_s_to_datetime(timestamp).unwrap();
+        let expected_date = datetime.date();
+        let expected_time = datetime.time();
+
+        assert_eq!(
+            timestamp_s_to_date(timestamp).unwrap().date(),
+            expected_date
+        );
+        assert_eq!(
+            timestamp_s_to_time(timestamp).unwrap().time(),
+            expected_time
+        );
+    }
+
     #[test]
     fn negative_input_timestamp_ns_to_datetime() {
         assert_eq!(
diff --git a/arrow-avro/LICENSE.txt b/arrow-avro/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-avro/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-avro/NOTICE.txt b/arrow-avro/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-avro/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-buffer/LICENSE.txt b/arrow-buffer/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-buffer/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-buffer/NOTICE.txt b/arrow-buffer/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-buffer/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-cast/LICENSE.txt b/arrow-cast/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-cast/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-cast/NOTICE.txt b/arrow-cast/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-cast/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-csv/LICENSE.txt b/arrow-csv/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-csv/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-csv/NOTICE.txt b/arrow-csv/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-csv/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-data/LICENSE.txt b/arrow-data/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-data/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-data/NOTICE.txt b/arrow-data/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-data/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-flight/LICENSE.txt b/arrow-flight/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-flight/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-flight/NOTICE.txt b/arrow-flight/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-flight/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-flight/src/utils.rs b/arrow-flight/src/utils.rs
index f6129ddfe..c3a2e0d0b 100644
--- a/arrow-flight/src/utils.rs
+++ b/arrow-flight/src/utils.rs
@@ -17,8 +17,7 @@
 
 //! Utilities to assist with reading and writing Arrow data as Flight messages
 
-use crate::{FlightData, IpcMessage, SchemaAsIpc, SchemaResult};
-use bytes::Bytes;
+use crate::{FlightData, SchemaAsIpc};
 use std::collections::HashMap;
 use std::sync::Arc;
 
@@ -104,41 +103,6 @@ pub fn flight_data_to_arrow_batch(
         })?
 }
 
-/// Convert a `Schema` to `SchemaResult` by converting to an IPC message
-#[deprecated(
-    since = "4.4.0",
-    note = "Use From trait, e.g.: SchemaAsIpc::new(schema, options).try_into()"
-)]
-pub fn flight_schema_from_arrow_schema(
-    schema: &Schema,
-    options: &IpcWriteOptions,
-) -> Result<SchemaResult, ArrowError> {
-    SchemaAsIpc::new(schema, options).try_into()
-}
-
-/// Convert a `Schema` to `FlightData` by converting to an IPC message
-#[deprecated(
-    since = "4.4.0",
-    note = "Use From trait, e.g.: SchemaAsIpc::new(schema, options).into()"
-)]
-pub fn flight_data_from_arrow_schema(schema: &Schema, options: &IpcWriteOptions) -> FlightData {
-    SchemaAsIpc::new(schema, options).into()
-}
-
-/// Convert a `Schema` to bytes in the format expected in `FlightInfo.schema`
-#[deprecated(
-    since = "4.4.0",
-    note = "Use TryFrom trait, e.g.: SchemaAsIpc::new(schema, options).try_into()"
-)]
-pub fn ipc_message_from_arrow_schema(
-    schema: &Schema,
-    options: &IpcWriteOptions,
-) -> Result<Bytes, ArrowError> {
-    let message = SchemaAsIpc::new(schema, options).try_into()?;
-    let IpcMessage(vals) = message;
-    Ok(vals)
-}
-
 /// Convert `RecordBatch`es to wire protocol `FlightData`s
 pub fn batches_to_flight_data(
     schema: &Schema,
diff --git a/arrow-ipc/LICENSE.txt b/arrow-ipc/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-ipc/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-ipc/NOTICE.txt b/arrow-ipc/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-ipc/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-json/LICENSE.txt b/arrow-json/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-json/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-json/NOTICE.txt b/arrow-json/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-json/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-ord/LICENSE.txt b/arrow-ord/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-ord/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-ord/NOTICE.txt b/arrow-ord/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-ord/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-row/LICENSE.txt b/arrow-row/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-row/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-row/NOTICE.txt b/arrow-row/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-row/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-schema/LICENSE.txt b/arrow-schema/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-schema/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-schema/NOTICE.txt b/arrow-schema/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-schema/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-select/LICENSE.txt b/arrow-select/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-select/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-select/NOTICE.txt b/arrow-select/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-select/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-string/LICENSE.txt b/arrow-string/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-string/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-string/NOTICE.txt b/arrow-string/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-string/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow/Cargo.toml b/arrow/Cargo.toml
index a0fd96415..732819cf0 100644
--- a/arrow/Cargo.toml
+++ b/arrow/Cargo.toml
@@ -54,7 +54,7 @@ arrow-select = { workspace = true }
 arrow-string = { workspace = true }
 
 rand = { version = "0.8", default-features = false, features = ["std", "std_rng"], optional = true }
-pyo3 = { version = "0.22.2", default-features = false, optional = true }
+pyo3 = { version = "0.23", default-features = false, optional = true }
 
 chrono = { workspace = true, optional = true }
 
diff --git a/arrow/LICENSE.txt b/arrow/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow/NOTICE.txt b/arrow/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow/src/pyarrow.rs b/arrow/src/pyarrow.rs
index 6effe1c03..4ccbd0541 100644
--- a/arrow/src/pyarrow.rs
+++ b/arrow/src/pyarrow.rs
@@ -111,7 +111,7 @@ impl<T: ToPyArrow> IntoPyArrow for T {
 }
 
 fn validate_class(expected: &str, value: &Bound<PyAny>) -> PyResult<()> {
-    let pyarrow = PyModule::import_bound(value.py(), "pyarrow")?;
+    let pyarrow = PyModule::import(value.py(), "pyarrow")?;
     let class = pyarrow.getattr(expected)?;
     if !value.is_instance(&class)? {
         let expected_module = class.getattr("__module__")?.extract::<PyBackedStr>()?;
@@ -177,7 +177,7 @@ impl ToPyArrow for DataType {
     fn to_pyarrow(&self, py: Python) -> PyResult<PyObject> {
         let c_schema = FFI_ArrowSchema::try_from(self).map_err(to_py_err)?;
         let c_schema_ptr = &c_schema as *const FFI_ArrowSchema;
-        let module = py.import_bound("pyarrow")?;
+        let module = py.import("pyarrow")?;
         let class = module.getattr("DataType")?;
         let dtype = class.call_method1("_import_from_c", (c_schema_ptr as Py_uintptr_t,))?;
         Ok(dtype.into())
@@ -213,7 +213,7 @@ impl ToPyArrow for Field {
     fn to_pyarrow(&self, py: Python) -> PyResult<PyObject> {
         let c_schema = FFI_ArrowSchema::try_from(self).map_err(to_py_err)?;
         let c_schema_ptr = &c_schema as *const FFI_ArrowSchema;
-        let module = py.import_bound("pyarrow")?;
+        let module = py.import("pyarrow")?;
         let class = module.getattr("Field")?;
         let dtype = class.call_method1("_import_from_c", (c_schema_ptr as Py_uintptr_t,))?;
         Ok(dtype.into())
@@ -249,7 +249,7 @@ impl ToPyArrow for Schema {
     fn to_pyarrow(&self, py: Python) -> PyResult<PyObject> {
         let c_schema = FFI_ArrowSchema::try_from(self).map_err(to_py_err)?;
         let c_schema_ptr = &c_schema as *const FFI_ArrowSchema;
-        let module = py.import_bound("pyarrow")?;
+        let module = py.import("pyarrow")?;
         let class = module.getattr("Schema")?;
         let schema = class.call_method1("_import_from_c", (c_schema_ptr as Py_uintptr_t,))?;
         Ok(schema.into())
@@ -309,7 +309,7 @@ impl ToPyArrow for ArrayData {
         let array = FFI_ArrowArray::new(self);
         let schema = FFI_ArrowSchema::try_from(self.data_type()).map_err(to_py_err)?;
 
-        let module = py.import_bound("pyarrow")?;
+        let module = py.import("pyarrow")?;
         let class = module.getattr("Array")?;
         let array = class.call_method1(
             "_import_from_c",
@@ -318,7 +318,7 @@ impl ToPyArrow for ArrayData {
                 addr_of!(schema) as Py_uintptr_t,
             ),
         )?;
-        Ok(array.to_object(py))
+        Ok(array.unbind())
     }
 }
 
@@ -335,7 +335,7 @@ impl<T: ToPyArrow> ToPyArrow for Vec<T> {
             .iter()
             .map(|v| v.to_pyarrow(py))
             .collect::<PyResult<Vec<_>>>()?;
-        Ok(values.to_object(py))
+        Ok(PyList::new(py, values)?.unbind().into())
     }
 }
 
@@ -451,7 +451,7 @@ impl FromPyArrow for ArrowArrayStreamReader {
         // make the conversion through PyArrow's private API
         // this changes the pointer's memory and is thus unsafe.
         // In particular, `_export_to_c` can go out of bounds
-        let args = PyTuple::new_bound(value.py(), [stream_ptr as Py_uintptr_t]);
+        let args = PyTuple::new(value.py(), [stream_ptr as Py_uintptr_t])?;
         value.call_method1("_export_to_c", args)?;
 
         let stream_reader = ArrowArrayStreamReader::try_new(stream)
@@ -469,9 +469,9 @@ impl IntoPyArrow for Box<dyn RecordBatchReader + Send> {
         let mut stream = FFI_ArrowArrayStream::new(self);
 
         let stream_ptr = (&mut stream) as *mut FFI_ArrowArrayStream;
-        let module = py.import_bound("pyarrow")?;
+        let module = py.import("pyarrow")?;
         let class = module.getattr("RecordBatchReader")?;
-        let args = PyTuple::new_bound(py, [stream_ptr as Py_uintptr_t]);
+        let args = PyTuple::new(py, [stream_ptr as Py_uintptr_t])?;
         let reader = class.call_method1("_import_from_c", args)?;
 
         Ok(PyObject::from(reader))
@@ -500,11 +500,17 @@ impl<'source, T: FromPyArrow> FromPyObject<'source> for PyArrowType<T> {
     }
 }
 
-impl<T: IntoPyArrow> IntoPy<PyObject> for PyArrowType<T> {
-    fn into_py(self, py: Python) -> PyObject {
+impl<'py, T: IntoPyArrow> IntoPyObject<'py> for PyArrowType<T> {
+    type Target = PyAny;
+
+    type Output = Bound<'py, Self::Target>;
+
+    type Error = PyErr;
+
+    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, PyErr> {
         match self.0.into_pyarrow(py) {
-            Ok(obj) => obj,
-            Err(err) => err.to_object(py),
+            Ok(obj) => Result::Ok(obj.into_bound(py)),
+            Err(err) => Result::Err(err),
         }
     }
 }
diff --git a/parquet/LICENSE.txt b/parquet/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/parquet/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/parquet/NOTICE.txt b/parquet/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/parquet/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/parquet_derive/LICENSE.txt b/parquet_derive/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/parquet_derive/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/parquet_derive/NOTICE.txt b/parquet_derive/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/parquet_derive/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file


Test patch:
diff --git a/arrow-integration-test/LICENSE.txt b/arrow-integration-test/LICENSE.txt
new file mode 120000
index 000000000..4ab43736a
--- /dev/null
+++ b/arrow-integration-test/LICENSE.txt
@@ -0,0 +1,1 @@
+../LICENSE.txt
\ No newline at end of file
diff --git a/arrow-integration-test/NOTICE.txt b/arrow-integration-test/NOTICE.txt
new file mode 120000
index 000000000..eb9f24e04
--- /dev/null
+++ b/arrow-integration-test/NOTICE.txt
@@ -0,0 +1,1 @@
+../NOTICE.txt
\ No newline at end of file
diff --git a/arrow-pyarrow-integration-testing/Cargo.toml b/arrow-pyarrow-integration-testing/Cargo.toml
index 0834f2d13..03d08df30 100644
--- a/arrow-pyarrow-integration-testing/Cargo.toml
+++ b/arrow-pyarrow-integration-testing/Cargo.toml
@@ -34,4 +34,4 @@ crate-type = ["cdylib"]
 
 [dependencies]
 arrow = { path = "../arrow", features = ["pyarrow"] }
-pyo3 = { version = "0.22", features = ["extension-module"] }
+pyo3 = { version = "0.23", features = ["extension-module"] }
diff --git a/arrow-pyarrow-integration-testing/src/lib.rs b/arrow-pyarrow-integration-testing/src/lib.rs
index e12c1389e..d4908fff0 100644
--- a/arrow-pyarrow-integration-testing/src/lib.rs
+++ b/arrow-pyarrow-integration-testing/src/lib.rs
@@ -43,7 +43,7 @@ fn to_py_err(err: ArrowError) -> PyErr {
 #[pyfunction]
 fn double(array: &Bound<PyAny>, py: Python) -> PyResult<PyObject> {
     // import
-    let array = make_array(ArrayData::from_pyarrow_bound(&array)?);
+    let array = make_array(ArrayData::from_pyarrow_bound(array)?);
 
     // perform some operation
     let array = array