Repository: tox-dev/tox-conda

Issue:
Permission error on conda environment temp file when running in Windows OS
I am receiving the following error (in .tox/python/log/python-0.log) when running tox.
```python
# Error snippet
      File "C:\Users\xxx\Anaconda3\lib\site-packages\conda_env\env.py", line 163, in from_file
        with open(filename, 'rb') as fp:
    PermissionError: [Errno 13] Permission denied: 'C:\\Users\\yyy\\tox_conda_tmp13zv20n4.yaml'

`$ C:\Users\xxx\Anaconda3\Scripts\conda-env-script.py create -p python --file C:\Users\yyy\tox_conda_tmp13zv20n4.yaml`
```

### Steps to reproduce the error on Window OS (Windows 10).
#### tox.ini
```
[tox]
envlist = py310
skipsdist = True

[testenv]
conda_env =
    environment.yaml
```
#### environment.yaml 
```
name: tox_environment
dependencies:
  - python=3.10
  - pytest=7.1.2
  - tox=3.27.1
  - tox-conda=0.10.1
```
#### run the following commands on Windows OS
```bash
# create conda env
conda env create -f environment.yaml
conda activate tox_environment
# run tox
tox
```

### Suspected cause of error
I suspect that the error might be due to the use of tempfile.NamedTemporaryFile in  [plugins.py](https://github.com/tox-dev/tox-conda/blob/main/tox_conda/plugin.py#L171). As per [docs](https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile):

> That name can be retrieved from the name attribute of the returned file-like object. Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows)

Any help is appreciated, thanks!

Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/tox-dev/tox-conda/pull/161?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev) Report
Base: **93.16**% // Head: **88.86**% // Decreases project coverage by **`-4.30%`** :warning:
> Coverage data is based on head [(`e5e6146`)](https://codecov.io/gh/tox-dev/tox-conda/pull/161?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev) compared to base [(`099ec51`)](https://codecov.io/gh/tox-dev/tox-conda/commit/099ec510c545581f8ff2efaac8616f232c5cf66a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev).
> Patch coverage: 100.00% of modified lines in pull request are covered.

:mega: This organization is not using Codecov’s [GitHub App Integration](https://github.com/apps/codecov). We recommend you install it so Codecov can continue to function properly for your repositories. [Learn more](https://about.codecov.io/blog/codecov-is-updating-its-github-integration/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev)

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #161      +/-   ##
==========================================
- Coverage   93.16%   88.86%   -4.30%     
==========================================
  Files           7        7              
  Lines         541      548       +7     
  Branches       61       62       +1     
==========================================
- Hits          504      487      -17     
- Misses         24       44      +20     
- Partials       13       17       +4     
```

| Flag | Coverage Δ | |
|---|---|---|
| tests | `88.86% <100.00%> (-3.19%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/tox-dev/tox-conda/pull/161?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev) | Coverage Δ | |
|---|---|---|
| [tests/test\_conda\_env.py](https://codecov.io/gh/tox-dev/tox-conda/pull/161?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev#diff-dGVzdHMvdGVzdF9jb25kYV9lbnYucHk=) | `98.64% <100.00%> (-1.36%)` | :arrow_down: |
| [tox\_conda/plugin.py](https://codecov.io/gh/tox-dev/tox-conda/pull/161?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev#diff-dG94X2NvbmRhL3BsdWdpbi5weQ==) | `84.70% <100.00%> (-3.39%)` | :arrow_down: |
| [tests/test\_conda.py](https://codecov.io/gh/tox-dev/tox-conda/pull/161?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev#diff-dGVzdHMvdGVzdF9jb25kYS5weQ==) | `81.39% <0.00%> (-13.96%)` | :arrow_down: |
| [tox\_conda/env\_activator.py](https://codecov.io/gh/tox-dev/tox-conda/pull/161?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev#diff-dG94X2NvbmRhL2Vudl9hY3RpdmF0b3IucHk=) | `68.57% <0.00%> (-12.86%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/tox-dev/tox-conda/pull/161?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tox-dev).


Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 762d974..4592cf4 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -18,7 +18,7 @@ repos:
         args:
           - --py3-plus
   - repo: https://github.com/PyCQA/isort
-    rev: 5.11.4
+    rev: 5.12.0
     hooks:
       - id: isort
   - repo: https://github.com/psf/black
diff --git a/tox.ini b/tox.ini
index ff58268..16db4ba 100644
--- a/tox.ini
+++ b/tox.ini
@@ -73,7 +73,7 @@ depends =
 
 [testenv:pkg_meta]
 description = check that the long description is valid
-basepython = python3.9
+basepython = python3.10
 skip_install = true
 deps =
     build>=0.0.4
diff --git a/tox_conda/plugin.py b/tox_conda/plugin.py
index d669718..f93631f 100644
--- a/tox_conda/plugin.py
+++ b/tox_conda/plugin.py
@@ -168,22 +168,27 @@ def tox_testenv_create(venv, action):
         env_file = yaml.load(env_path)
         env_file["dependencies"].append(python)
 
-        with tempfile.NamedTemporaryFile(
-            dir=env_path.parent, prefix="tox_conda_tmp", suffix=".yaml"
-        ) as tmp_env:
-            yaml.dump(env_file, tmp_env)
-
-            args = [
-                venv.envconfig.conda_exe,
-                "env",
-                "create",
-                "-p",
-                envdir,
-                "--file",
-                tmp_env.name,
-            ]
-
-            _run_conda_process(args, venv, action, basepath)
+        tmp_env = tempfile.NamedTemporaryFile(
+            dir=env_path.parent,
+            prefix="tox_conda_tmp",
+            suffix=".yaml",
+            delete=False,
+        )
+        yaml.dump(env_file, tmp_env)
+
+        args = [
+            venv.envconfig.conda_exe,
+            "env",
+            "create",
+            "-p",
+            envdir,
+            "--file",
+            tmp_env.name,
+        ]
+        tmp_env.close()
+        _run_conda_process(args, venv, action, basepath)
+        Path(tmp_env.name).unlink()
+
     else:
         args = [venv.envconfig.conda_exe, "create", "--yes", "-p", envdir]
         for channel in venv.envconfig.conda_channels:


Test patch:
diff --git a/tests/test_conda_env.py b/tests/test_conda_env.py
index 4435c15..1756846 100644
--- a/tests/test_conda_env.py
+++ b/tests/test_conda_env.py
@@ -1,5 +1,6 @@
 import io
 import os
+import pathlib
 import re
 from unittest.mock import mock_open, patch
 
@@ -278,10 +279,12 @@ def test_conda_env(tmpdir, newconfig, mocksession):
 
     mock_file = mock_open()
     with patch("tox_conda.plugin.tempfile.NamedTemporaryFile", mock_file):
-        with mocksession.newaction(venv.name, "getenv") as action:
-            tox_testenv_create(action=action, venv=venv)
+        with patch.object(pathlib.Path, "unlink", autospec=True) as mock_unlink:
+            with mocksession.newaction(venv.name, "getenv") as action:
+                tox_testenv_create(action=action, venv=venv)
+                mock_unlink.assert_called_once
 
-    mock_file.assert_called_with(dir=tmpdir, prefix="tox_conda_tmp", suffix=".yaml")
+    mock_file.assert_called_with(dir=tmpdir, prefix="tox_conda_tmp", suffix=".yaml", delete=False)
 
     pcalls = mocksession._pcalls
     assert len(pcalls) >= 1
@@ -335,10 +338,12 @@ def test_conda_env_and_spec(tmpdir, newconfig, mocksession):
 
     mock_file = mock_open()
     with patch("tox_conda.plugin.tempfile.NamedTemporaryFile", mock_file):
-        with mocksession.newaction(venv.name, "getenv") as action:
-            tox_testenv_create(action=action, venv=venv)
+        with patch.object(pathlib.Path, "unlink", autospec=True) as mock_unlink:
+            with mocksession.newaction(venv.name, "getenv") as action:
+                tox_testenv_create(action=action, venv=venv)
+                mock_unlink.assert_called_once
 
-    mock_file.assert_called_with(dir=tmpdir, prefix="tox_conda_tmp", suffix=".yaml")
+    mock_file.assert_called_with(dir=tmpdir, prefix="tox_conda_tmp", suffix=".yaml", delete=False)
 
     pcalls = mocksession._pcalls
     assert len(pcalls) >= 1