diff --git a/docs/history.rst b/docs/history.rst index ad7fbfafa..85e59d03a 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -6,27 +6,27 @@ Change Log * Minimum supported Python version 3.6 (issue #499) * Minimum PROJ version 7.2 (issues #599 & #689) * WHL: Removed datumgrids from wheels because not needed with RFC 4 (pull #628) -* Refactor Proj to inherit from Transformer (issue #624) +* ENH: Added :ref:`network` (#675, #691, #695) +* ENH: Added ability to use global context (issue #661) +* ENH: Added transformation grid sync API/CLI (issue #572) * ENH: Support obects with '__array__' method (pandas.Series, xarray.DataArray, dask.array.Array) (issue #573) * ENH: Added :func:`pyproj.datadir.get_user_data_dir` (pull #636) -* ENH: Added network methods to Transformer (issue #629) -* ENH: Use 'proj_get_units_from_database' in :func:`pyproj.get_units_map` & cleanup :func:`pyproj.get_codes` (issue #619) +* ENH: Added :attr:`pyproj.transformer.Transformer.is_network_enabled` (issue #629) +* ENH: Added :meth:`pyproj.transformer.TransformerGroup.download_grids` (pull #643) +* ENH: Use 'proj_get_units_from_database' in :func:`pyproj.database.get_units_map` & cleanup :func:`pyproj.database.get_codes` (issue #619) * ENH: Added support for radians for Proj & Transformer.from_pipeline & use less gil (issue #612) * ENH: Datum.from_name default to check all datum types (issue #606) * ENH: Use from_user_input in __eq__ when comparing CRS sub-classes (i.e. PrimeMeridian, Datum, Ellipsoid, etc.) (issue #606) -* ENH: Added :meth:`pyproj.transformer.TransformerGroup.download_grids` (pull #643) -* ENH: Added transformation grid sync API/CLI (issue #572) * ENH: Add support for coordinate systems with CRS using CF conventions (issue #536) * ENH: Use `proj_is_equivalent_to_with_ctx` in the place of `proj_is_equivalent_to` internally (issue #666) * BUG: Add support for identifying engineering/parametric/temporal datums (issue #670) -* ENH: Added ability to use global context (issue #661) * ENH: Add support for temporal CRS CF coordinate system (issue #672) -* BUG: Fix handling of polygon holes when calculating area in Geod (pull #686) -* ENH: Added :ref:`network` (#675, #691, #695) * ENH: Added support for debugging internal PROJ (pull #696) * ENH: Added pathlib support for data directory methods (pull #702) -* ENH: Added `pyproj.database.query_crs_info` (pull #703) +* ENH: Added :func:`pyproj.database.query_crs_info` (pull #703) +* REF: Refactor Proj to inherit from Transformer (issue #624) * REF: Added `pyproj.database`, `pyproj.aoi`, and `pyproj.list` modules (pull #703) +* BUG: Fix handling of polygon holes when calculating area in Geod (pull #686) 2.6.1 ~~~~~ diff --git a/docs/transformation_grids.rst b/docs/transformation_grids.rst index 3220162ee..1ebfe1a0b 100644 --- a/docs/transformation_grids.rst +++ b/docs/transformation_grids.rst @@ -56,10 +56,7 @@ Available methods for download include: - `pyproj sync `__ command line program (pyproj 3+; useful if you use pyproj wheels). -- Enabling `PROJ network `__ capabilities. - - .. note:: You can use the `network` kwarg when initializing - :class:`pyproj.Proj` or :class:`pyproj.Transformer ` +- Enabling `PROJ network `__ capabilities. See also :ref:`network`. - Download stable from https://download.osgeo.org/proj or latest from https://github.com/OSGeo/PROJ-data @@ -91,7 +88,8 @@ What grids to download? - Have a machine that can hold and extra 500 MB - 1 GB of data? Then downloading all grids shouldn't be an issue. -- Have a machine with limited space, a great network connection, and PROJ 7+? Look into `PROJ network `__ capabilities. +- Have a machine with limited space, a great network connection, and PROJ 7+? + Look into `PROJ network `__ capabilities. See also :ref:`network`. - Have a machine with limited space and want to pre-download files? diff --git a/pyproj/_crs.pyx b/pyproj/_crs.pyx index 0f9422439..0c3c129c3 100644 --- a/pyproj/_crs.pyx +++ b/pyproj/_crs.pyx @@ -161,11 +161,10 @@ cdef _get_concatenated_operations(PJ_CONTEXT* context, PJ* concatenated_operatio ) cdef PJ* operation = NULL cdef PJ_CONTEXT* sub_context = NULL - cdef int network_enabled = proj_context_is_network_enabled(context) cdef int iii = 0 operations = [] for iii in range(step_count): - sub_context = pyproj_context_create(network=network_enabled) + sub_context = pyproj_context_create() operation = proj_concatoperation_get_step( sub_context, concatenated_operation, diff --git a/pyproj/_datadir.pxd b/pyproj/_datadir.pxd index 1a7332429..1a9e0b0ae 100644 --- a/pyproj/_datadir.pxd +++ b/pyproj/_datadir.pxd @@ -1,4 +1,4 @@ include "proj.pxi" -cdef PJ_CONTEXT* pyproj_context_create(network=*) except * +cdef PJ_CONTEXT* pyproj_context_create() except * diff --git a/pyproj/_datadir.pyx b/pyproj/_datadir.pyx index 1d820e534..2927350c7 100644 --- a/pyproj/_datadir.pyx +++ b/pyproj/_datadir.pyx @@ -120,19 +120,8 @@ cdef void set_context_data_dir(PJ_CONTEXT* context) except *: free(c_data_dir) -cdef void pyproj_context_set_enable_network( - PJ_CONTEXT* context, - network=None, -) except *: - if network is not None: - enabled = proj_context_set_enable_network(context, bool(network)) - if network and not enabled: - warnings.warn("PROJ network cannot be enabled.") - - cdef void pyproj_context_initialize( PJ_CONTEXT* context, - network=None, bint autoclose_database=True, ) except *: """ @@ -142,13 +131,10 @@ cdef void pyproj_context_initialize( proj_context_use_proj4_init_rules(context, 1) if autoclose_database: proj_context_set_autoclose_database(context, 1) - pyproj_context_set_enable_network(context, network=network) set_context_data_dir(context) -cdef PJ_CONTEXT* pyproj_context_create( - network=None, -) except *: +cdef PJ_CONTEXT* pyproj_context_create() except *: """ Create and initialize the context(s) for pyproj. This also manages whether the global context is used. @@ -156,16 +142,13 @@ cdef PJ_CONTEXT* pyproj_context_create( global _USE_GLOBAL_CONTEXT if _USE_GLOBAL_CONTEXT: return NULL - cdef PJ_CONTEXT* context = proj_context_create() - pyproj_context_set_enable_network(context, network=network) - return context + return proj_context_create() def _pyproj_global_context_initialize(): global _USE_GLOBAL_CONTEXT pyproj_context_initialize( NULL, - network=None, autoclose_database=not _USE_GLOBAL_CONTEXT ) diff --git a/pyproj/_transformer.pyi b/pyproj/_transformer.pyi index d0e0bbd10..102de9e78 100644 --- a/pyproj/_transformer.pyi +++ b/pyproj/_transformer.pyi @@ -37,7 +37,6 @@ class _TransformerGroup: skip_equivalent: bool = False, always_xy: bool = False, area_of_interest: Optional[AreaOfInterest] = None, - network: Optional[bool] = None, ) -> None: ... class _Transformer(Base): @@ -71,12 +70,9 @@ class _Transformer(Base): skip_equivalent: bool = False, always_xy: bool = False, area_of_interest: Optional[AreaOfInterest] = None, - network: Optional[bool] = None, ) -> "_Transformer": ... @staticmethod - def from_pipeline( - proj_pipeline: str, network: Optional[bool] = None - ) -> "_Transformer": ... + def from_pipeline(proj_pipeline: str) -> "_Transformer": ... def _transform( self, inx: Any, diff --git a/pyproj/_transformer.pyx b/pyproj/_transformer.pyx index 162625fe5..7418d9ed1 100644 --- a/pyproj/_transformer.pyx +++ b/pyproj/_transformer.pyx @@ -113,7 +113,6 @@ cdef class _TransformerGroup: skip_equivalent=False, always_xy=False, area_of_interest=None, - network=None, ): """ From PROJ docs: @@ -124,7 +123,7 @@ cdef class _TransformerGroup: area of use of the CRS), and by increasing accuracy. Operations with unknown accuracy are sorted last, whatever their area. """ - self.context = pyproj_context_create(network=network) + self.context = pyproj_context_create() cdef PJ_OPERATION_FACTORY_CONTEXT* operation_factory_context = NULL cdef PJ_OBJ_LIST * pj_operations = NULL cdef PJ* pj_transform = NULL @@ -174,7 +173,7 @@ cdef class _TransformerGroup: ) num_operations = proj_list_get_count(pj_operations) for iii in range(num_operations): - context = pyproj_context_create(network=network) + context = pyproj_context_create() pj_transform = proj_list_get( context, pj_operations, @@ -306,7 +305,6 @@ cdef class _Transformer(Base): skip_equivalent=False, always_xy=False, area_of_interest=None, - network=None, ): """ Create a transformer from CRS objects @@ -336,7 +334,7 @@ cdef class _Transformer(Base): east_lon_degree, north_lat_degree, ) - transformer.context = pyproj_context_create(network=network) + transformer.context = pyproj_context_create() transformer.projobj = proj_create_crs_to_crs( transformer.context, cstrencode(crs_from.srs), @@ -386,12 +384,12 @@ cdef class _Transformer(Base): return transformer @staticmethod - def from_pipeline(const char *proj_pipeline, network=None): + def from_pipeline(const char *proj_pipeline): """ Create Transformer from a PROJ pipeline string. """ cdef _Transformer transformer = _Transformer() - transformer.context = pyproj_context_create(network=network) + transformer.context = pyproj_context_create() # initialize projection transformer.projobj = proj_create( transformer.context, diff --git a/pyproj/crs/_cf1x8.py b/pyproj/crs/_cf1x8.py index 62eb85429..cc43ca7f0 100644 --- a/pyproj/crs/_cf1x8.py +++ b/pyproj/crs/_cf1x8.py @@ -358,7 +358,7 @@ def _rotated_latitude_longitude(cf_params): } _GEOGRAPHIC_GRID_MAPPING_NAME_MAP = { - "rotated_latitude_longitude": _rotated_latitude_longitude, + "rotated_latitude_longitude": _rotated_latitude_longitude } diff --git a/pyproj/network.py b/pyproj/network.py index 3cb253d7d..c2d2a531a 100644 --- a/pyproj/network.py +++ b/pyproj/network.py @@ -37,11 +37,7 @@ def set_ca_bundle_path(ca_bundle_path: Union[Path, str, bool, None] = None) -> N or an empty string then it will default to the system settings or environment variables. """ - env_var_names = ( - "PROJ_CURL_CA_BUNDLE", - "CURL_CA_BUNDLE", - "SSL_CERT_FILE", - ) + env_var_names = ("PROJ_CURL_CA_BUNDLE", "CURL_CA_BUNDLE", "SSL_CERT_FILE") if ca_bundle_path is False: # need to reset CA Bundle path to use system settings # or environment variables because it diff --git a/pyproj/proj.py b/pyproj/proj.py index f5c4c2a29..4b9fca329 100644 --- a/pyproj/proj.py +++ b/pyproj/proj.py @@ -45,11 +45,7 @@ class Proj(Transformer): """ def __init__( - self, - projparams: Any = None, - preserve_units: bool = True, - network=None, - **kwargs, + self, projparams: Any = None, preserve_units: bool = True, **kwargs ) -> None: """ A Proj class instance is initialized with proj map projection @@ -59,19 +55,12 @@ def __init__( https://proj.org/operations/projections/index.html for examples of key/value pairs defining different map projections. - .. versionadded:: 3.0.0 network - Parameters ---------- projparams: int, str, dict, pyproj.CRS A PROJ or WKT string, PROJ dict, EPSG integer, or a pyproj.CRS instance. preserve_units: bool If false, will ensure +units=m. - network: bool, optional - Default is None, which uses the system defaults for networking. - If True, it will force the use of network for grids regardless of - any other network setting. If False, it will force disable use of - network for grids regardless of any other network setting. **kwargs: PROJ projection parameters. @@ -142,9 +131,7 @@ def __init__( projstring = self.crs.to_proj4() or self.crs.srs self.srs = re.sub(r"\s\+?type=crs", "", projstring).strip() - super().__init__( - _Transformer.from_pipeline(cstrencode(self.srs), network=network) - ) + super().__init__(_Transformer.from_pipeline(cstrencode(self.srs))) def __call__( self, diff --git a/pyproj/sync.py b/pyproj/sync.py index d4addf9a5..c53d37e53 100644 --- a/pyproj/sync.py +++ b/pyproj/sync.py @@ -76,10 +76,7 @@ def _bbox_from_geom(geom: Dict[str, Any]) -> Optional[BBox]: def _filter_bbox( - feature: Dict[str, Any], - bbox: BBox, - spatial_test: str, - include_world_coverage: bool, + feature: Dict[str, Any], bbox: BBox, spatial_test: str, include_world_coverage: bool ) -> bool: """ Filter by the bounding box. Designed to use with 'filter' diff --git a/pyproj/transformer.py b/pyproj/transformer.py index ff5c2270c..280affaf7 100644 --- a/pyproj/transformer.py +++ b/pyproj/transformer.py @@ -54,7 +54,6 @@ def __init__( skip_equivalent: bool = False, always_xy: bool = False, area_of_interest: Optional[AreaOfInterest] = None, - network: Optional[bool] = None, ) -> None: """Get all possible transformations from a :obj:`pyproj.crs.CRS` or input used to create one. @@ -77,11 +76,6 @@ def __init__( area_of_interest: :class:`pyproj.transformer.AreaOfInterest`, optional The area of interest to help order the transformations based on the best operation for the area. - network: bool, optional - Default is None, which uses the system defaults for networking. - If True, it will force the use of network for grids regardless of - any other network setting. If False, it will force disable use of - network for grids regardless of any other network setting. """ super().__init__( @@ -90,7 +84,6 @@ def __init__( skip_equivalent=skip_equivalent, always_xy=always_xy, area_of_interest=area_of_interest, - network=network, ) for iii, transformer in enumerate(self._transformers): self._transformers[iii] = Transformer(transformer) @@ -291,14 +284,12 @@ def from_proj( skip_equivalent: bool = False, always_xy: bool = False, area_of_interest: Optional[AreaOfInterest] = None, - network: Optional[bool] = None, ) -> "Transformer": """Make a Transformer from a :obj:`pyproj.Proj` or input used to create one. .. versionadded:: 2.1.2 skip_equivalent .. versionadded:: 2.2.0 always_xy .. versionadded:: 2.3.0 area_of_interest - .. versionadded:: 3.0.0 network Parameters ---------- @@ -316,11 +307,6 @@ def from_proj( Default is false. area_of_interest: :class:`pyproj.transformer.AreaOfInterest`, optional The area of interest to help select the transformation. - network: bool, optional - Default is None, which uses the system defaults for networking. - If True, it will force the use of network for grids regardless of - any other network setting. If False, it will force disable use of - network for grids regardless of any other network setting. Returns ------- @@ -340,7 +326,6 @@ def from_proj( skip_equivalent=skip_equivalent, always_xy=always_xy, area_of_interest=area_of_interest, - network=network, ) @staticmethod @@ -350,14 +335,12 @@ def from_crs( skip_equivalent: bool = False, always_xy: bool = False, area_of_interest: Optional[AreaOfInterest] = None, - network: Optional[bool] = None, ) -> "Transformer": """Make a Transformer from a :obj:`pyproj.crs.CRS` or input used to create one. .. versionadded:: 2.1.2 skip_equivalent .. versionadded:: 2.2.0 always_xy .. versionadded:: 2.3.0 area_of_interest - .. versionadded:: 3.0.0 network Parameters ---------- @@ -375,11 +358,6 @@ def from_crs( Default is false. area_of_interest: :class:`pyproj.transformer.AreaOfInterest`, optional The area of interest to help select the transformation. - network: bool, optional - Default is None, which uses the system defaults for networking. - If True, it will force the use of network for grids regardless of - any other network setting. If False, it will force disable use of - network for grids regardless of any other network setting. Returns ------- @@ -393,38 +371,26 @@ def from_crs( skip_equivalent=skip_equivalent, always_xy=always_xy, area_of_interest=area_of_interest, - network=network, ) ) @staticmethod - def from_pipeline( - proj_pipeline: str, network: Optional[bool] = None - ) -> "Transformer": + def from_pipeline(proj_pipeline: str) -> "Transformer": """Make a Transformer from a PROJ pipeline string. https://proj.org/operations/pipeline.html - .. versionadded:: 3.0.0 network - Parameters ---------- proj_pipeline: str Projection pipeline string. - network: bool, optional - Default is None, which uses the system defaults for networking. - If True, it will force the use of network for grids regardless of - any other network setting. If False, it will force disable use of - network for grids regardless of any other network setting. Returns ------- Transformer """ - return Transformer( - _Transformer.from_pipeline(cstrencode(proj_pipeline), network=network) - ) + return Transformer(_Transformer.from_pipeline(cstrencode(proj_pipeline))) def transform( self, diff --git a/setup.py b/setup.py index 5f60ba7e1..3b48cd35f 100644 --- a/setup.py +++ b/setup.py @@ -71,10 +71,7 @@ def get_proj_libdirs(proj_dir: Path) -> List[str]: proj_libdir = os.environ.get("PROJ_LIBDIR") libdirs = [] if proj_libdir is None: - libdir_search_paths = ( - proj_dir / "lib", - proj_dir / "lib64", - ) + libdir_search_paths = (proj_dir / "lib", proj_dir / "lib64") for libdir_search_path in libdir_search_paths: if libdir_search_path.exists(): libdirs.append(str(libdir_search_path)) diff --git a/test/conftest.py b/test/conftest.py index 3e260c221..fa85ae619 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -16,14 +16,11 @@ def proj_network_env(): """ Ensure global context network settings reset """ - if not pyproj._datadir._USE_GLOBAL_CONTEXT: + network = pyproj.network.is_network_enabled() + try: yield - else: - network = pyproj.network.is_network_enabled() - try: - yield - finally: - pyproj.network.set_network_enabled(network) + finally: + pyproj.network.set_network_enabled(network) @contextmanager diff --git a/test/test_doctest_wrapper.py b/test/test_doctest_wrapper.py index 450c20e96..46141f792 100644 --- a/test/test_doctest_wrapper.py +++ b/test/test_doctest_wrapper.py @@ -5,19 +5,16 @@ import warnings import pytest -from mock import patch import pyproj from test.conftest import proj_network_env -@patch.dict("os.environ", {"PROJ_NETWORK": "ON"}, clear=True) def test_doctests(): """run the examples in the docstrings using the doctest module""" with warnings.catch_warnings(), proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled(active=True) + pyproj.network.set_network_enabled(active=True) warnings.filterwarnings( "ignore", "You will likely lose important projection information when", diff --git a/test/test_proj.py b/test/test_proj.py index c3c44356a..da986d556 100644 --- a/test/test_proj.py +++ b/test/test_proj.py @@ -534,25 +534,22 @@ def test_numpy_bool_kwarg_true(): @patch.dict("os.environ", {"PROJ_NETWORK": "ON"}, clear=True) def test_network__disable(): with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled(active=False) - transformer = Proj(3857, network=False) + pyproj.network.set_network_enabled(active=False) + transformer = Proj(3857) assert transformer.is_network_enabled is False @patch.dict("os.environ", {"PROJ_NETWORK": "OFF"}, clear=True) def test_network__enable(): with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled(active=True) - transformer = Proj(3857, network=True) + pyproj.network.set_network_enabled(active=True) + transformer = Proj(3857) assert transformer.is_network_enabled is True def test_network__default(): with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled() + pyproj.network.set_network_enabled() transformer = Proj(3857) assert transformer.is_network_enabled == ( os.environ.get("PROJ_NETWORK") == "ON" diff --git a/test/test_transformer.py b/test/test_transformer.py index b14818892..9ec0ccc50 100644 --- a/test/test_transformer.py +++ b/test/test_transformer.py @@ -792,9 +792,8 @@ def test_pipeline_itransform(pipeline_str): @patch.dict("os.environ", {"PROJ_NETWORK": "ON"}, clear=True) def test_network__disable(transformer): with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled(active=False) - trans = transformer(network=False) + pyproj.network.set_network_enabled(active=False) + trans = transformer() assert trans.is_network_enabled is False @@ -811,9 +810,8 @@ def test_network__disable(transformer): @patch.dict("os.environ", {"PROJ_NETWORK": "OFF"}, clear=True) def test_network__enable(transformer): with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled(active=True) - trans = transformer(network=True) + pyproj.network.set_network_enabled(active=True) + trans = transformer() assert trans.is_network_enabled is True @@ -829,8 +827,7 @@ def test_network__enable(transformer): ) def test_network__default(transformer): with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled() + pyproj.network.set_network_enabled() trans = transformer() assert trans.is_network_enabled == (os.environ.get("PROJ_NETWORK") == "ON") @@ -838,9 +835,8 @@ def test_network__default(transformer): @patch.dict("os.environ", {"PROJ_NETWORK": "OFF"}, clear=True) def test_transformer_group__network_enabled(): with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled(active=True) - trans_group = TransformerGroup(4326, 2964, network=True) + pyproj.network.set_network_enabled(active=True) + trans_group = TransformerGroup(4326, 2964) assert len(trans_group.unavailable_operations) == 0 assert len(trans_group.transformers) == 10 assert trans_group.best_available @@ -854,9 +850,8 @@ def test_transformer_group__network_enabled(): @patch.dict("os.environ", {"PROJ_NETWORK": "ON"}, clear=True) def test_transformer_group__network_disabled(): with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled(active=False) - trans_group = TransformerGroup(4326, 2964, network=False) + pyproj.network.set_network_enabled(active=False) + trans_group = TransformerGroup(4326, 2964) for transformer in trans_group.transformers: assert transformer.is_network_enabled is False @@ -956,9 +951,8 @@ def test_transform_honours_input_types(x, y, z): def test_transformer_group__download_grids(get_user_data_dir_mock, tmp_path, capsys): get_user_data_dir_mock.return_value = str(tmp_path) with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled(active=False) - trans_group = TransformerGroup(4326, 2964, network=False) + pyproj.network.set_network_enabled(active=False) + trans_group = TransformerGroup(4326, 2964) trans_group.download_grids(verbose=True) captured = capsys.readouterr() get_user_data_dir_mock.assert_called_with(True) @@ -992,7 +986,7 @@ def test_transformer_group__download_grids(get_user_data_dir_mock, tmp_path, cap "pyproj.transformer._download_resource_file" ) as download_mock: append_data_dir(str(tmp_path)) - trans_group = TransformerGroup(4326, 2964, network=False) + trans_group = TransformerGroup(4326, 2964) trans_group.download_grids() get_user_data_dir_mock.assert_called_with(True) download_mock.assert_not_called() @@ -1004,9 +998,8 @@ def test_transformer_group__download_grids__directory( get_user_data_dir_mock, download_mock, tmp_path, capsys ): with proj_network_env(): - if pyproj._datadir._USE_GLOBAL_CONTEXT: - pyproj.network.set_network_enabled(active=False) - trans_group = TransformerGroup(4326, 2964, network=False) + pyproj.network.set_network_enabled(active=False) + trans_group = TransformerGroup(4326, 2964) trans_group.download_grids(directory=tmp_path) get_user_data_dir_mock.assert_not_called() captured = capsys.readouterr()