Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing conda_cli, tmp_env, and path_factory fixtures #12592

Merged
merged 19 commits into from
May 16, 2023

Conversation

kenodegard
Copy link
Contributor

@kenodegard kenodegard commented Apr 13, 2023

Description

We have two different run subcommand implementations that effectively do the same thing. Each adds unnecessary complexities that we are better off avoiding all together.

from conda.testing.integration import run_command, Commands
from pathlib import Path

def test_info_envs():
    out, err, code = run_commands(Commands.INFO, None, "--envs")

def test_create(tmp_path: Path):
    out, err, code = run_commands(Commands.CREATE, tmp_path, "--yes")

vs.

from conda.testing.helpers import run_inprocess_conda_command
from pathlib import Path

def test_info_envs():
    out, err, code = run_inprocess_conda_command("conda info --envs")

def test_create(tmp_path: Path):
    out, err, code = run_inprocess_conda_command(f"conda create --prefix {tmp_path}" --yes")

Here we propose rewriting these into a pytest fixture:

from conda.testing.integration import CondaCLIFixture
from pathlib import Path

def test_info_envs(conda_cli: CondaCLIFixture):
    out, err, code = conda_cli("info", "--envs")

def test_create(conda_cli: CondaCLIFixture, tmp_path: Path):
    out, err, code = conda_cli("create", "--prefix", tmp_path, "--yes")

In addition to the new conda_cli fixture we also implemented:

  • tmp_env fixture to replace conda.testing.integration.make_temp_env
  • path_factory fixture which does tmp_path / uuid.uuid4().hex for us

Checklist - did you ...

  • Add a file to the news directory (using the template) for the next release's release notes?
  • Add / update necessary tests?
  • Add / update outdated documentation?

@kenodegard kenodegard self-assigned this Apr 13, 2023
@kenodegard kenodegard requested a review from a team as a code owner April 13, 2023 20:59
@conda-bot conda-bot added the cla-signed [bot] added once the contributor has signed the CLA label Apr 13, 2023
)
if not isfile(join(prefix, "conda-meta", "history")):
raise DirectoryNotACondaEnvironmentError(prefix)
print("\nRemove all packages in environment %s:\n" % prefix, file=sys.stderr)
print(f"\nRemove all packages in environment {prefix}:\n")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes stderr to stdout

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct, IMO the text printed does not belong in stderr:

$ conda create -n scratch python --yes
...
$ conda remove -n scratch --all --yes > /dev/null

Remove all packages in environment /Users/kodegard/.conda/arm64/23.1.0/3.10/envs/scratch:
$ conda create -n scratch python --yes
...
$ conda remove -n scratch --all 2> /dev/null

## Package Plan ##

  environment location: /Users/kodegard/.conda/arm64/23.1.0/3.10/envs/scratch


The following packages will be REMOVED:

  bzip2-1.0.8-h620ffc9_4
  ca-certificates-2023.01.10-hca03da5_0
  certifi-2022.12.7-py311hca03da5_0
  libffi-3.4.2-hca03da5_6
  ncurses-6.4-h313beb8_0
  openssl-1.1.1t-h1a28f6b_0
  pip-23.0.1-py311hca03da5_0
  python-3.11.2-hc0d8a6c_0
  readline-8.2-h1a28f6b_0
  setuptools-65.6.3-py311hca03da5_0
  sqlite-3.41.2-h80987f9_0
  tk-8.6.12-hb8d0fd4_0
  tzdata-2023c-h04d1e81_0
  wheel-0.38.4-py311hca03da5_0
  xz-5.2.10-h80987f9_1
  zlib-1.2.13-h5a0b063_0


Preparing transaction: done
Verifying transaction: done
Executing transaction: done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that seemed to be a bug

conda/testing/__init__.py Show resolved Hide resolved
@@ -1361,7 +1361,7 @@ def test_conda_run_1(self):
use_restricted_unicode=False, name=str(uuid4())[:7]
) as prefix:
output, error, rc = run_command(Commands.RUN, prefix, "echo", "hello")
assert output == "hello" + os.linesep
assert output == f"hello{os.linesep}\n"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If os.linesep is \n are we looking for \n\n now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not entirely sure why this change was necessary but the change was test driven:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: is the bash shell introducing the \n

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conda run likes to spit out an extra trailing newline, you can test this locally:

$ conda run -n base python --version
Python 3.10.8

$ conda run -n base echo hello
hello

stdout_logger = getLogger("conda.stdoutlog")
stdout_logger.info(get_main_info_str(info_dict))
stdout_logger.info("\n")
print(get_main_info_str(info_dict) + "\n")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting way to send messages presumably to stdout with stdout_logger instead of print. I wonder if that flexibility was ever used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious about this change, the conda.stdoutlog logger behaves the same as print()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's effectively the same for the CLI.

I had to change it because the logging was resulting in the output getting collected differently so the new conda_cli didn't work correctly for run commands.

Per my understanding, an effort was previously undertaken to replace all print (to both stdout and stderr) with this kind of logging logic. My best guess is this was to potentially allow third-party tools (like navigator) to better redirect/interface with the text streams. This effort was never completed and the logging system has become over complicated as a result. (I'll ping the navigator team to check that this won't cause issues)

@@ -5,6 +5,8 @@

import pytest

from conda.testing import conda_cli, path_factory, tmp_env

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this file should be under changes committed?

Copy link
Contributor Author

@kenodegard kenodegard Apr 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Importing these fixtures here makes these fixtures available to all tests.

As for this extra newline, isort + black handles this formatting, if we remove it, it'll be re-added.

"ca-certificates",
"--yes",
)
assert out
Copy link
Contributor

@sven6002 sven6002 Apr 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert out is not None I think is a better usage of assertion in this section.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conda_cli returns tuple[str, str, int], out will always be not None so that would be a redundant check

what I'm asserting here is whether anything was printed to stdout so an empty string is considered a failure

@@ -156,3 +165,94 @@ def conda_check_versions_aligned():
)
with open(version_file, "w") as fh:
fh.write(version_from_git)


@dataclass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a dataclass?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally I had:

class CondaCLIFixture:
    def __init__(self, capsys: CaptureFixture):
        self.capsys = capsys

Which is what a dataclass does 🤷🏼‍♂️

@kenodegard kenodegard changed the title Introducing simplified subcommand run fixture Introducing conda_cli, tmp_env, and path_factory fixtures Apr 14, 2023
@kenodegard kenodegard requested a review from dholth April 23, 2023 20:13
beeankha
beeankha previously approved these changes Apr 26, 2023
jezdez
jezdez previously approved these changes Apr 27, 2023
Copy link
Member

@jezdez jezdez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some questions, but generally this is a big step forward

@@ -55,4 +55,4 @@ def execute(args, parser):
log = getLogger(__name__)
log.warning(f"CONDA_TEST_SAVE_TEMPS :: retaining main_run script {script}")

return response
return response.rc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is odd, wasn't the return code returned before? Might make things tricky for VS Code etc.

Copy link
Contributor Author

@kenodegard kenodegard Apr 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently no, we've been returning the entire Response object (which happens to be a custom NamedTuple?)

This should only impact downstream projects if they invoke conda run via Python (I'll ping the VSCode community to confirm)

This change ensures that all of the execute functions defined for our subcommands consistently return an int exit code (a good change IMO)

stdout_logger = getLogger("conda.stdoutlog")
stdout_logger.info(get_main_info_str(info_dict))
stdout_logger.info("\n")
print(get_main_info_str(info_dict) + "\n")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious about this change, the conda.stdoutlog logger behaves the same as print()?

Copy link
Contributor

@travishathaway travishathaway left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kenodegard,

Looking good so far. Thanks for the very clear examples on the description of the pull request. That made this a lot easier to review.

Before we merge this, could we please update this article in the documentation?

https://docs.conda.io/projects/conda/en/stable/dev-guide/writing-tests/integration-tests.html

Shouldn't be too difficult.

@jezdez jezdez requested a review from travishathaway May 2, 2023 09:30
@travishathaway travishathaway added the source::anaconda created by members of Anaconda, Inc. label May 4, 2023
@kenodegard kenodegard dismissed travishathaway’s stale review May 16, 2023 15:39

documentation has been updated as requested

@kenodegard kenodegard merged commit 21232ba into conda:main May 16, 2023
91 checks passed
@kenodegard kenodegard deleted the combine-runs branch May 16, 2023 16:07
@sven6002 sven6002 mentioned this pull request May 22, 2023
6 tasks
travishathaway pushed a commit that referenced this pull request Jun 6, 2023
Combine `conda.testing.integration.run_commands` and `conda.testing.helpers.run_inprocess_conda_command` into a new `conda_cli` fixture. Define new `tmp_env` fixture to replace `conda.testing.integration.make_temp_env`. Define new `path_factory` fixture to simplify doing `tmp_path / uuid.uuid4().hex`.
@github-actions github-actions bot added the locked [bot] locked due to inactivity label May 17, 2024
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 17, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cla-signed [bot] added once the contributor has signed the CLA locked [bot] locked due to inactivity source::anaconda created by members of Anaconda, Inc.
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

7 participants