`BertTokenizer.from_pretrained()` not working with native Python `pathlib` module
Author: macwanj
Pull request: no
Labels: name: wontfix

name: Good First Issue

Consider this code that downloads models and tokenizers to disk and then uses `BertTokenizer.from_pretrained` to load the tokenizer from disk. 

**ISSUE:** `BertTokenizer.from_pretrained()` does not seem to be compatible with Python's native [pathlib](https://docs.python.org/3/library/pathlib.html) module. 

```
# -*- coding: utf-8 -*-
"""
Created on: 25-04-2020
Author: MacwanJ

ISSUE:
BertTokenizer.from_pretrained() is not compatible with pathlib constructs 

"""

from pathlib import Path
import os
from transformers import BertModel, BertTokenizer

# enables proper path resolves when this script is run in terminal
# or in an interactive Python shell/notebook
try:
    file_location = Path(__file__).parent.resolve()
except NameError:
    file_location = Path.cwd().resolve()

PROJ_DIR = file_location.parent

#####################################################################
# DOWNLOAD MODELS & TOKENIZERS
#####################################################################

model_name = 'bert-base-uncased'

if not os.path.exists(PROJ_DIR/'models'/model_name):
    print(model_name,
          'folder does not exist. Creating folder now',
          'and proceeding to download and save model')
    os.makedirs(PROJ_DIR/'models'/model_name)
else:
    print(model_name,
          'folder already exists. Proceeding to download and save model')

tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertModel.from_pretrained(model_name)
print('Download complete. Proceeding to save to disk')

model.save_pretrained(PROJ_DIR/'models'/model_name)
tokenizer.save_pretrained(PROJ_DIR/'models'/model_name)
print('Model saving complete')

#####################################################################
# LOAD MODEL & TOKENIZER FROM DISK
#####################################################################
model_name = 'bert-base-uncased'

# Load pre-trained model tokenizer (vocabulary)
# !! DOES NOT WORK UNLESS I CONVERT THE PATHLIB OBJECT TO STRING!!
tokenizer = BertTokenizer.from_pretrained(PROJ_DIR/'models'/model_name)

# Load pre-trained model weights
model = BertModel.from_pretrained(PROJ_DIR/'models'/model_name,
                                  output_hidden_states=True)
```
Running:
`tokenizer = BertTokenizer.from_pretrained(PROJ_DIR/'models'/model_name)`
Yields this error:
```
Traceback (most recent call last):

  File "C:\Users\macwanj\AppData\Local\miniconda3\envs\bert\lib\site-packages\IPython\core\interactiveshell.py", line 3331, in run_code

    exec(code_obj, self.user_global_ns, self.user_ns)

  File "<ipython-input-94-eb0783e1626e>", line 1, in <module>

    tokenizer = BertTokenizer.from_pretrained(PROJ_DIR/'models'/model_name)

  File "C:\Users\macwanj\AppData\Local\miniconda3\envs\bert\lib\site-packages\transformers\tokenization_utils.py", line 393, in from_pretrained

    return cls._from_pretrained(*inputs, **kwargs)

  File "C:\Users\macwanj\AppData\Local\miniconda3\envs\bert\lib\site-packages\transformers\tokenization_utils.py", line 424, in _from_pretrained

    if os.path.isfile(pretrained_model_name_or_path) or is_remote_url(pretrained_model_name_or_path):

  File "C:\Users\macwanj\AppData\Local\miniconda3\envs\bert\lib\site-packages\transformers\file_utils.py", line 146, in is_remote_url

    parsed = urlparse(url_or_filename)

  File "C:\Users\macwanj\AppData\Local\miniconda3\envs\bert\lib\urllib\parse.py", line 367, in urlparse

    url, scheme, _coerce_result = _coerce_args(url, scheme)

  File "C:\Users\macwanj\AppData\Local\miniconda3\envs\bert\lib\urllib\parse.py", line 123, in _coerce_args

    return _decode_args(args) + (_encode_result,)

  File "C:\Users\macwanj\AppData\Local\miniconda3\envs\bert\lib\urllib\parse.py", line 107, in _decode_args

    return tuple(x.decode(encoding, errors) if x else '' for x in args)

  File "C:\Users\macwanj\AppData\Local\miniconda3\envs\bert\lib\urllib\parse.py", line 107, in <genexpr>

    return tuple(x.decode(encoding, errors) if x else '' for x in args)

AttributeError: 'WindowsPath' object has no attribute 'decode'

```
All the other functions and methods appear to be compatible with pathlib except for `BertTokenizer.from_pretrained()`

It would be good to ensure consistency with pathlib constructs across all functions because pathlib makes it easier to specify paths that work out of the box across operating systems.
     
- `transformers` version: 2.8.0
- Platform: Windows 10
- Python version: 3.7.0
- PyTorch version (GPU?):Non-GPU 1.3.1
- Tensorflow version (GPU?):2.1.0 non gpu
- Using GPU in script?: No
- Using distributed or parallel set-up in script?: No


Comments:
Looking into the `BertTokenizer` code, it inherits the `from_pretrained` function so the real issue is coming from `PreTrainedTokenizer`. To confirm this, I tried loading the pretrained `roberta-base` tokenizer and reproduced the same error:

```
model_name = 'roberta-base'
tokenizer = AutoTokenizer.from_pretrained(PROJ_DIR/'models'/model_name)
model = AutoModel.from_pretrained(PROJ_DIR/'models'/model_name)

Output:
AttributeError: 'PosixPath' object has no attribute 'decode'
```
I actually also get the same error from the `AutoModel.from_pretrained()` line but oddly not when it's `BertModel.from_pretrained()`.  Looking into the documentation for `from_pretrained` in `PreTrainedTokenizer` this [line](https://github.com/huggingface/transformers/blob/4e817ff41885063e08bb3bcd63e5adfd835b9911/src/transformers/tokenization_utils.py#L825) doesn't suggest that a Path object is a supported input anyways. You could just stringify the Path before passing it in:

```
tokenizer = AutoTokenizer.from_pretrained(str(PROJ_DIR/'models'/model_name))
model = AutoModel.from_pretrained(str(PROJ_DIR/'models'/model_name))
```



Yes, stringify works. I upgraded from transformers 2.1 (from conda-forge) to the latest yesterday and the older version of transformers seems to work with `pathlib`. This isn't a dealbreaker for sure, but many other mature Python libraries, such as pandas, scikit-learn etc. have consistent compatibility with pathlib so it would be a *nice-to-have* to see this consistency with transformers too across all functions and classes.

From `pandas.io.common` they use a function [`stringify_path`](https://github.com/pandas-dev/pandas/blob/77a0f19c53279f7b2bf86c9e33daae2030b16e51/pandas/io/common.py#L96-L126) to convert any possible path-like objects to a string. This really comes down to whether the conversion from`pathlib.Path` to `str` should be handled by transformers or on the client side @julien-c .

 I think issue is resolved now. It should be closed now

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.