Repository: bentoml/BentoML
Pull request: fix: Replace backslahes by normal slashes, making bentoml pull possible on windows
## What does this PR address?
With the as_posix we replace the path's backslahes with slashes, making the bentoml pull command from yatai possible on windows systems.
<!--
Thanks for sending a pull request!

Congrats for making it this far! Here's a 🍱 for you. There are still a few steps ahead.

Please make sure to read the contribution guidelines, then fill out the blanks below before requesting a code review.

Name your Pull Request with one of the following prefixes, e.g. "feat: add support for PyTorch", to indicate the type of changes proposed. This is based on the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/#summary).
  - feat: (new feature for the user, not a new feature for build script)
  - fix: (bug fix for the user, not a fix to a build script)
  - docs: (changes to the documentation)
  - style: (formatting, missing semicolons, etc; no production code change)
  - refactor: (refactoring production code, eg. renaming a variable)
  - perf: (code changes that improve performance)
  - test: (adding missing tests, refactoring tests; no production code change)
  - chore: (updating grunt tasks etc; no production code change)
  - build: (changes that affect the build system or external dependencies)
  - ci: (changes to configuration files and scripts)
  - revert: (reverts a previous commit)

Describe your changes in detail. Attach screenshots here if appropriate.

Once you're done with this, someone from BentoML team or community member will help review your PR (see "Who can help review?" section for potential reviewers.). If no one has reviewed your PR after a week have passed, don't hesitate to post a new comment and ping @-the same person. Notifications sometimes get lost 🥲.
-->

<!-- Remove if not applicable -->

Fixes #4440 

## Before submitting:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
<!--- If you plan to update documentation or tests in follow-up, please note -->

- [x ] Does the Pull Request follow [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/#summary) naming? Here are [GitHub's
      guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) on how to create a pull request.
- [ x] Does the code follow BentoML's code style, `pre-commit run -a` script has passed ([instructions](https://github.com/bentoml/BentoML/blob/main/DEVELOPMENT.md#style-check-auto-formatting-type-checking))?
- [x ] Did you read through [contribution guidelines](https://github.com/bentoml/BentoML/blob/main/CONTRIBUTING.md#ways-to-contribute) and follow [development guidelines](https://github.com/bentoml/BentoML/blob/main/DEVELOPMENT.md#start-developing)?
- [ ] Did your changes require updates to the documentation? Have you updated
      those accordingly? Here are [documentation guidelines](https://github.com/bentoml/BentoML/tree/main/docs) and [tips on writting docs](https://github.com/bentoml/BentoML/tree/main/docs#writing-documentation).
- [ ] Did you write tests to cover your changes?


Problem statement:
bug: Pulling latest version from Remote Yatai Store does not work on Windows - Path Error
### Describe the bug

I pushed a working model to our local Yatai server. However, I can not pull it again, as the latest model is not found on remote Bento store.
If I add the version code manually the Bento is found but, I get a BentoMLException.



Error with latest in the tag:
 File "C:\edge_bento\main.py", line 11, in <module>
    main()
  File "C:\edge_bento\edge_bento\main.py", line 7, in main
    bentoml.pull("pytorch_mnist_demo:latest")
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\simple_di\__init__.py", line 139, in _
    return func(*_inject_args(bind.args), **_inject_kwargs(bind.kwargs))
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\bentoml\bentos.py", line 267, in pull
    _cloud_client.pull_bento(tag, force=force, bento_store=_bento_store)
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\simple_di\__init__.py", line 139, in _
    return func(*_inject_args(bind.args), **_inject_kwargs(bind.kwargs))
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\bentoml\_internal\cloud\bentocloud.py", line 416, in pull_bento
    return self._do_pull_bento(
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\simple_di\__init__.py", line 139, in _
    return func(*_inject_args(bind.args), **_inject_kwargs(bind.kwargs))
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\bentoml\_internal\cloud\bentocloud.py", line 458, in _do_pull_bento
    raise BentoMLException(f'Bento "{_tag}" not found on remote Bento store')
bentoml.exceptions.BentoMLException: Bento "pytorch_mnist_demo:latest" not found on remote Bento store


Error with specific version in the tag:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Finished downloading model "pytorch_mnist:nr7glwfsc226qaav" files           │
│ Successfully pulled model "pytorch_mnist:nr7glwfsc226qaav"                  │
│ Finished downloading all bento "pytorch_mnist_demo:eiijhwvsdsnssaav" files  │
└─────────────────────────────────────────────────────────────────────────────┘
Pulling bento "pytorch_mnist_demo:eiijhwvsdsnssaav" --- 0.0% • 71… • ?   • 0:0…
                                                               by…             
 Downloading model "pytorch_mnist:nr7glwfsc226qaav" --- 0.0% • 8,… • 11… • 0:0…
                                                               by…   MB…       Traceback (most recent call last):
  File "C:\edge_bento\main.py", line 11, in <module>
    main()
  File "C:\edge_bento\main.py", line 7, in main
    bentoml.pull("pytorch_mnist_demo:eiijhwvsdsnssaav")
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\simple_di\__init__.py", line 139, in _
    return func(*_inject_args(bind.args), **_inject_kwargs(bind.kwargs))
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\bentoml\bentos.py", line 267, in pull
    _cloud_client.pull_bento(tag, force=force, bento_store=_bento_store)
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\simple_di\__init__.py", line 139, in _
    return func(*_inject_args(bind.args), **_inject_kwargs(bind.kwargs))
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\bentoml\_internal\cloud\bentocloud.py", line 416, in pull_bento
    return self._do_pull_bento(
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\simple_di\__init__.py", line 139, in _
    return func(*_inject_args(bind.args), **_inject_kwargs(bind.kwargs))
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\bentoml\_internal\cloud\bentocloud.py", line 547, in _do_pull_bento
    temp_fs.makedirs(str(p.parent), recreate=True)
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\fs\base.py", line 1124, in makedirs
    dir_paths = tools.get_intermediate_dirs(self, path)
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\fs\tools.py", line 77, in get_intermediate_dirs
    resource = fs.getinfo(path)
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\fs\osfs.py", line 283, in getinfo
    _path = self.validatepath(path)
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\fs\osfs.py", line 686, in validatepath
    return super(OSFS, self).validatepath(path)
  File "C:\Users\---\AppData\Local\miniconda3\envs\edge\lib\site-packages\fs\base.py", line 1581, in validatepath
    raise errors.InvalidCharsInPath(path)
fs.errors.InvalidCharsInPath: path '/env\conda' contains invalid characters

### To reproduce
```
import bentoml
def main() -> None:
    bentoml.pull("pytorch_mnist_demo:latest")
    _ = bentoml.load("pytorch_mnist_demo:latest")

if __name__ == "__main__":
    main()
```
### Expected behavior

I would like to download the latest Bento from our Yatai Server.

### Environment

bentoml, version 1.1.11
Python 3.10.13
platform: windows

Hints from issue discussion:
https://github.com/bentoml/BentoML/blob/fa6420e49eab15b544eccd8d7f562fa6544947e8/src/bentoml/_internal/cloud/bentocloud.py#L547

If I change the line to:
```
temp_fs.makedirs(str(p.parent).replace('\\', '/'), recreate=True)
```
it works on my windows system. Is there any problem encountered so far using bentoml with windows?
Hello, I have the same problem and your solution fixes it for me. Thanks! 
Would be cool if you could include this in the next release.

Commit message: ci: auto fixes from pre-commit.ci

For more information, see https://pre-commit.ci

Patch to review:
diff --git a/src/bentoml/_internal/cloud/bentocloud.py b/src/bentoml/_internal/cloud/bentocloud.py
index 0cdd38034cf..8f69ca57875 100644
--- a/src/bentoml/_internal/cloud/bentocloud.py
+++ b/src/bentoml/_internal/cloud/bentocloud.py
@@ -544,7 +544,9 @@ def pull_model(model_tag: Tag):
                                 continue
                             p = Path(member.name)
                             if p.parent != Path("."):
-                                temp_fs.makedirs(str(p.parent), recreate=True)
+                                temp_fs.makedirs(
+                                    str(p.parent.as_posix()), recreate=True
+                                )
                             temp_fs.writebytes(member.name, f.read())
                         bento = Bento.from_fs(temp_fs)
                         for model_tag in remote_bento.manifest.models:


Code review comments:
diff_hunk: @@ -544,7 +544,9 @@ def pull_model(model_tag: Tag):
                                 continue
                             p = Path(member.name)
                             if p.parent != Path("."):
-                                temp_fs.makedirs(str(p.parent), recreate=True)
+                                temp_fs.makedirs(
+                                    str(p.parent.as_posix()), recreate=True
path: src/bentoml/_internal/cloud/bentocloud.py
text: @user1:
```suggestion
                                    p.parent.as_posix(), recreate=True
```
`as_posix()` is a string itself, no need the `str()`