Repository: PyPSA/PyPSA

Issue:
Cannot use pathlib.Path for opening with pypsa.Network(...)
Paths of networks need to be provided as `str` and `pathlib.Path` is not supported when trying to open Networks using `pypsa.Netowrk(...)`. See screenshot:

![image](https://user-images.githubusercontent.com/42553970/188843335-ab87a9c1-a186-4209-ae9b-a069733241d7.png)

## Checklist

- [x] I am using the current [`master`](https://github.com/pypsa/pypsa/tree/master) branch or the latest [release](https://github.com/pypsa/pypsa/releases). Please indicate:

## Describe the Bug

See above
## Error Message

See screenshot

Discussion:

Patch:
diff --git a/doc/release_notes.rst b/doc/release_notes.rst
index 813c61a6..eb500a5a 100644
--- a/doc/release_notes.rst
+++ b/doc/release_notes.rst
@@ -7,7 +7,7 @@ Upcoming Release
 
 .. warning:: The features listed below are not released yet, but will be part of the next release! To use the features already you have to install the ``master`` branch, e.g. ``pip install git+https://github.com/pypsa/pypsa#egg=pypsa``.
 
-* New features
+* Accept ``pathlib.Path`` objects when importing networks with ``pypsa.Network()``.
 
 PyPSA 0.20.0 (26th July 2022)
 ==============================
diff --git a/pypsa/components.py b/pypsa/components.py
index 4689592c..05a5951d 100644
--- a/pypsa/components.py
+++ b/pypsa/components.py
@@ -18,6 +18,7 @@ __copyright__ = (
 import os
 import sys
 from collections import namedtuple
+from pathlib import Path
 
 import numpy as np
 import pandas as pd
@@ -132,17 +133,14 @@ class Network(Basic):
 
     Parameters
     ----------
-    import_name : string
-        Name of netCDF file, HDF5 .h5 store or folder from which to import CSVs
-        of network data.
+    import_name : string, Path
+        Path to netCDF file, HDF5 .h5 store or folder of CSV files from which to
+        import network data.
     name : string, default ""
         Network name.
     ignore_standard_types : boolean, default False
         If True, do not read in PyPSA standard types into standard types
         DataFrames.
-    csv_folder_name : string
-        Name of folder from which to import CSVs of network data. Overrides
-        import_name.
     override_components : pandas.DataFrame
         If you want to override the standard PyPSA components in
         pypsa.components.components, pass it a DataFrame with index of component
@@ -328,13 +326,18 @@ class Network(Basic):
         if not ignore_standard_types:
             self.read_in_default_standard_types()
 
-        if import_name is not None:
-            if import_name[-3:] == ".h5":
+        if import_name:
+            import_name = Path(import_name)
+            if import_name.suffix == ".h5":
                 self.import_from_hdf5(import_name)
-            elif import_name[-3:] == ".nc":
+            elif import_name.suffix == ".nc":
                 self.import_from_netcdf(import_name)
-            else:
+            elif import_name.is_dir():
                 self.import_from_csv_folder(import_name)
+            else:
+                raise ValueError(
+                    f"import_name '{import_name}' is not a valid .h5 file, .nc file or directory."
+                )
 
         for key, value in kwargs.items():
             setattr(self, key, value)
diff --git a/pypsa/io.py b/pypsa/io.py
index a280664a..e8af30e5 100644
--- a/pypsa/io.py
+++ b/pypsa/io.py
@@ -20,6 +20,7 @@ import json
 import math
 import os
 from glob import glob
+from pathlib import Path
 from textwrap import dedent
 
 import numpy as np
@@ -257,18 +258,18 @@ if has_xarray:
     class ImporterNetCDF(Importer):
         def __init__(self, path):
             self.path = path
-            if isinstance(path, str):
+            if isinstance(path, (str, Path)):
                 self.ds = xr.open_dataset(path)
             else:
                 self.ds = path
 
         def __enter__(self):
-            if isinstance(self.path, str):
+            if isinstance(self.path, (str, Path)):
                 super(ImporterNetCDF, self).__init__()
             return self
 
         def __exit__(self, exc_type, exc_val, exc_tb):
-            if isinstance(self.path, str):
+            if isinstance(self.path, (str, Path)):
                 super(ImporterNetCDF, self).__exit__(exc_type, exc_val, exc_tb)
 
         def get_attributes(self):
@@ -493,7 +494,7 @@ def import_from_csv_folder(network, csv_folder_name, encoding=None, skip_time=Fa
     >>> network.import_from_csv_folder(csv_folder_name)
     """
 
-    basename = os.path.basename(csv_folder_name)
+    basename = Path(csv_folder_name).name
     with ImporterCSV(csv_folder_name, encoding=encoding) as importer:
         _import_from_importer(network, importer, basename=basename, skip_time=skip_time)
 
@@ -548,13 +549,13 @@ def import_from_hdf5(network, path, skip_time=False):
 
     Parameters
     ----------
-    path : string
+    path : string, Path
         Name of HDF5 store
     skip_time : bool, default False
         Skip reading in time dependent attributes
     """
 
-    basename = os.path.basename(path)
+    basename = Path(path).name
     with ImporterHDF5(path) as importer:
         _import_from_importer(network, importer, basename=basename, skip_time=skip_time)
 
@@ -610,7 +611,7 @@ def import_from_netcdf(network, path, skip_time=False):
 
     assert has_xarray, "xarray must be installed for netCDF support."
 
-    basename = os.path.basename(path) if isinstance(path, str) else None
+    basename = Path(path).name
     with ImporterNetCDF(path=path) as importer:
         _import_from_importer(network, importer, basename=basename, skip_time=skip_time)
 


Test patch:
diff --git a/test/test_io.py b/test/test_io.py
index 61f95b23..fce6ff81 100644
--- a/test/test_io.py
+++ b/test/test_io.py
@@ -1,5 +1,6 @@
 # -*- coding: utf-8 -*-
 import os
+from pathlib import Path
 
 import pandas as pd
 import pytest
@@ -16,6 +17,12 @@ def test_netcdf_io(scipy_network, tmpdir, meta):
     assert reloaded.meta == scipy_network.meta
 
 
+def test_netcdf_io_Path(scipy_network, tmpdir):
+    fn = Path(os.path.join(tmpdir, "netcdf_export.nc"))
+    scipy_network.export_to_netcdf(fn)
+    pypsa.Network(fn)
+
+
 @pytest.mark.parametrize("meta", [{"test": "test"}, {"test": {"test": "test"}}])
 def test_csv_io(scipy_network, tmpdir, meta):
     fn = os.path.join(tmpdir, "csv_export")
@@ -26,6 +33,12 @@ def test_csv_io(scipy_network, tmpdir, meta):
     assert reloaded.meta == scipy_network.meta
 
 
+def test_csv_io_Path(scipy_network, tmpdir):
+    fn = Path(os.path.join(tmpdir, "csv_export"))
+    scipy_network.export_to_csv_folder(fn)
+    pypsa.Network(fn)
+
+
 @pytest.mark.parametrize("meta", [{"test": "test"}, {"test": {"test": "test"}}])
 def test_hdf5_io(scipy_network, tmpdir, meta):
     fn = os.path.join(tmpdir, "hdf5_export.h5")
@@ -36,6 +49,12 @@ def test_hdf5_io(scipy_network, tmpdir, meta):
     assert reloaded.meta == scipy_network.meta
 
 
+def test_hdf5_io_Path(scipy_network, tmpdir):
+    fn = Path(os.path.join(tmpdir, "hdf5_export.h5"))
+    scipy_network.export_to_hdf5(fn)
+    pypsa.Network(fn)
+
+
 def test_netcdf_io_multiindexed(ac_dc_network_multiindexed, tmpdir):
     fn = os.path.join(tmpdir, "netcdf_export.nc")
     ac_dc_network_multiindexed.export_to_netcdf(fn)