necaris / conda.el

Emacs helper library (and minor mode) to work with conda environments
MIT License
153 stars 49 forks source link

Error auto activating base env with custom conda home #125

Closed zalky closed 1 year ago

zalky commented 2 years ago

Hi, I have a custom conda home directory set according to the docs:

(setq conda-env-home-directory (expand-file-name "~/opt/anaconda3/"))    ;; was this the old way?
(custom-set-variables '(conda-anaconda-home "~/opt/anaconda3/"))

I'm on version: 20220717.251

When I attempt to run the conda--switch-buffer-auto-activate when loading a python file with no environment.yml or environment specified (ie: it should default to the base env), I see the following error:

Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  file-name-as-directory(nil)
  (let ((dir (file-name-as-directory candidate))) (and (not (s-blank\? candidate)) (f-directory\? dir) (or (f-directory\? (concat dir conda-env-executables-dir)) (f-directory\? (concat dir conda-env-meta-dir)))))
  conda--env-dir-is-valid(nil)
  -filter(conda--env-dir-is-valid (nil "/Users/home/opt/anaconda3/envs/"))
  (let* ((default-location (file-name-as-directory (conda-env-default-location))) (initial-possibilities (list name (concat default-location name))) (possibilities (if (boundp 'venv-location) (if (stringp 'venv-location) (cons venv-location initial-possibilities) (nconc venv-location initial-possibilities)) initial-possibilities)) (matches (-filter 'conda--env-dir-is-valid possibilities))) (if (> (length matches) 0) (file-name-as-directory (expand-file-name (car matches))) (error "No such conda environment: %s" name)))
  (if (and (string= name "base") (conda--env-dir-is-valid conda-anaconda-home)) (file-name-as-directory (expand-file-name conda-anaconda-home)) (let* ((default-location (file-name-as-directory (conda-env-default-location))) (initial-possibilities (list name (concat default-location name))) (possibilities (if (boundp 'venv-location) (if (stringp 'venv-location) (cons venv-location initial-possibilities) (nconc venv-location initial-possibilities)) initial-possibilities)) (matches (-filter 'conda--env-dir-is-valid possibilities))) (if (> (length matches) 0) (file-name-as-directory (expand-file-name (car matches))) (error "No such conda environment: %s" name))))
  conda-env-name-to-dir(nil)
  conda-env-activate-for-buffer()
  conda--switch-buffer-auto-activate()
  run-hooks(change-major-mode-after-body-hook prog-mode-hook python-mode-hook)
  apply(run-hooks (change-major-mode-after-body-hook prog-mode-hook python-mode-hook))
  run-mode-hooks(python-mode-hook)
  python-mode()

If I manually activate the base env, that seems to work. Let me know if I've misconfigured something, or if you require more information.

Thanks!

necaris commented 2 years ago

The way I have typically used conda is, aligned with the default installation, to have the "base" environment pretty much always activated by default. This is true in my terminal (thanks to conda messing with my .bashrc) and I set up Emacs to inherit settings from my terminal (see the exec-path-from-shell package, for instance). So I would not want to activate the "base" environment when switching buffers.

I recognize different people have different patterns for using Emacs so I've added a tentative feature to activate the "base" environment if no other can be inferred, which should solve your problem -- you would have to set the custom variable, but that would be it.

zalky commented 1 year ago

Hi, thanks for the response!

Maybe I've misunderstood the workflow you're describing, but ultimately my workflow needs are pretty basic: to be able to switch between projects (python and non-python) and not have to manually ensure the global conda environment is the right one.

I agree that base should be the default, but if switch from a project with a specific env active (environment.yml), to one that has no env defined (and should default to base), then conda--switch-buffer-auto-activate will throw this error, and I don't think the base env was being applied.

This same error is also thrown every time I switch buffers in a non-python project with conda-env-autoactivate-mode active. A side question: is conda-env-autoactivate-mode searching the directory tree with every buffer switch even in non-python projects?

My naive approach would be to have conda--switch-buffer-auto-activate set the environment locally for the buffer while also resolving base as the default environment, and then set that as a python mode hook. But I have no idea whether or not you can set the conda environment locally for a buffer. If this were possible it would avoid the need for a minor mode that manages a global conda environment every time the buffer changes, and all its associated complications.

Apologies if I've misunderstood your description of the problem.

Thanks again for all the great work put into this project!

necaris commented 1 year ago

A couple of things to clarify:

It sounds like you have open, on a regular basis:

Is that accurate?

zalky commented 1 year ago

It sounds like you have open, on a regular basis:

  • Python buffers associated with different projects / Conda environments, all of which are flagged with an environment.yml
  • non-Python buffers that don't need to be associated with Conda environments

Is that accurate?

  • currently, we try to store the appropriate environment buffer-locally. This may well be buggy, but it should avoid searching repeatedly

Gotcha, well, I can confirm that conda-project-env-path variable is buffer local (I think this is the only buffer local variable being set by conda.el). Despite this, unfortunately the active environment semantics still appear global when tested from a python shell. For example, in buffer 1 I can activate env A, then switch to buffer 2 and activate env B, then switch back to buffer 1 and env B will be active, even though conda-project-env-path will point to the path of env A.

Is there any information I can provide to help reproduce or debug the issue?