Repository: geopandas/geopandas
Pull request #3235 (2024-03-29 13:38:41)

COMPAT: adjust for new `copy`  behaviour of numpy.array / __array__
This should fix the one failing test for `astype` in the dev build


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d4539b99..254db876 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,8 @@ Notes on dependencies:
 - GeoPandas 1.0 drops support for shapely<2 and PyGEOS. The only geometry engine that is
   currently supported is shapely >= 2. As a consequence, spatial indexing based on the
   rtree package has also been removed. (#3035)
+- The I/O engine now defaults to Pyogrio which is now installed with GeoPandas instead
+  of Fiona. (#3223)
 
 API changes:
 
diff --git a/README.md b/README.md
index 6d5afa57..68b6b114 100644
--- a/README.md
+++ b/README.md
@@ -57,7 +57,7 @@ for all details. GeoPandas depends on the following packages:
 
 - ``pandas``
 - ``shapely``
-- ``fiona``
+- ``pyogrio``
 - ``pyproj``
 - ``packaging``
 
@@ -114,7 +114,7 @@ GeoPandas objects also know how to plot themselves. GeoPandas uses
 
     >>> g.plot()
 
-GeoPandas also implements alternate constructors that can read any data format recognized by [fiona](http://fiona.readthedocs.io/en/latest/). To read a zip file containing an ESRI shapefile with the [boroughs boundaries of New York City](https://data.cityofnewyork.us/City-Government/Borough-Boundaries/tqmj-j8zm) (the example can be fetched using the [`geodatasets`](https://geodatasets.readthedocs.io/en/latest/) package):
+GeoPandas also implements alternate constructors that can read any data format recognized by [pyogrio](http://pyogrio.readthedocs.io/en/latest/). To read a zip file containing an ESRI shapefile with the [boroughs boundaries of New York City](https://data.cityofnewyork.us/City-Government/Borough-Boundaries/tqmj-j8zm) (the example can be fetched using the [`geodatasets`](https://geodatasets.readthedocs.io/en/latest/) package):
 
     >>> import geodatasets
     >>> nybb_path = geodatasets.get_path('nybb')
diff --git a/asv.conf.json b/asv.conf.json
index 21a20246..0b044f0a 100644
--- a/asv.conf.json
+++ b/asv.conf.json
@@ -56,7 +56,7 @@
     "matrix": {
         "pandas": [],
         "shapely": [],
-        "fiona": [],
+        "pyogrio": [],
         "pyproj": [],
         "matplotlib": [],
     },
diff --git a/ci/envs/310-pd20-conda-forge.yaml b/ci/envs/310-pd20-conda-forge.yaml
index 91e55bc9..6d77f84d 100644
--- a/ci/envs/310-pd20-conda-forge.yaml
+++ b/ci/envs/310-pd20-conda-forge.yaml
@@ -7,7 +7,7 @@ dependencies:
   - pandas=2.0
   - numpy=1.24 # released 4 months before pandas 2.0
   - shapely
-  - fiona
+  - pyogrio
   - pyproj
   - packaging
   # testing
diff --git a/ci/envs/311-dev.yaml b/ci/envs/311-dev.yaml
index 313e8758..8a09de87 100644
--- a/ci/envs/311-dev.yaml
+++ b/ci/envs/311-dev.yaml
@@ -6,6 +6,7 @@ dependencies:
   - cython
   # required
   - pyproj
+  - gdal
   - geos
   - packaging
   # testing
@@ -32,3 +33,4 @@ dependencies:
     - git+https://github.com/python-visualization/folium.git@main
     - git+https://github.com/geopandas/xyzservices.git@main
     - git+https://github.com/geopandas/geodatasets.git@main
+    - git+https://github.com/geopandas/pyogrio.git@main
diff --git a/ci/envs/39-minimal.yaml b/ci/envs/39-minimal.yaml
index 50788a00..3406bdad 100644
--- a/ci/envs/39-minimal.yaml
+++ b/ci/envs/39-minimal.yaml
@@ -7,7 +7,7 @@ dependencies:
   - numpy=1.22
   - pandas=1.4
   - shapely=2.0.0
-  - fiona=1.8.21
+  # - pyogrio=0.7.2
   - packaging
   # testing
   - pytest
@@ -25,3 +25,4 @@ dependencies:
   - pip
   - pip:
     - pyproj==3.3.0
+    - pyogrio==0.7.2
diff --git a/ci/envs/39-no-optional-deps.yaml b/ci/envs/39-no-optional-deps.yaml
index cb6f036a..a6efcbe5 100644
--- a/ci/envs/39-no-optional-deps.yaml
+++ b/ci/envs/39-no-optional-deps.yaml
@@ -6,7 +6,7 @@ dependencies:
   # required
   - pandas
   - shapely
-  - fiona
+  - pyogrio>=0.7.2
   - pyproj
   - packaging
   # testing
diff --git a/ci/envs/39-pd15-defaults.yaml b/ci/envs/39-pd15-defaults.yaml
index fcfc7ab6..e78bb92f 100644
--- a/ci/envs/39-pd15-defaults.yaml
+++ b/ci/envs/39-pd15-defaults.yaml
@@ -6,7 +6,7 @@ dependencies:
   # required
   - pandas=1.5
   - shapely
-  - fiona
+  # - pyogrio # comes as 0.5.1
   - numpy=1.23
   - pyproj>=3.3.0
   - geos
@@ -23,6 +23,7 @@ dependencies:
   - libspatialite
   - pip
   - pip:
+      - pyogrio
       - geopy
       - mapclassify==2.4.0
       - pyarrow
diff --git a/doc/source/community/contributing.rst b/doc/source/community/contributing.rst
index 7187a9c5..56259d82 100644
--- a/doc/source/community/contributing.rst
+++ b/doc/source/community/contributing.rst
@@ -214,7 +214,7 @@ GeoPandas. If you used the provided environment in section 2, skip this
 step and continue to section 4. If you created the environment manually, we suggest installing
 dependencies using the following commands (executed after your development environment has been activated)::
 
-    conda install -c conda-forge pandas fiona shapely pyproj pytest
+    conda install -c conda-forge pandas pyogrio shapely pyproj pytest
 
 This should install all necessary dependencies.
 
diff --git a/doc/source/community/ecosystem.md b/doc/source/community/ecosystem.md
index 96429dd9..1ff83cdb 100644
--- a/doc/source/community/ecosystem.md
+++ b/doc/source/community/ecosystem.md
@@ -4,7 +4,7 @@
 
 GeoPandas brings together the full capability of `pandas` and the open-source geospatial
 tools `Shapely`, which brings manipulation and analysis of geometric objects backed by
-[`GEOS`](https://trac.osgeo.org/geos) library, `Fiona`, allowing us to read and write
+[`GEOS`](https://trac.osgeo.org/geos) library, `pyogrio`, allowing us to read and write
 geographic data files using [`GDAL`](https://gdal.org), and `pyproj`, a library for
 cartographic projections and coordinate transformations, which is a Python interface to
 [`PROJ`](https://proj.org).
@@ -29,14 +29,10 @@ geometric objects. It is based on the widely deployed `GEOS` (the engine of Post
 `JTS` (from which `GEOS` is ported) libraries. `Shapely` is not concerned with data
 formats or coordinate systems, but can be readily integrated with packages that are.
 
-#### [Fiona](https://github.com/Toblerity/Fiona)
-`Fiona` is `GDAL’s` neat and nimble vector API for Python programmers. Fiona is designed
-to be simple and dependable. It focuses on reading and writing data in standard Python
-IO style and relies upon familiar Python types and protocols such as files,
-dictionaries, mappings, and iterators instead of classes specific to `OGR`. Fiona can
-read and write real-world data using multi-layered GIS formats and zipped virtual file
-systems and integrates readily with other Python GIS packages such as `pyproj`, `Rtree`,
-and `Shapely`.
+#### [pyogrio](https://github.com/geopandas/pyogrio)
+Pyogrio provides a GeoPandas-oriented API to OGR vector data sources, such as ESRI
+Shapefile, GeoPackage, and GeoJSON. Vector data sources have geometries, such as points,
+lines, or polygons, and associated records with potentially many columns worth of data.
 
 #### [pyproj](https://github.com/pyproj4/pyproj)
 `pyproj` is a Python interface to `PROJ` (cartographic projections and coordinate
@@ -64,6 +60,15 @@ of hardcopy formats and interactive environments across platforms. Matplotlib ca
 used in Python scripts, the Python and IPython shell, web application servers, and
 various graphical user interface toolkits.
 
+#### [Fiona](https://github.com/Toblerity/Fiona)
+`Fiona` is `GDAL’s` neat and nimble vector API for Python programmers. Fiona is designed
+to be simple and dependable. It focuses on reading and writing data in standard Python
+IO style and relies upon familiar Python types and protocols such as files,
+dictionaries, mappings, and iterators instead of classes specific to `OGR`. Fiona can
+read and write real-world data using multi-layered GIS formats and zipped virtual file
+systems and integrates readily with other Python GIS packages such as `pyproj`, `Rtree`,
+and `Shapely`.
+
 ## GeoPandas ecosystem
 
 Various packages are built on top of GeoPandas addressing specific geospatial data
diff --git a/doc/source/docs/user_guide/geometric_manipulations.rst b/doc/source/docs/user_guide/geometric_manipulations.rst
index ac74c5a6..38447e31 100644
--- a/doc/source/docs/user_guide/geometric_manipulations.rst
+++ b/doc/source/docs/user_guide/geometric_manipulations.rst
@@ -62,7 +62,7 @@ Constructive methods
 
 .. method:: GeoSeries.remove_repeated_points
 
-   Returns a :class:`~geopandas.GeoSeries` containing a copy of the input geometry 
+   Returns a :class:`~geopandas.GeoSeries` containing a copy of the input geometry
    with repeated points removed.
 
 .. method:: GeoSeries.simplify(tolerance, preserve_topology=True)
@@ -153,7 +153,7 @@ GeoPandas objects also know how to plot themselves. GeoPandas uses `matplotlib`_
 
     >>> g.plot()
 
-GeoPandas also implements alternate constructors that can read any data format recognized by `Fiona`_.  To read a zip file containing an ESRI shapefile with the `borough boundaries of New York City`_ (GeoPandas includes this as an example dataset):
+GeoPandas also implements alternate constructors that can read any data format recognized by `Pyogrio`_.  To read a zip file containing an ESRI shapefile with the `borough boundaries of New York City`_ (provided by the ``geodatasets`` package):
 
 .. sourcecode:: python
 
@@ -257,7 +257,7 @@ borough that are in the holes:
     dtype: float64
 
 .. _matplotlib: http://matplotlib.org
-.. _fiona: http://fiona.readthedocs.io/en/latest/
+.. _pyogrio: http://pyogrio.readthedocs.io/en/latest/
 .. _geopy: https://github.com/geopy/geopy
 .. _geo_interface: https://gist.github.com/sgillies/2217756
 .. _borough boundaries of New York City: https://data.cityofnewyork.us/City-Government/Borough-Boundaries/tqmj-j8zm
diff --git a/doc/source/docs/user_guide/io.rst b/doc/source/docs/user_guide/io.rst
index 58aadb10..73f613c7 100644
--- a/doc/source/docs/user_guide/io.rst
+++ b/doc/source/docs/user_guide/io.rst
@@ -14,28 +14,17 @@ shapefile, GeoJSON files and more using the :func:`geopandas.read_file` command:
 which returns a GeoDataFrame object. This is possible because GeoPandas makes
 use of the massive open-source program called
 `GDAL/OGR <http://www.gdal.org/>`_ designed to facilitate spatial data
-transformations, through the Python packages `Fiona <http://fiona.readthedocs.io/en/latest/manual.html>`_
-or `pyogrio <https://pyogrio.readthedocs.io/en/stable/>`_, which both provide bindings to GDAL.
-
-.. note::
-
-    GeoPandas currently defaults to use Fiona as the engine in ``read_file``. However,
-    GeoPandas 1.0 will switch to use pyogrio as the default engine, since pyogrio can
-    provide a significant speedup compared to Fiona. We recommend to already install
-    pyogrio and specify the engine by using the ``engine`` keyword
-    (``geopandas.read_file(..., engine="pyogrio")``), or by setting the default for the
-    ``engine`` keyword globally with::
-
-        geopandas.options.io_engine = "pyogrio"
+transformations, through the Python packages `Pyogrio <https://pyogrio.readthedocs.io/en/stable/>`_
+or `Fiona <http://fiona.readthedocs.io/en/latest/manual.html>`_, which both provide bindings to GDAL.
 
 Any arguments passed to :func:`geopandas.read_file` after the file name will be
-passed directly to :func:`fiona.open` or :func:`pyogrio.read_dataframe`, which
+passed directly to :func:`pyogrio.read_dataframe` or :func:`fiona.open`, which
 does the actual data importation.
 In general, :func:`geopandas.read_file` is pretty smart and should do what you want
 without extra arguments, but for more help, type::
 
-    import fiona; help(fiona.open)
     import pyogrio; help(pyogrio.read_dataframe)
+    import fiona; help(fiona.open)
 
 Among other things, one can explicitly set the driver (shapefile, GeoJSON) with
 the ``driver`` keyword, or pick a single layer from a multi-layered file with
@@ -184,7 +173,12 @@ Load in a subset of data with a `SQL WHERE clause <https://gdal.org/user/ogr_sql
 Supported drivers
 ~~~~~~~~~~~~~~~~~
 
-Currently fiona only exposes the default drivers. To display those, type::
+When using pyogrio, all drivers supported by the GDAL installation are enabled,
+and you can check those with::
+
+    import pyogrio; pyogrio.list_drivers()
+
+Fiona only exposes the default drivers. To display those, type::
 
     import fiona; fiona.supported_drivers
 
@@ -194,18 +188,12 @@ these on runtime by updating the `supported_drivers` dictionary like::
 
     fiona.supported_drivers["NAS"] = "raw"
 
-When using pyogrio, all drivers supported by the GDAL installation are enabled,
-and you can check those with::
-
-    import pyogrio; pyogrio.list_drivers()
-
-
 Writing spatial data
 ---------------------
 
 GeoDataFrames can be exported to many different standard formats using the
 :meth:`geopandas.GeoDataFrame.to_file` method.
-For a full list of supported formats, type ``import fiona; fiona.supported_drivers``.
+For a full list of supported formats, type ``import pyogrio; pyogrio.list_drivers()``.
 
 In addition, GeoDataFrames can be uploaded to `PostGIS <https://postgis.net/>`__ database (starting with GeoPandas 0.8)
 by using the :meth:`geopandas.GeoDataFrame.to_postgis` method.
@@ -218,8 +206,8 @@ by using the :meth:`geopandas.GeoDataFrame.to_postgis` method.
 
 .. note::
 
-    One GeoDataFrame can contain multiple geometry (GeoSeries) columns, but most standard GIS file formats, e.g. GeoPackage or ESRI Shapefile, 
-    support only a single geometry column. To store multiple geometry columns, non-active GeoSeries need to be converted to 
+    One GeoDataFrame can contain multiple geometry (GeoSeries) columns, but most standard GIS file formats, e.g. GeoPackage or ESRI Shapefile,
+    support only a single geometry column. To store multiple geometry columns, non-active GeoSeries need to be converted to
     an alternative representation like well-known text (WKT) or well-known binary (WKB) before saving to file. Alternatively, they can be saved as an Apache (Geo)Parquet or Feather file, both of which support multiple geometry columns natively.
 
 **Writing to Shapefile**::
diff --git a/doc/source/getting_started/install.rst b/doc/source/getting_started/install.rst
index d5db47b9..b6b1d112 100644
--- a/doc/source/getting_started/install.rst
+++ b/doc/source/getting_started/install.rst
@@ -92,7 +92,7 @@ as well::
     When using pip to install GeoPandas, you need to make sure that all dependencies are
     installed correctly.
 
-    Our main dependencies (`shapely`_, `pyproj`_, `fiona`_, `pyogrio`_) provide binary
+    Our main dependencies (`shapely`_, `pyproj`_, `pyogrio`_) provide binary
     wheels with dependencies included for Mac, Linux, and Windows.
 
     However, depending on your platform or Python version, there might be no
@@ -130,7 +130,7 @@ the need to have all dependencies correctly installed applies. But, those
 dependencies can also be installed independently with conda before installing
 GeoPandas from source::
 
-    conda install pandas fiona shapely pyproj
+    conda install pandas pyogrio shapely pyproj
 
 See the :ref:`section on conda <install-conda>` above for more details on
 getting running with Anaconda.
@@ -145,13 +145,13 @@ Required dependencies:
 - `numpy`_
 - `pandas`_ (version 1.4 or later)
 - `shapely`_ (interface to `GEOS`_; version 2.0.0 or later)
-- `fiona`_ (interface to `GDAL`_; version 1.8.21 or later)
+- `pyogrio`_ (interface to `GDAL`_; version 0.7.2 or later)
 - `pyproj`_ (interface to `PROJ`_; version 3.3.0 or later)
 - `packaging`_
 
 Further, optional dependencies are:
 
-- `pyogrio`_ (optional; faster alternative for fiona, will become the default in GeoPandas 1.0)
+- `fiona`_ (optional; slower alternative to `pyogrio`)
 - `psycopg`_ (optional; for PostGIS connection)
 - `psycopg2`_ (optional; for PostGIS connection - older version of `psycopg` library)
 - `GeoAlchemy2`_ (optional; for writing to PostGIS)
diff --git a/doc/source/index.rst b/doc/source/index.rst
index d36504e8..c8866ace 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -7,11 +7,11 @@ GeoPandas is an open source project to make working with geospatial
 data in python easier.  GeoPandas extends the datatypes used by
 `pandas`_ to allow spatial operations on geometric types.  Geometric
 operations are performed by `shapely`_.  Geopandas further depends on
-`fiona`_ for file access and `matplotlib`_ for plotting.
+`pyogrio`_ for file access and `matplotlib`_ for plotting.
 
 .. _pandas: http://pandas.pydata.org
 .. _shapely: https://shapely.readthedocs.io
-.. _fiona: https://fiona.readthedocs.io
+.. _pyogrio: https://pyogrio.readthedocs.io
 .. _matplotlib: http://matplotlib.org
 
 Description
diff --git a/environment-dev.yml b/environment-dev.yml
index db5f53d7..62e2ffc6 100644
--- a/environment-dev.yml
+++ b/environment-dev.yml
@@ -4,7 +4,7 @@ channels:
 dependencies:
     - python
     # required
-    - fiona>=1.8.21
+    - pyogrio>=0.7.2
     - pandas>=1.3.0
     - pyproj>=3.3.0
     - shapely>=2.0.0
diff --git a/environment.yml b/environment.yml
index b3702c22..44b7251f 100644
--- a/environment.yml
+++ b/environment.yml
@@ -4,7 +4,7 @@ channels:
 dependencies:
   - geopandas
   - shapely
-  - fiona
+  - pyogrio
   - pyproj
   - mapclassify
   - libpysal
diff --git a/geopandas/array.py b/geopandas/array.py
index 5ce017f6..7d18a9dd 100644
--- a/geopandas/array.py
+++ b/geopandas/array.py
@@ -1288,7 +1288,13 @@ class GeometryArray(ExtensionArray):
                 return pd.array(string_values, dtype=pd_dtype)
             return string_values.astype(dtype, copy=False)
         else:
-            return np.array(self, dtype=dtype, copy=copy)
+            # numpy 2.0 makes copy=False case strict (errors if cannot avoid the copy)
+            # -> in that case use `np.asarray` as backwards compatible alternative
+            # for `copy=None` (when requiring numpy 2+, this can be cleaned up)
+            if not copy:
+                return np.asarray(self, dtype=dtype)
+            else:
+                return np.array(self, dtype=dtype, copy=copy)
 
     def isna(self):
         """
@@ -1615,7 +1621,7 @@ class GeometryArray(ExtensionArray):
             f"does not support reduction '{name}'"
         )
 
-    def __array__(self, dtype=None):
+    def __array__(self, dtype=None, copy=None):
         """
         The numpy array interface.
 
@@ -1623,7 +1629,9 @@ class GeometryArray(ExtensionArray):
         -------
         values : numpy array
         """
-        return to_shapely(self)
+        if copy and (dtype is None or dtype == np.dtype("object")):
+            return self._data.copy()
+        return self._data
 
     def _binop(self, other, op):
         def convert_values(param):
diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py
index 790d371d..3364f2c6 100644
--- a/geopandas/geodataframe.py
+++ b/geopandas/geodataframe.py
@@ -540,17 +540,17 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
         It is recommended to use :func:`geopandas.read_file` instead.
 
         Can load a ``GeoDataFrame`` from a file in any format recognized by
-        `fiona`. See http://fiona.readthedocs.io/en/latest/manual.html for details.
+        `pyogrio`. See http://pyogrio.readthedocs.io/ for details.
 
         Parameters
         ----------
         filename : str
             File path or file handle to read from. Depending on which kwargs
             are included, the content of filename may vary. See
-            http://fiona.readthedocs.io/en/latest/README.html#usage for usage details.
+            :func:`pyogrio.read_dataframe` for usage details.
         kwargs : key-word arguments
-            These arguments are passed to fiona.open, and can be used to
-            access multi-layer data, data stored within archives (zip files),
+            These arguments are passed to :func:`pyogrio.read_dataframe`, and can be
+            used to access multi-layer data, data stored within archives (zip files),
             etc.
 
         Examples
@@ -1218,11 +1218,11 @@ properties': {'col1': 'name1'}, 'geometry': {'type': 'Point', 'coordinates': (1.
         """Write the ``GeoDataFrame`` to a file.
 
         By default, an ESRI shapefile is written, but any OGR data source
-        supported by Fiona can be written. A dictionary of supported OGR
+        supported by Pyogrio or Fiona can be written. A dictionary of supported OGR
         providers is available via:
 
-        >>> import fiona
-        >>> fiona.supported_drivers  # doctest: +SKIP
+        >>> import pyogrio
+        >>> pyogrio.list_drivers()  # doctest: +SKIP
 
         Parameters
         ----------
@@ -1257,18 +1257,19 @@ properties': {'col1': 'name1'}, 'geometry': {'type': 'Point', 'coordinates': (1.
             will determine the crs based on crs df attribute.
             The value can be anything accepted
             by :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
-            such as an authority string (eg "EPSG:4326") or a WKT string.
-        engine : str, "fiona" or "pyogrio"
+            such as an authority string (eg "EPSG:4326") or a WKT string. The keyword
+            is not supported for the "pyogrio" engine.
+        engine : str, "pyogrio" or "fiona"
             The underlying library that is used to write the file. Currently, the
-            supported options are "fiona" and "pyogrio". Defaults to "fiona" if
-            installed, otherwise tries "pyogrio".
+            supported options are "pyogrio" and "fiona". Defaults to "pyogrio" if
+            installed, otherwise tries "fiona".
         **kwargs :
             Keyword args to be passed to the engine, and can be used to write
             to multi-layer data, store data within archives (zip files), etc.
-            In case of the "fiona" engine, the keyword arguments are passed to
-            fiona.open`. For more information on possible keywords, type:
-            ``import fiona; help(fiona.open)``. In case of the "pyogrio" engine,
-            the keyword arguments are passed to `pyogrio.write_dataframe`.
+            In case of the "pyogrio" engine, the keyword arguments are passed to
+            `pyogrio.write_dataframe`. In case of the "fiona" engine, the keyword
+            arguments are passed to fiona.open`. For more information on possible
+            keywords, type: ``import pyogrio; help(pyogrio.write_dataframe)``.
 
         Notes
         -----
diff --git a/geopandas/geoseries.py b/geopandas/geoseries.py
index 8ff2faa5..a9523d9d 100644
--- a/geopandas/geoseries.py
+++ b/geopandas/geoseries.py
@@ -325,7 +325,7 @@ class GeoSeries(GeoPandasBase, Series):
         """Alternate constructor to create a ``GeoSeries`` from a file.
 
         Can load a ``GeoSeries`` from a file from any format recognized by
-        `fiona`. See http://fiona.readthedocs.io/en/latest/manual.html for details.
+        `pyogrio`. See http://pyogrio.readthedocs.io/ for details.
         From a file with attributes loads only geometry column. Note that to do
         that, GeoPandas first loads the whole GeoDataFrame.
 
@@ -334,10 +334,10 @@ class GeoSeries(GeoPandasBase, Series):
         filename : str
             File path or file handle to read from. Depending on which kwargs
             are included, the content of filename may vary. See
-            http://fiona.readthedocs.io/en/latest/README.html#usage for usage details.
+            :func:`pyogrio.read_dataframe` for usage details.
         kwargs : key-word arguments
-            These arguments are passed to fiona.open, and can be used to
-            access multi-layer data, data stored within archives (zip files),
+            These arguments are passed to :func:`pyogrio.read_dataframe`, and can be
+            used to access multi-layer data, data stored within archives (zip files),
             etc.
 
         Examples
@@ -577,7 +577,7 @@ class GeoSeries(GeoPandasBase, Series):
         """Write the ``GeoSeries`` to a file.
 
         By default, an ESRI shapefile is written, but any OGR data source
-        supported by Fiona can be written.
+        supported by Pyogrio or Fiona can be written.
 
         Parameters
         ----------
@@ -607,18 +607,19 @@ class GeoSeries(GeoPandasBase, Series):
             will determine the crs based on crs df attribute.
             The value can be anything accepted
             by :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
-            such as an authority string (eg "EPSG:4326") or a WKT string.
-        engine : str, "fiona" or "pyogrio"
+            such as an authority string (eg "EPSG:4326") or a WKT string. The keyword
+            is not supported for the "pyogrio" engine.
+        engine : str, "pyogrio" or "fiona"
             The underlying library that is used to write the file. Currently, the
-            supported options are "fiona" and "pyogrio". Defaults to "fiona" if
-            installed, otherwise tries "pyogrio".
+            supported options are "pyogrio" and "fiona". Defaults to "pyogrio" if
+            installed, otherwise tries "fiona".
         **kwargs :
             Keyword args to be passed to the engine, and can be used to write
             to multi-layer data, store data within archives (zip files), etc.
-            In case of the "fiona" engine, the keyword arguments are passed to
-            fiona.open`. For more information on possible keywords, type:
-            ``import fiona; help(fiona.open)``. In case of the "pyogrio" engine,
-            the keyword arguments are passed to `pyogrio.write_dataframe`.
+            In case of the "pyogrio" engine, the keyword arguments are passed to
+            `pyogrio.write_dataframe`. In case of the "fiona" engine, the keyword
+            arguments are passed to fiona.open`. For more information on possible
+            keywords, type: ``import pyogrio; help(pyogrio.write_dataframe)``.
 
         See Also
         --------
diff --git a/geopandas/io/file.py b/geopandas/io/file.py
index 74bcd894..f4d8262b 100644
--- a/geopandas/io/file.py
+++ b/geopandas/io/file.py
@@ -66,20 +66,16 @@ def _import_fiona():
 
 pyogrio = None
 pyogrio_import_error = None
-PYOGRIO_GE_07 = False
 
 
 def _import_pyogrio():
     global pyogrio
     global pyogrio_import_error
-    global PYOGRIO_GE_07
 
     if pyogrio is None:
         try:
             import pyogrio
 
-            PYOGRIO_GE_07 = Version(pyogrio.__version__) >= Version("0.7.0")
-
         except ImportError as err:
             pyogrio = False
             pyogrio_import_error = str(err)
@@ -103,34 +99,34 @@ def _check_pyogrio(func):
 
 
 def _check_engine(engine, func):
-    # if not specified through keyword or option, then default to "fiona" if
-    # installed, otherwise try pyogrio
+    # if not specified through keyword or option, then default to "pyogrio" if
+    # installed, otherwise try fiona
     if engine is None:
         import geopandas
 
         engine = geopandas.options.io_engine
 
     if engine is None:
-        _import_fiona()
-        if fiona:
-            engine = "fiona"
+        _import_pyogrio()
+        if pyogrio:
+            engine = "pyogrio"
         else:
-            _import_pyogrio()
-            if pyogrio:
-                engine = "pyogrio"
+            _import_fiona()
+            if fiona:
+                engine = "fiona"
 
-    if engine == "fiona":
-        _import_fiona()
-        _check_fiona(func)
-    elif engine == "pyogrio":
+    if engine == "pyogrio":
         _import_pyogrio()
         _check_pyogrio(func)
+    elif engine == "fiona":
+        _import_fiona()
+        _check_fiona(func)
     elif engine is None:
         raise ImportError(
             f"The {func} requires the 'pyogrio' or 'fiona' package, "
             "but neither is installed or imports correctly."
-            f"\nImporting fiona resulted in: {fiona_import_error}"
             f"\nImporting pyogrio resulted in: {pyogrio_import_error}"
+            f"\nImporting fiona resulted in: {fiona_import_error}"
         )
 
     return engine
@@ -183,17 +179,6 @@ def _read_file(
     """
     Returns a GeoDataFrame from a file or URL.
 
-    .. note::
-
-        GeoPandas currently defaults to use Fiona as the engine in ``read_file``.
-        However, GeoPandas 1.0 will switch to use pyogrio as the default engine, since
-        pyogrio can provide a significant speedup compared to Fiona. We recommend to
-        already install pyogrio and specify the engine by using the ``engine`` keyword
-        (``geopandas.read_file(..., engine="pyogrio")``), or by setting the default for
-        the ``engine`` keyword globally with::
-
-            geopandas.options.io_engine = "pyogrio"
-
     Parameters
     ----------
     filename : str, path object or file-like object
@@ -220,17 +205,18 @@ def _read_file(
     rows : int or slice, default None
         Load in specific rows by passing an integer (first `n` rows) or a
         slice() object.
-    engine : str, "fiona" or "pyogrio"
+    engine : str,  "pyogrio" or "fiona"
         The underlying library that is used to read the file. Currently, the
-        supported options are "fiona" and "pyogrio". Defaults to "fiona" if
-        installed, otherwise tries "pyogrio".
+        supported options are "pyogrio" and "fiona". Defaults to "pyogrio" if
+        installed, otherwise tries "fiona". Engine can also be set globally
+        with the ``geopandas.options.io_engine`` option.
     **kwargs :
-        Keyword args to be passed to the engine. In case of the "fiona" engine,
-        the keyword arguments are passed to :func:`fiona.open` or
-        :class:`fiona.collection.BytesCollection` when opening the file.
-        For more information on possible keywords, type:
-        ``import fiona; help(fiona.open)``. In case of the "pyogrio" engine,
-        the keyword arguments are passed to :func:`pyogrio.read_dataframe`.
+        Keyword args to be passed to the engine, and can be used to write
+        to multi-layer data, store data within archives (zip files), etc.
+        In case of the "pyogrio" engine, the keyword arguments are passed to
+        `pyogrio.write_dataframe`. In case of the "fiona" engine, the keyword
+        arguments are passed to fiona.open`. For more information on possible
+        keywords, type: ``import pyogrio; help(pyogrio.write_dataframe)``.
 
 
     Examples
@@ -493,11 +479,6 @@ def _read_file_pyogrio(path_or_bytes, bbox=None, mask=None, rows=None, **kwargs)
 
     if mask is not None:
         # NOTE: mask cannot be used at same time as bbox keyword
-        if not PYOGRIO_GE_07:
-            raise ValueError(
-                "The 'mask' keyword requires pyogrio >= 0.7.0.  "
-                "You can use 'bbox' instead."
-            )
         if isinstance(mask, (GeoDataFrame, GeoSeries)):
             crs = pyogrio.read_info(path_or_bytes).get("crs")
             if isinstance(path_or_bytes, IOBase):
@@ -585,19 +566,9 @@ def _to_file(
     Write this GeoDataFrame to an OGR data source
 
     A dictionary of supported OGR providers is available via:
-    >>> import fiona
-    >>> fiona.supported_drivers  # doctest: +SKIP
-
-    .. note::
 
-        GeoPandas currently defaults to use Fiona as the engine in ``to_file``.
-        However, GeoPandas 1.0 will switch to use pyogrio as the default engine, since
-        pyogrio can provide a significant speedup compared to Fiona. We recommend to
-        already install pyogrio and specify the engine by using the ``engine`` keyword
-        (``df.to_file(..., engine="pyogrio")``), or by setting the default for
-        the ``engine`` keyword globally with::
-
-            geopandas.options.io_engine = "pyogrio"
+    >>> import pyogrio
+    >>> pyogrio.list_drivers()  # doctest: +SKIP
 
     Parameters
     ----------
@@ -639,10 +610,11 @@ def _to_file(
         The value can be anything accepted
         by :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
         such as an authority string (eg "EPSG:4326") or a WKT string.
-    engine : str, "fiona" or "pyogrio"
-        The underlying library that is used to write the file. Currently, the
-        supported options are "fiona" and "pyogrio". Defaults to "fiona" if
-        installed, otherwise tries "pyogrio".
+    engine : str,  "pyogrio" or "fiona"
+        The underlying library that is used to read the file. Currently, the
+        supported options are "pyogrio" and "fiona". Defaults to "pyogrio" if
+        installed, otherwise tries "fiona". Engine can also be set globally
+        with the ``geopandas.options.io_engine`` option.
     **kwargs :
         Keyword args to be passed to the engine, and can be used to write
         to multi-layer data, store data within archives (zip files), etc.
@@ -690,10 +662,10 @@ def _to_file(
     if mode not in ("w", "a"):
         raise ValueError(f"'mode' should be one of 'w' or 'a', got '{mode}' instead")
 
-    if engine == "fiona":
-        _to_file_fiona(df, filename, driver, schema, crs, mode, **kwargs)
-    elif engine == "pyogrio":
+    if engine == "pyogrio":
         _to_file_pyogrio(df, filename, driver, schema, crs, mode, **kwargs)
+    elif engine == "fiona":
+        _to_file_fiona(df, filename, driver, schema, crs, mode, **kwargs)
     else:
         raise ValueError(f"unknown engine '{engine}'")
 
diff --git a/geopandas/tools/_show_versions.py b/geopandas/tools/_show_versions.py
index 04a87ac5..26d02f3a 100644
--- a/geopandas/tools/_show_versions.py
+++ b/geopandas/tools/_show_versions.py
@@ -58,33 +58,27 @@ def _get_C_info():
             geos_dir = None
 
     try:
-        import fiona
+        import pyogrio
 
-        gdal_version = fiona.env.get_gdal_release_name()
+        gdal_version = pyogrio.__gdal_version_string__
+        gdal_dir = pyogrio.get_gdal_data_path()
     except Exception:
         gdal_version = None
-    try:
-        import fiona
-
-        gdal_dir = fiona.env.GDALDataFinder().search()
-    except Exception:
         gdal_dir = None
 
     if gdal_version is None:
         try:
-            import pyogrio
+            import fiona
 
-            gdal_version = pyogrio.__gdal_version_string__
-            gdal_dir = None
+            gdal_version = fiona.env.get_gdal_release_name()
         except Exception:
-            pass
+            gdal_version = None
         try:
-            # get_gdal_data_path is only available in pyogrio >= 0.4.2
-            from pyogrio import get_gdal_data_path
+            import fiona
 
-            gdal_dir = get_gdal_data_path()
+            gdal_dir = fiona.env.GDALDataFinder().search()
         except Exception:
-            pass
+            gdal_dir = None
 
     blob = [
         ("GEOS", geos_version),
@@ -114,12 +108,12 @@ def _get_deps_info():
         "pyproj",
         "shapely",
         # optional deps
-        "fiona",
+        "pyogrio",
         "geoalchemy2",
         "geopy",
         "matplotlib",
         "mapclassify",
-        "pyogrio",
+        "fiona",
         "psycopg",
         "psycopg2",
         "pyarrow",
diff --git a/pyproject.toml b/pyproject.toml
index 382829fb..a7833131 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -21,7 +21,7 @@ classifiers = [
 ]
 requires-python = ">=3.9"
 dependencies = [
-    "fiona >= 1.8.21",
+    "pyogrio >= 0.7.2",
     "packaging",
     "pandas >= 1.4.0",
     "pyproj >= 3.3.0",
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 4808fbf5..a4b33520 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -1,5 +1,5 @@
 # required
-fiona>=1.8.21
+pyogrio>=0.7.2
 pandas>=1.4.0
 pyproj>=3.3.0
 shapely>=2.0.0


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 6cc121b8..021843b4 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -40,14 +40,14 @@ jobs:
           - ci/envs/39-pd15-defaults.yaml
           - ci/envs/39-latest-defaults.yaml
           - ci/envs/39-latest-conda-forge.yaml
-          - ci/envs/39-latest-conda-forge_no_fiona.yaml
+          - ci/envs/39-latest-conda-forge_no_pyogrio.yaml
           - ci/envs/310-pd20-conda-forge.yaml
           - ci/envs/310-latest-conda-forge.yaml
           - ci/envs/311-latest-conda-forge.yaml
           - ci/envs/312-latest-conda-forge.yaml
           - ci/envs/312-latest-conda-forge_no_pyproj.yaml
         include:
-          - env: ci/envs/39-latest-conda-forge_no_fiona.yaml
+          - env: ci/envs/39-latest-conda-forge_no_pyogrio.yaml
             os: macos-latest
             postgis: false
             dev: false
@@ -55,7 +55,7 @@ jobs:
             os: macos-latest
             postgis: false
             dev: false
-          - env: ci/envs/39-latest-conda-forge_no_fiona.yaml
+          - env: ci/envs/39-latest-conda-forge_no_pyogrio.yaml
             os: windows-latest
             postgis: false
             dev: false
diff --git a/ci/envs/310-latest-conda-forge.yaml b/ci/envs/310-latest-conda-forge.yaml
index 5cb064f7..ceed4640 100644
--- a/ci/envs/310-latest-conda-forge.yaml
+++ b/ci/envs/310-latest-conda-forge.yaml
@@ -6,7 +6,7 @@ dependencies:
   # required
   - pandas
   - shapely
-  - fiona
+  - pyogrio
   - pyproj
   - packaging
   # testing
@@ -30,7 +30,7 @@ dependencies:
   - libspatialite
   - geoalchemy2
   - pyarrow
-  # - pyogrio
+  - fiona
   # doctest testing
   - pytest-doctestplus
   - pip
diff --git a/ci/envs/311-latest-conda-forge.yaml b/ci/envs/311-latest-conda-forge.yaml
index c5d1a091..3158fd8c 100644
--- a/ci/envs/311-latest-conda-forge.yaml
+++ b/ci/envs/311-latest-conda-forge.yaml
@@ -6,7 +6,7 @@ dependencies:
   # required
   - pandas
   - shapely
-  - fiona
+  - pyogrio
   - pyproj
   - packaging
   # testing
@@ -15,7 +15,7 @@ dependencies:
   - pytest-xdist
   - fsspec
   # optional
-  - pyogrio
+  - fiona
   - matplotlib
   - mapclassify
   - folium
diff --git a/ci/envs/312-latest-conda-forge.yaml b/ci/envs/312-latest-conda-forge.yaml
index 2d108dbb..bc5c8cb4 100644
--- a/ci/envs/312-latest-conda-forge.yaml
+++ b/ci/envs/312-latest-conda-forge.yaml
@@ -6,7 +6,7 @@ dependencies:
   # required
   - pandas
   - shapely
-  - fiona
+  - pyogrio
   - pyproj
   - packaging
   # testing
@@ -15,7 +15,7 @@ dependencies:
   - pytest-xdist
   - fsspec
   # optional
-  - pyogrio
+  - fiona
   - matplotlib
   - mapclassify
   - folium
diff --git a/ci/envs/312-latest-conda-forge_no_pyproj.yaml b/ci/envs/312-latest-conda-forge_no_pyproj.yaml
index 82ec8506..e995ab29 100644
--- a/ci/envs/312-latest-conda-forge_no_pyproj.yaml
+++ b/ci/envs/312-latest-conda-forge_no_pyproj.yaml
@@ -6,7 +6,7 @@ dependencies:
   # required
   - pandas
   - shapely
-  - fiona
+  # - pyogrio
   # - pyproj
   - packaging
   # testing
@@ -15,7 +15,7 @@ dependencies:
   - pytest-xdist
   - fsspec
   # optional
-  # - pyogrio
+  - fiona
   - matplotlib
   - mapclassify
   - folium
diff --git a/ci/envs/39-latest-conda-forge.yaml b/ci/envs/39-latest-conda-forge.yaml
index 891f9495..a9b8201f 100644
--- a/ci/envs/39-latest-conda-forge.yaml
+++ b/ci/envs/39-latest-conda-forge.yaml
@@ -8,7 +8,7 @@ dependencies:
   - shapely=2
   - geos
   - cython
-  - fiona
+  - pyogrio>=0.7.2
   - pyproj
   # use this build to have one with only shapely 2.0 installed
   - packaging
diff --git a/ci/envs/39-latest-conda-forge_no_fiona.yaml b/ci/envs/39-latest-conda-forge_no_pyogrio.yaml
similarity index 89%
rename from ci/envs/39-latest-conda-forge_no_fiona.yaml
rename to ci/envs/39-latest-conda-forge_no_pyogrio.yaml
index a81986f1..f7c48b01 100644
--- a/ci/envs/39-latest-conda-forge_no_fiona.yaml
+++ b/ci/envs/39-latest-conda-forge_no_pyogrio.yaml
@@ -6,7 +6,7 @@ dependencies:
   # required
   - pandas
   - shapely
-  # - fiona  # build with only pyogrio
+  # - pyogrio  # build with only fiona
   - libgdal
   - pyproj
   - packaging
@@ -25,6 +25,6 @@ dependencies:
   - SQLalchemy
   - libspatialite
   - pyarrow
-  - pyogrio
+  - fiona
   - pointpats
   - geodatasets
diff --git a/ci/envs/39-latest-defaults.yaml b/ci/envs/39-latest-defaults.yaml
index 6353ecea..f682653f 100644
--- a/ci/envs/39-latest-defaults.yaml
+++ b/ci/envs/39-latest-defaults.yaml
@@ -7,7 +7,7 @@ dependencies:
   - numpy
   - pandas
   - shapely
-  - fiona
+  # - pyogrio # comes as 0.5.1
   - pyproj>=3.3.0
   - geos
   - packaging
@@ -23,6 +23,7 @@ dependencies:
   - libspatialite
   - pip
   - pip:
+      - pyogrio
       - geopy
       - mapclassify
       - pyarrow
diff --git a/geopandas/io/tests/test_file.py b/geopandas/io/tests/test_file.py
index 2904eb85..cd1475fd 100644
--- a/geopandas/io/tests/test_file.py
+++ b/geopandas/io/tests/test_file.py
@@ -24,10 +24,8 @@ from geopandas.tests.util import PACKAGE_DIR, validate_boro_df
 try:
     import pyogrio
 
-    PYOGRIO_GE_07 = Version(pyogrio.__version__) >= Version("0.7.0")
 except ImportError:
     pyogrio = False
-    PYOGRIO_GE_07 = False
 
 
 try:
@@ -64,11 +62,6 @@ def skip_pyogrio_not_supported(engine):
         pytest.skip("not supported for the pyogrio engine")
 
 
-def skip_pyogrio_lt_07(engine):
-    if engine == "pyogrio" and not PYOGRIO_GE_07:
-        pytest.skip("requires pyogrio >= 0.7.0")
-
-
 @pytest.fixture
 def df_nybb(engine, nybb_filename):
     df = read_file(nybb_filename, engine=engine)
@@ -205,8 +198,6 @@ datetime_type_tests = (TEST_DATE, eastern.localize(TEST_DATE))
 @pytest.mark.parametrize("driver,ext", driver_ext_pairs)
 def test_to_file_datetime(tmpdir, driver, ext, time, engine):
     """Test writing a data file with the datetime column type"""
-    if engine == "pyogrio" and time.tzinfo is not None and not PYOGRIO_GE_07:
-        pytest.skip("pyogrio < 0.7.0 doesn't support timezones")
     if ext in (".shp", ""):
         pytest.skip(f"Driver corresponding to ext {ext} doesn't support dt fields")
 
@@ -250,7 +241,7 @@ def write_invalid_date_file(date_str, tmpdir, ext, engine):
     )
     # Schema not required for GeoJSON since not typed, but needed for GPKG
     if ext == "geojson":
-        df.to_file(tempfilename)
+        df.to_file(tempfilename, engine=engine)
     else:
         schema = {"geometry": "Point", "properties": {"date": "datetime"}}
         if engine == "pyogrio" and not fiona:
@@ -265,7 +256,7 @@ def test_read_file_datetime_invalid(tmpdir, ext, engine):
     # https://github.com/geopandas/geopandas/issues/2502
     date_str = "9999-99-99T00:00:00"  # invalid date handled by GDAL
     tempfilename = write_invalid_date_file(date_str, tmpdir, ext, engine)
-    res = read_file(tempfilename)
+    res = read_file(tempfilename, engine=engine)
     if ext == "gpkg":
         assert is_datetime64_any_dtype(res["date"])
         assert pd.isna(res["date"].iloc[-1])
@@ -276,10 +267,12 @@ def test_read_file_datetime_invalid(tmpdir, ext, engine):
 
 @pytest.mark.parametrize("ext", dt_exts)
 def test_read_file_datetime_out_of_bounds_ns(tmpdir, ext, engine):
+    if engine == "pyogrio" and not PANDAS_GE_20:
+        pytest.skip("with pyogrio requires pandas >= 2.0 to pass")
     # https://github.com/geopandas/geopandas/issues/2502
     date_str = "9999-12-31T00:00:00"  # valid to GDAL, not to [ns] format
     tempfilename = write_invalid_date_file(date_str, tmpdir, ext, engine)
-    res = read_file(tempfilename)
+    res = read_file(tempfilename, engine=engine)
     # Pandas invalid datetimes are read in as object dtype (strings)
     assert res["date"].dtype == "object"
     assert isinstance(res["date"].iloc[0], str)
@@ -302,12 +295,11 @@ def test_read_file_datetime_mixed_offsets(tmpdir):
     res = read_file(tempfilename)
     # Convert mixed timezones to UTC equivalent
     assert is_datetime64_any_dtype(res["date"])
-    if engine == "fiona" or (engine == "pyogrio" and PYOGRIO_GE_07):
-        if not PANDAS_GE_20:
-            utc = pytz.utc
-        else:
-            utc = datetime.timezone.utc
-        assert res["date"].dt.tz == utc
+    if not PANDAS_GE_20:
+        utc = pytz.utc
+    else:
+        utc = datetime.timezone.utc
+    assert res["date"].dt.tz == utc
 
 
 @pytest.mark.parametrize("driver,ext", driver_ext_pairs)
@@ -743,13 +735,7 @@ def test_read_file_filtered__rows_bbox(df_nybb, engine, nybb_filename):
         1047224.3104931959,
         244317.30894023244,
     )
-    if engine == "pyogrio" and not PYOGRIO_GE_07:
-        with pytest.raises(ValueError, match="'skip_features' must be between 0 and 1"):
-            # combination bbox and rows (rows slice applied after bbox filtering!)
-            filtered_df = read_file(
-                nybb_filename, bbox=bbox, rows=slice(4, None), engine=engine
-            )
-    else:  # fiona
+    if engine == "fiona":
         # combination bbox and rows (rows slice applied after bbox filtering!)
         filtered_df = read_file(
             nybb_filename, bbox=bbox, rows=slice(4, None), engine=engine
@@ -956,7 +942,6 @@ def test_read_file_bbox_gdf(df_nybb, engine, nybb_filename, file_like):
 @pytest.mark.skipif(not HAS_PYPROJ, reason="pyproj not installed")
 @pytest.mark.parametrize("file_like", [False, True])
 def test_read_file_mask_gdf(df_nybb, engine, nybb_filename, file_like):
-    skip_pyogrio_lt_07(engine)
     full_df_shape = df_nybb.shape
     mask = geopandas.GeoDataFrame(
         geometry=[
@@ -979,7 +964,6 @@ def test_read_file_mask_gdf(df_nybb, engine, nybb_filename, file_like):
 
 
 def test_read_file_mask_polygon(df_nybb, engine, nybb_filename):
-    skip_pyogrio_lt_07(engine)
     full_df_shape = df_nybb.shape
     mask = box(
         1031051.7879884212, 224272.49231459625, 1047224.3104931959, 244317.30894023244
@@ -991,7 +975,6 @@ def test_read_file_mask_polygon(df_nybb, engine, nybb_filename):
 
 
 def test_read_file_mask_geojson(df_nybb, nybb_filename, engine):
-    skip_pyogrio_lt_07(engine)
     full_df_shape = df_nybb.shape
     mask = mapping(
         box(
@@ -1009,7 +992,6 @@ def test_read_file_mask_geojson(df_nybb, nybb_filename, engine):
 
 @pytest.mark.skipif(not HAS_PYPROJ, reason="pyproj not installed")
 def test_read_file_bbox_gdf_mismatched_crs(df_nybb, engine, nybb_filename):
-    skip_pyogrio_lt_07(engine)
     full_df_shape = df_nybb.shape
     bbox = geopandas.GeoDataFrame(
         geometry=[
@@ -1031,7 +1013,6 @@ def test_read_file_bbox_gdf_mismatched_crs(df_nybb, engine, nybb_filename):
 
 @pytest.mark.skipif(not HAS_PYPROJ, reason="pyproj not installed")
 def test_read_file_mask_gdf_mismatched_crs(df_nybb, engine, nybb_filename):
-    skip_pyogrio_lt_07(engine)
     full_df_shape = df_nybb.shape
     mask = geopandas.GeoDataFrame(
         geometry=[
@@ -1052,8 +1033,6 @@ def test_read_file_mask_gdf_mismatched_crs(df_nybb, engine, nybb_filename):
 
 
 def test_read_file_bbox_mask_not_allowed(engine, nybb_filename):
-    skip_pyogrio_lt_07(engine)
-
     bbox = (
         1031051.7879884212,
         224272.49231459625,
diff --git a/geopandas/io/tests/test_file_geom_types_drivers.py b/geopandas/io/tests/test_file_geom_types_drivers.py
index d500d964..867271a1 100644
--- a/geopandas/io/tests/test_file_geom_types_drivers.py
+++ b/geopandas/io/tests/test_file_geom_types_drivers.py
@@ -302,7 +302,22 @@ def test_to_file_roundtrip(tmpdir, geodataframe, ogr_driver, engine):
                 output_file, driver=driver, engine=engine, **write_kwargs
             )
     else:
-        geodataframe.to_file(output_file, driver=driver, engine=engine, **write_kwargs)
+        if driver == "SQLite" and engine == "pyogrio":
+            try:
+                geodataframe.to_file(
+                    output_file, driver=driver, engine=engine, **write_kwargs
+                )
+            except ValueError as e:
+                if "unrecognized option 'SPATIALITE'" in str(e):
+                    pytest.xfail(
+                        "pyogrio wheels from PyPI do not come with SpatiaLite support. "
+                        f"Error: {e}"
+                    )
+                raise
+        else:
+            geodataframe.to_file(
+                output_file, driver=driver, engine=engine, **write_kwargs
+            )
 
         reloaded = geopandas.read_file(output_file, engine=engine)