Repository: modin-project/modin

Issue:
BUG: no module named 'botocore' when using modin.pandas.read_csv with fsspec url
### Modin version checks

- [X] I have checked that this issue has not already been reported.

- [X] I have confirmed this bug exists on the latest released version of Modin.

- [X] I have confirmed this bug exists on the main branch of Modin. (In order to do this you can follow [this guide](https://modin.readthedocs.io/en/stable/getting_started/installation.html#installing-from-the-github-master-branch).)


### Reproducible Example

```python
import modin.pandas as pd

pd.read_csv("myprotocol://file_path")
```


### Issue Description

There is no 'botocore' library when reading CSV file using fsspec url.

### Expected Behavior

Should add 'botocore' library to requirement file

### Error Logs

from botocore.exceptions import (
    255     NoCredentialsError,
    256     EndpointConnectionError,
    257     ConnectTimeoutError,
    258 )
    260 if storage_options is not None:
    261     new_storage_options = dict(storage_options)

ModuleNotFoundError: No module named 'botocore'
<img width="548" alt="Screenshot 2023-08-29 at 11 37 42" src="https://github.com/modin-project/modin/assets/50819157/f9f6c8b8-51cf-4c18-9cdb-fec51fc44702">


### Installed Versions

INSTALLED VERSIONS
------------------
commit           : 26ce87547e327ad129ca1d75dc9102bf9d5cb77c
python           : 3.8.13.final.0
python-bits      : 64
OS               : Darwin
OS-release       : 22.6.0
Version          : Darwin Kernel Version 22.6.0: Wed Jul  5 22:22:05 PDT 2023; root:xnu-8796.141.3~6/RELEASE_ARM64_T6000
machine          : x86_64
processor        : i386
byteorder        : little
LC_ALL           : None
LANG             : en_US.UTF-8
LOCALE           : en_US.UTF-8

Modin dependencies
------------------
modin            : 0.20.0+46.g26ce8754.dirty
ray              : 2.5.1
dask             : None
distributed      : None
hdk              : None

pandas dependencies
-------------------
pandas           : 1.5.3
numpy            : 1.24.4
pytz             : 2023.3
dateutil         : 2.8.2
setuptools       : 68.0.0
pip              : 23.1.2
Cython           : None
pytest           : 7.3.1
hypothesis       : None
sphinx           : None
blosc            : None
feather          : None
xlsxwriter       : None
lxml.etree       : None
html5lib         : None
pymysql          : None
psycopg2         : None
jinja2           : 3.1.2
IPython          : 8.12.0
pandas_datareader: None
bs4              : 4.12.2
bottleneck       : None
brotli           : 1.0.9
fastparquet      : 2023.7.0
fsspec           : 2023.4.0
gcsfs            : None
matplotlib       : None
numba            : None
numexpr          : None
odfpy            : None
openpyxl         : None
pandas_gbq       : None
pyarrow          : 12.0.1
pyreadstat       : None
pyxlsb           : None
s3fs             : None
scipy            : None
snappy           : None
sqlalchemy       : None
tables           : None
tabulate         : None
xarray           : None
xlrd             : None
xlwt             : None
zstandard        : None
tzdata           : 2023.3


Discussion:
@anmyachev, shouldn't botocore be automatically installed even after #6496?

Resolving patch:
diff --git a/modin/core/io/file_dispatcher.py b/modin/core/io/file_dispatcher.py
--- a/modin/core/io/file_dispatcher.py
+++ b/modin/core/io/file_dispatcher.py
@@ -89,7 +89,7 @@ def __enter__(self):
                 PermissionError,
             )
         except ModuleNotFoundError:
-            credential_error_type = ()
+            credential_error_type = (PermissionError,)
 
         args = (self.file_path, self.mode, self.compression)
 
@@ -257,11 +257,21 @@ def file_exists(cls, file_path, storage_options=None):
         if not is_fsspec_url(file_path) and not is_url(file_path):
             return os.path.exists(file_path)
 
-        from botocore.exceptions import (
-            NoCredentialsError,
-            EndpointConnectionError,
-            ConnectTimeoutError,
-        )
+        try:
+            from botocore.exceptions import (
+                NoCredentialsError,
+                EndpointConnectionError,
+                ConnectTimeoutError,
+            )
+
+            credential_error_type = (
+                NoCredentialsError,
+                PermissionError,
+                EndpointConnectionError,
+                ConnectTimeoutError,
+            )
+        except ModuleNotFoundError:
+            credential_error_type = (PermissionError,)
 
         if storage_options is not None:
             new_storage_options = dict(storage_options)
@@ -273,12 +283,7 @@ def file_exists(cls, file_path, storage_options=None):
         exists = False
         try:
             exists = fs.exists(file_path)
-        except (
-            NoCredentialsError,
-            PermissionError,
-            EndpointConnectionError,
-            ConnectTimeoutError,
-        ):
+        except credential_error_type:
             fs, _ = fsspec.core.url_to_fs(file_path, anon=True, **new_storage_options)
             exists = fs.exists(file_path)
 
diff --git a/modin/experimental/core/io/text/csv_glob_dispatcher.py b/modin/experimental/core/io/text/csv_glob_dispatcher.py
--- a/modin/experimental/core/io/text/csv_glob_dispatcher.py
+++ b/modin/experimental/core/io/text/csv_glob_dispatcher.py
@@ -282,11 +282,21 @@ def file_exists(cls, file_path: str, storage_options=None) -> bool:
         if not is_fsspec_url(file_path):
             return len(glob.glob(file_path)) > 0
 
-        from botocore.exceptions import (
-            NoCredentialsError,
-            EndpointConnectionError,
-            ConnectTimeoutError,
-        )
+        try:
+            from botocore.exceptions import (
+                NoCredentialsError,
+                EndpointConnectionError,
+                ConnectTimeoutError,
+            )
+
+            credential_error_type = (
+                NoCredentialsError,
+                PermissionError,
+                EndpointConnectionError,
+                ConnectTimeoutError,
+            )
+        except ModuleNotFoundError:
+            credential_error_type = (PermissionError,)
 
         if storage_options is not None:
             new_storage_options = dict(storage_options)
@@ -298,12 +308,7 @@ def file_exists(cls, file_path: str, storage_options=None) -> bool:
         exists = False
         try:
             exists = fs.exists(file_path)
-        except (
-            NoCredentialsError,
-            PermissionError,
-            EndpointConnectionError,
-            ConnectTimeoutError,
-        ):
+        except credential_error_type:
             fs, _ = fsspec.core.url_to_fs(file_path, anon=True, **new_storage_options)
             exists = fs.exists(file_path)
         return exists or len(fs.glob(file_path)) > 0
@@ -328,11 +333,21 @@ def get_path(cls, file_path: str) -> list:
             abs_paths = [os.path.abspath(path) for path in relative_paths]
             return abs_paths
 
-        from botocore.exceptions import (
-            NoCredentialsError,
-            EndpointConnectionError,
-            ConnectTimeoutError,
-        )
+        try:
+            from botocore.exceptions import (
+                NoCredentialsError,
+                EndpointConnectionError,
+                ConnectTimeoutError,
+            )
+
+            credential_error_type = (
+                NoCredentialsError,
+                PermissionError,
+                EndpointConnectionError,
+                ConnectTimeoutError,
+            )
+        except ModuleNotFoundError:
+            credential_error_type = (PermissionError,)
 
         def get_file_path(fs_handle) -> List[str]:
             file_paths = fs_handle.glob(file_path)
@@ -344,12 +359,7 @@ def get_file_path(fs_handle) -> List[str]:
         fs, _ = fsspec.core.url_to_fs(file_path)
         try:
             return get_file_path(fs)
-        except (
-            NoCredentialsError,
-            PermissionError,
-            EndpointConnectionError,
-            ConnectTimeoutError,
-        ):
+        except credential_error_type:
             fs, _ = fsspec.core.url_to_fs(file_path, anon=True)
         return get_file_path(fs)
 


Test patch: