Is there any way to create a "project file" in Emacs? - python

I say "project file" in the loosest sense. I have a few python projects that I work on with ropemacs using emacs W32 for Windows. What would be ideal is if I could have an icon I could click on on my desktop to open up emacs, open up the rope project, and set the speed bar in the top-level directory of that project. Then I could also maybe have a way to open up the next project in its own emacs set up the same way (but for that project). Of course, it's also acceptable if there were an emacs command or a shell command I could use to achieve the same effect instead of an icon on my desktop.
Is there any way to do this? I have absolutely no elisp-fu. :-(

You could get everything set up the way you want for a project, then use the answer I posted about using desktop.el and named sessions:
What alternate session managers are available for Emacs?

I'm actually working on a solution to this very problem. I always had a group of files I wanted to open/close at the same time, plus do things like open a magit-status window, a dired buffer, etc. I've started on my own project mode called metaproject. It's in the very early stages, but is functional enough that I'm using it for project groups at work now.
Check it out here: http://nafai77.github.com/metaproject/
What's in git is pretty stable, though sparsely documented. I'm going to start working on it again here soon. I currently have the basics of a small plug-in architecture, so you can register custom actions that can be done on project open.

I use the following "solution" for myself: A project root is defined by a directory that contains a Makefile. I've bound F12 to the mode specific elisp function that "compiles" the project by makeing the first target of the corresponding Makefile. This is found by recursively going upwards from the directory of the current file.
It is a little bit of setup, but you will never have to reconstruct your .metadata directory as was frequently the case with Eclipse before. And once set up, you just have to place the proper Makefiles around and you have your projects.
(defun get-makefile-recursively-higher ()
(loop for i below 100 for cwd = (expand-file-name default-directory)
then next for next = (expand-file-name (concat cwd "/..")) for file =
(concat cwd "/" "Makefile") do (cond ((and (file-exists-p file))
(return file))) until (equal cwd next))
)
This is then used e.g. by the LaTeX and Python mode as follows:
(defun py-execute-prog (&optional target)
"Invoke python on the file being edited in the current buffer using
arguments obtained from the minibuffer. It will save all of the modified
buffers before trying to execute the file."
(interactive)
(let* (makefile file cmd)
(setq makefile (get-makefile-recursively-higher))
(setq file (buffer-file-name (current-buffer)))
(setq cmd (concat "make -f " makefile))
(setq default-directory (file-name-directory makefile))
(save-some-buffers (not py-ask-about-save) nil)
(setq py-pdbtrack-do-tracking-p t)
(if (get-buffer py-output-buffer)
(kill-buffer py-output-buffer)) ; Get rid of buffer if it exists.
(global-unset-key "\C-x\C-l" )
(global-unset-key "\C-x\C-p" )
(global-unset-key "\C-x\C-e" )
(global-unset-key "\C-x\C-n" )
(global-set-key "\C-x\C-l" 'py-last-exception)
(global-set-key "\C-x\C-p" 'py-previous-exception)
(global-set-key "\C-x\C-e" 'py-current-line-exception)
(global-set-key "\C-x\C-n" 'py-next-exception)
(define-key comint-mode-map [mouse-3] 'py-current-line-exception)
(make-comint "Python Output" "make" nil "-f" makefile)
(if (not (get-buffer py-output-buffer))
(message "No output.")
(setq py-exception-buffer (current-buffer))
(pop-to-buffer py-output-buffer)
)))
(defun make-tex (&optional target)
(interactive)
(let (makefile cmd)
(setq makefile (get-makefile-recursively-higher))
(save-buffer)
(TeX-save-document (TeX-master-file))
(setq cmd (concat "make -j4 -f " makefile " LATEXPARAM=\"-halt-on-error -file-line-error\""
" TEXMASTER=" (expand-file-name (TeX-master-file)) ".tex"
" TEXMASTERDIR=" (file-name-directory makefile) "/"))
(when (stringp target)
(setq cmd (concat cmd " " target))
)
(ad-activate-regexp "auto-compile-yes-or-no-p-always-yes")
(compile cmd)
(ad-deactivate-regexp "auto-compile-yes-or-no-p-always-yes")
)
)

There's eproject, but it seems to be very sparsely documented.

You can roll your own in bash/cmd.exe. The windows emacs distribution comes with a .bat file called runemacs.bat which accepts files to open as arguments. Write a small script and it should be able to open everything up from one icon.

See http://www.emacswiki.org/emacs/CategoryProgrammerUtils#ProjectSupport. There are several packages which manage "projects". I favor mk-project, but then again, I wrote it. ;-)

You can use Desktop bookmarks, Dired bookmarks, or Bookmark-List bookmarks to do what you want -- see Bookmark+. You can even encapsulate code and multiple bookmarks in a single bookmark to get just the state and setup you want.
See also: Icicles support for projects for more options.

Related

Emacs 24.3 python: Can't guess python-indent-offset, using defaults 4

Can anyone who understands Lisp please help resolve this warning?
I upgraded to Emacs 24.3 and whenever I create a Python file using Emacs I get this warning message. Searched in python.el and found the following section of code that produces the warning:
(let ((indentation (when block-end
(goto-char block-end)
(python-util-forward-comment)
(current-indentation))))
(if indentation
(set (make-local-variable 'python-indent-offset) indentation)
(message "Can't guess python-indent-offset, using defaults: %s"
python-indent-offset)))
And here is my .emacs setup:
(setq-default c-basic-offset 4
tab-width 4
indent-tabs-mode nil)
(add-hook 'c-mode-common-hook
(lambda ()
(c-set-offset 'arglist-intro '+)
(c-set-offset 'arglist-close 0)))
(add-hook 'python-mode-hook
(lambda ()
(c-set-offset 'arglist-intro '+)
(c-set-offset 'arglist-close 0)))
When you open a python file, emacs guesses the indentation offset (number of spaces to indent) based on that file style. When you create a file (the case you describe), emacs cannot guess (file is empty) so it uses your default (4) and notifies the user.
In other words: it is a harmless warning; if you find this is a bug please report it as such.
If you don't like emacs guessing the offset, customize the variable python-indent-guess-indent-offset to nil, and then emacs will use always your default (very unsafe in python, where indentation has meaning and you could be editing a file created by somebody else with other defaults).
If all you want is to silence the warnings, while letting emacs still guess the offset as juanleon's answer explains, you can switch the python-indent-guess-indent-offset-verbose variable off.
(setq python-indent-guess-indent-offset t)
(setq python-indent-guess-indent-offset-verbose nil)
Per this comprehensive answer on the emacs SE.
Look in python.el, not python.elc. If you do not have python.el, then google for it (at least to look at it -- you do not need it to use Emacs). *.elc is a byte-compiled file, which is pretty much incomprehensible to humans.
The source code, in python.el, will tell you just what python-indent-guess-indent-offset does, and hence why you see the result you see.
In addition to the previous answers, and silencing the warning, this procedure deals with the problem and gives two examples for why the warning is useful.
Get a list of currently open buffers with C-x C-b. Filter those with a Python
extension, add quotes around them, and replace them in this command:
(dolist (f '(
"/path/to/file1"
"/path/to/file2"
))
(message (concat "Opening file: " f))
(find-file (expand-file-name f)))
Execute the command (select the region, then M-x evaluate-region). Then *Messages* looks like this:
Opening file: /path/to/file1
Opening file: /path/to/file2
Can’t guess python-indent-offset, using defaults: 4
For information about GNU Emacs and the GNU system, type C-h C-a.
I had files I had used for testing and that I had forgotten, for example:
from time import sleep
sleep(10000)
I only realized it thanks to this message and I deleted the files.
In another case, I had a useful file with just global variables, so I added this
line:
# -*- mode: python; python-indent-offset: 4 -*-
SOME_GLOBAL_VAR = 0
Although this does set the buffer-local variable (check by changing to 6, then
checking the value with C-h v python-indent-offset), it only does so after the
warning message, not before. I decided to tolerate this message.

emacs and python updating modules

atm i'm using emacs to write some python code, so far it works quite fine except one problem that is really a bit annoying.
Always when I update something inside a self written module i reevaluate the buffer and the module in the python shell inside emacs doesn't get updated. i always have to end the python process and start it again to get the change. I figured out that emacs copies some things to a tmp dir to execute them, so i guess it has something to do with this.
Maybe someone out there had the same problem and solved it already so help would be appreciated
You have to reload the module manually in the shell in order for it to take effect.
See the documentation here on the Python reload function
I asked a similar question which you can see here
I found a better solution that needs no emacs config:
simply do
$ ipython profile create
that should create ipython profile in
$HOME/.ipython/profile_default/ipython_config.py
then put the following inside
c = get_config()
c.TerminalInteractiveShell.editor = 'emacsclient'
c.InteractiveShellApp.extensions = [
'autoreload'
]
c.InteractiveShellApp.exec_lines = []
c.InteractiveShellApp.exec_lines.append('%load_ext autoreload')
c.InteractiveShellApp.exec_lines.append('%autoreload 2')
then restart emacs. Now each time you save changes to file inside emacs - ipython would reload it automatically
and the following I have in my emacs config
;; ------------------
;; misc python config
;; ------------------
(company-mode -1)
(elpy-enable)
(elpy-use-ipython "ipython")
(setq python-shell-interpreter "ipython" python-shell-interpreter-args "--simple-prompt --pprint")
(setq python-check-command "flake8")
(setq elpy-rpc-backend "jedi")
(setq elpy-rpc-python-command "python")
; https://github.com/gregsexton/ob-ipython/issues/28
(setq python-shell-completion-native-enable nil)
if you want to see my full python config, it's here
You can advise a python-mode.el function to get the desired effect (at least, if I am understanding your request properly). Put the following in your Emacs init file:
(defun py-reload-file (buf)
"Reload buffer's file in Python interpreter."
(let ((file (buffer-file-name buf)))
(if file
(progn
;; Maybe save some buffers
(save-some-buffers (not py-ask-about-save) nil)
(let ((reload-cmd
(if (string-match "\\.py$" file)
(let ((f (file-name-sans-extension
(file-name-nondirectory file))))
(format "if globals().has_key('%s'):\n reload(%s)\nelse:\n import %s\n"
f f f))
(format "execfile(r'%s')\n" file))))
(save-excursion
(set-buffer (get-buffer-create
(generate-new-buffer-name " *Python Command*")))
(insert reload-cmd)
(py-execute-base (point-min) (point-max))))))))
(defadvice py-execute-region
(around reload-in-shell activate)
"After execution, reload in Python interpreter."
(save-window-excursion
(let ((buf (current-buffer)))
ad-do-it
(py-reload-file buf))))
Now, when you're in a python program, you can select a region of code, press C-| to evaluate the region and the python program will be reloaded (or imported if it wasn't previously loaded) in the Python interpreter buffer. The ENTIRE module will be reloaded, not just the region that was selected and you will be prompted to save the python file if it hasn't already been saved. Note that the caveats that were mentioned in the replies to your previous question still apply (e.g. - If you have class instances already created from the imported module, have instantiated other objects, etc, they won't be reloaded). General breakage may occur, so caveat emptor!).
I'd recommend using Elpy as discussed here.
Add the following to your Emacs configuration file:
(defun my-restart-python-console ()
"Restart python console before evaluate buffer or region to avoid various uncanny conflicts, like not reloding modules even when they are changed"
(interactive)
(if (get-buffer "*Python*")
(let ((kill-buffer-query-functions nil)) (kill-buffer "*Python*")))
(elpy-shell-send-region-or-buffer))
(global-set-key (kbd "C-c C-x C-c") 'my-restart-python-console)
restart your Emacs run your code using C-c C-x C-c
In short, this code has the "if clause" for checking if Python buffer is open. This will help to be able to run C-c C-x C-c at any time of development even when there is no Python process already open. Another part is kill-buffer-query-functions which neglects the prompt for killing the Python buffer.

python code completion in Emacs

I tried make PythonIDE using emacs like in this article http://www.enigmacurry.com/2009/01/21/autocompleteel-python-code-completion-in-emacs/ But emacs said me "auto-complete-mode not enabled". It is possible use emacs for python coding?
You want to activate the auto-complete mode in the context where you get that message, either
every time you open python files, by adding the following to your .emacs:
(add-hook 'python-mode-hook
(lambda ()
(auto-complete-mode 1)))
or when you open any file, by adding the following to your .emacs:
(global-auto-complete-mode t)
The question you're linking to suggests something even more complete (i.e. which subsumes the first of the two additions I suggest):
(add-hook 'python-mode-hook
(lambda ()
(auto-complete-mode 1)
(set (make-local-variable 'ac-sources)
(append ac-sources '(ac-source-rope) '(ac-source-yasnippet)))
(set (make-local-variable 'ac-find-function) 'ac-python-find)
(set (make-local-variable 'ac-candidate-function) 'ac-python-candidate)
(set (make-local-variable 'ac-auto-start) nil)))
Those additions will be needed to get full completion using snippets and Rope.

Can flymake's temporary file be created in the system's temporary directory?

I am currently using the following code to hook up flymake and Pyflakes in emacs:
(defun flymake-create-temp-in-system-tempdir (filename prefix)
(make-temp-file (or prefix "flymake")))
and then I pass this function to flymake-init-create-temp-buffer-copy. (Taken from http://hustoknow.blogspot.com/2010/09/emacs-and-pyflakes-using-tmp-directory.html).
This code worked fine until yesterday. When I visit certain Python files, I get the following error:
switched OFF Flymake mode for buffer admin.py due to fatal status
CFGERR, warning Configuration error has occured while running
(pyflakes ../../../../../../../tmp/flymake28459SVv)
Why is flymake passing what seems like the wrong filename to pyflakes? I expect it to pass something like "/tmp/efe234234" and I haven't modified any of the tmp directory settings.
I don't recall emacs being updated for Ubuntu recently and can't think of anything that might have caused this to mess up (.emacs files are versioned).
The only issue I can think of is that this is a heavily nested directory symlinked to a directory in my ~/Dropbox directory but this doesn't happen to other symlinked in a similar way.
How can I fix this problem?
UPDATE
I've done some debugging and now I see that it's not passing the correct path as the argument. It needs one more parent directory inserted into the path to make it work which makes me think it's getting messed up because of symlinks.
Here is an example shell session to show what I mean. I am doing this from the correct relative directory:
$ pyflakes ../../../../../tmp/flymake13382xHi
../../../../../tmp/flymake13382xHi: No such file or directory
That is the command flymake is trying to run. If I change it:
$ pyflakes ../../../../../../tmp/flymake13382xHi
I get no output (as expected). Note the extra ".." in the path.
How can I get flymake to pass an absolute path instead of these crazy relative paths?
UPDATE 2
I've gotten everything to work. Basically there is this function:
(defun flymake-pyflakes-init ()
; Make sure it's not a remote buffer or flymake would not work
(when (not (subsetp (list (current-buffer)) (tramp-list-remote-buffers)))
(let* ((temp-file (flymake-init-create-temp-buffer-copy
'flymake-create-temp-in-system-tempdir))
(local-file (file-relative-name
temp-file
(file-name-directory buffer-file-name))))
(list "pyflakes" (list temp-file)))))
In the last part I had to change the argument to list from local-file to temp-file because local-file was the crazy relative path I didn't want. Why did the author of that snippet use local-file in the first place?
Thanks,
Ryan
For me, i have resolved by modify user script /usr/local/bin/pyflakes, i test if file exist, if no, i add a slash.
#!/bin/bash
FILE=$1
# Test if folder exist
if [ ! -e "$FILE" ]; then
FILE="/$1"
fi
epylint "$FILE" 2>/dev/null
pep8 --ignore=E221,E701,E202 --repeat "$FILE"
true
I don't have a direct solution to the pyflakes question, but here's something similar for you.
I didn't like how C# was handled in flymake, so I modified the C# entry in the flymake-allowed-file-name-masks to refer to distinct init and cleanup routines, with this code:
(let ((csharpentry (assoc "\\.cs\\'" flymake-allowed-file-name-masks)))
(if csharpentry
(setcdr csharpentry '(csharp-flymake-init csharp-flymake-cleanup))
(add-to-list
'flymake-allowed-file-name-masks
(list key 'csharp-flymake-init 'csharp-flymake-cleanup))))
The documentation is sort of spotty on this stuff, but the code is the documentation, and from what I could tell, the init routine is supposed to return the command line for a syntax check run. It is formatted as a 2-element list, the car is the command to run, and the cadr is itself a list of the arguments. In my example the return value is like this:
("csc.exe" ("/t:module" "/nologo" "nameOfFileToCheck.cs"))
The init routine that returns this command line copies the existing buffer into a temporary file, using flymake's builtin copy fn, and then uses the name of the temp file as the thing to check. So if the buffer filename is "source.cs", the actual value returned from the init fn is
("csc.exe" ("/t:module" "/nologo" "source_flymake.cs"))
The code looks like this:
(defun csharp-flymake-init ()
(csharp-flymake-init-impl
'flymake-create-temp-inplace t t 'csharp-flymake-get-cmdline))
(defun csharp-flymake-init-impl (create-temp-f use-relative-base-dir use-relative-source get-cmdline-f)
"Create syntax check command line for a directly checked source file.
Use CREATE-TEMP-F for creating temp copy."
(let* ((args nil)
(temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)))
(setq args (flymake-get-syntax-check-program-args
temp-source-file-name "."
use-relative-base-dir use-relative-source
get-cmdline-f))
args))
I implemented it in 2 distinct functions, only to follow the pattern I saw in flymake.el.
Anyway...What you can see is that the init fn creates the temp file then returns the arguments. The call to flymake-get-syntax-check-program-args actually boils down to a call into get-cmdline-f, which in the case of C# is csharp-flymake-get-cmdline. Why all this layering and indirection? I don't know; that's how flymake is.
In the C#-specific cleanup fn, I just check for any "product" files from the syntax check and delete them, and then also chain to flymake-simple-cleanup, to delete the *_flymake.cs temp file that was created.
Maybe your nested dir path has something to do with the use-relative-base-dir and use-relative-source arguments that flymake uses in its own default init routine, which I think is flymake-simple-make-init-impl.
The function make-temp-file uses the variable temporary-file-directory, so perhaps you could try setting temporary-file-directory to something else to fix your problem.
This is what I use for PHP on Windows. It uses the make-temp-file suggestion from Trey. It also explicitly sets the init and cleanup functions for PHP, to the things I want. You could use basically the same thing, for python.
(defun cheeso-flymake-create-temp-intemp (file-name prefix)
"Return file name in temporary directory for checking FILE-NAME.
This is a replacement for `flymake-create-temp-inplace'. The
difference is that it gives a file name in
`temporary-file-directory' instead of the same directory as
FILE-NAME.
For the use of PREFIX see that function.
This won't always work; it will fail if the source module
refers to relative paths.
"
(unless (stringp file-name)
(error "Invalid file-name"))
(or prefix
(setq prefix "flymake"))
(let* ((name (concat
(file-name-nondirectory
(file-name-sans-extension file-name))
"_" prefix))
(ext (concat "." (file-name-extension file-name)))
(temp-name (make-temp-file name nil ext))
)
(flymake-log 3 "create-temp-intemp: file=%s temp=%s" file-name temp-name)
temp-name))
(defun cheeso-php-flymake-get-cmdline (source base-dir)
"Gets the cmd line for running a flymake session in a PHP buffer.
This gets called by flymake itself."
(list "c:\\Progra~2\\PHP\\v5.3\\php.exe"
(list "-f" source "-l")))
(defun cheeso-php-flymake-init ()
"initialize flymake for php"
(let ((create-temp-f 'cheeso-flymake-create-temp-intemp)
;;(create-temp-f 'flymake-create-temp-inplace)
(use-relative-base-dir t)
(use-relative-source t)
(get-cmdline-f 'cheeso-php-flymake-get-cmdline)
args
temp-source-file-name)
(setq temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)
args (flymake-get-syntax-check-program-args
temp-source-file-name "."
use-relative-base-dir use-relative-source
get-cmdline-f))
args))
(defun cheeso-php-flymake-cleanup ()
)
(eval-after-load "flymake"
'(progn
;; 1. add a PHP entry to the flymake-allowed-file-name-masks
(let* ((key "\\.php\\'")
(phpentry (assoc key flymake-allowed-file-name-masks)))
(if phpentry
(setcdr phpentry '(cheeso-php-flymake-init cheeso-php-flymake-cleanup))
(add-to-list
'flymake-allowed-file-name-masks
(list key 'cheeso-php-flymake-init 'cheeso-php-flymake-cleanup))))))

how can I load my .el file only while editing python code

I have collected a list of emacs customizations in a file my-python-setup.el. How can I ensure that emacs will first load python-mode and then load this library only when I'm editing python files?
I've tried putting
(load-library "my-python-setup")
in my .emacs file, but that loads these customizations for all kinds of files.
These customizations are on top of python-mode, and the value of auto-mode-alist currently is ("\\.py\\'" . python-mode).
I'm by no means an Emacs expert, but I think you could just stick add a python-mode-hook function and load your library in there. Something like:
;; define your hook function
(defun python-mode-setup ()
(message "Custom python hook run")
(load-library "my-python-setup"))
;; install your hook so it is called when python-mode is invoked
(add-hook 'python-mode-hook 'python-mode-setup)
Here is my personal python-mode-hook, for example:
(defun python-mode-setup ()
(setq python-indent-offset 4
python-indent 4
;; turn off indentation guessing in various python modes
python-guess-indent nil
python-indent-guess-indent-offset nil
py-smart-indentation nil
;; fix mark-defun in new python.el
python-use-beginning-of-innermost-defun t))
(add-hook 'python-mode-hook 'python-mode-setup)
If you only want your code to be loaded when you edit python code, you may want to consider sticking your lisp code in your own major-mode which extends python mode.
(define-derived-mode 'my-python-mode 'python-mode "MyPy"
"A customized version of python-mode"
... here goes your code ...
)
Then you'll have to configure emacs to load 'my-python-mode instead of python-mode by adjusting auto-mode-alist.

Categories

Resources