~hristoast/hristoast

hristoast/site/editing-python-emacs.html -rw-r--r-- 10.2 KiB
4c97c4e5Hristos N. Triantafillou No more zen2 12 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
<h1 id="title">Editing Python with Emacs</h1>

<div id="dates">
  <span>Posted: <time id="post-date">2015-09-30</time> | Updated: <time>2019-11-09</time></span>
</div>

<p style="font-size: 1.3em;"><span class="bold">UPDATE 2:</span> I've since done <a href="/emacs-python-my-setup-2018/">yet another post on the topic of Emacs and Python editing</a>.  Be sure to check that out, as well as <a href="/init.el/">my init.el itself</a>.</p>

<p style="font-size: 1.3em;"><span class="bold">UPDATE:</span> Please be sure to check out the <a href="/editing-with-emacs-python-part-2/">Part 2 to this entry</a>  Where I describe other awesome bits like Jedi!  It's an update as well as an errata for this one.</p>

<p id="post-excerpt">The recent business with <a href="http://blog.jetbrains.com/blog/2015/09/04/we-are-listening/">JetBrains&#39; licensing</a> is a great example of how quickly things can change (<a href="http://blog.jetbrains.com/blog/2015/09/18/final-update-on-the-jetbrains-toolbox-announcement/">though this seems to have been resolved</a>). Other things, like <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a> for example, don&#39;t change too terribly much over very long periods of time.</p>

<p>I really love PyCharm and have been a license holder for several years. It&#39;s sort of hard to imagine working on Django projects without some of the neato bells and whistles it provides, and although I&#39;m not 100% certain I won&#39;t continue to be a JetBrains customer, this news had made me really think about how far I am from just using Emacs for <strong>all</strong> of my Python dev work.</p>

<p>Can I do this? Or will I go insane from the lack of convenience?!</p>

<div id="toc"></div>

<h3>Ranting</h3>

<p>A wise but stubborn man once told me: &quot;Emacs is a terrible text editor!&quot; ...</p>

<p>First thing&#39;s first, I already prefer Emacs to PyCharm for non-Django Python work. But working with Django (and web projects in general) is a whole different beast; you&#39;re almost guaranteed to be working with HTML, CSS, Javascript, and maybe even SQL (or at the very least interact with a database via an ORM.)</p>

<p>I don&#39;t use PyCharm to manage my database, I don&#39;t use its hooks into manage.py, and I don&#39;t really use any of the build system/debugger features either. I prefer to do these things via the command line, with scripts or a makefile-based system.</p>

<p>Ultimately, what really hits the sweet spot for me about PyCharm is the awesome syntax-checking and code completion. That&#39;s for any Python, HTML, CSS, or Javascript. By and large, it is seemingly flawless and very quick. Especially in HTML templates, having the editor know about, and complete <code>{% if %}</code> and the like is super handy.</p>

<h3>Can Emacs do this?</h3>

<p>Indeed that is the question. More precisely: can I have awesome syntax-checking and code completion in Emacs (and will it be at least as good as what I have with PyCharm?)</p>

<p>The answer to those questions, respectively are: <strong>yes absolutely</strong> and <strong>yes mostly</strong>, but it takes a bit of work to get there. Elsewhere on this site I show off my init.el, and while it isn&#39;t necessary to cite the entire file everything I&#39;m about to discuss is in there.</p>

<p>In the end, I want something that is:</p>

<ul>
  <li>Easy to configure (or self-installing)</li>
  <li>Smart (syntax checking, code completion)</li>
  <li>But not too smart (database schema viewers, Django wrappers)</li>
</ul>

<p>You can get these things for Emacs, to be sure, but for now I really just want fast and accurate editing.</p>

<h4><strong>Packages and MELPA</strong></h4>

<p>We can take care of the first point with a couple of lines of Emacs lisp:</p>

<pre><code>(defvar package-list
      &#39;(clean-aindent-mode company diff-hl dtrt-indent
        elpy flycheck function-args web-mode))

(require &#39;package)
(add-to-list &#39;package-archives
             &#39;(&quot;melpa&quot; . &quot;http://melpa.milkbox.net/packages/&quot;) t)
(package-initialize)

(or (file-exists-p package-user-dir)
    (package-refresh-contents))

(dolist (package package-list)
  (unless (package-installed-p package)
    (package-install package)))</code></pre>

<p>The lists the packages we want to install and then iterates over them, ensuring they are installed. The package list includes everything you&#39;ll need for the functionality we want, with some notable highlights:</p>

<ul>
  <li>Flycheck - syntax/error checking</li>
  <li>Elpy - various Python goodies</li>
  <li>web-mode - for html/template</li>
  <li>clean-aindent/dtrt-indent - indent helping</li>
  <li>function-args - be smart about arguments</li>
</ul>

<p>I strongly recommend checking out the <a href="https://github.com/jorgenschaefer/elpy#quick-installation">Elpy quick install guide</a> before proceeding, there are a few pip packages you&#39;ll need which is covered there.</p>

<p>Arguably, web-mode and the indent packages are optional, but I find them to be more helpful than intrusive. YMMV.</p>

<h4>Setting up</h4>

<p>Now that we&#39;ve got all these packages, we need to actually use them. Add this to your init.el, below what you&#39;ve already got:</p>

<pre><code>(require &#39;elpy)
(elpy-enable)

(require &#39;flycheck)
(add-hook &#39;after-init-hook #&#39;global-flycheck-mode)

(require &#39;function-args)
(fa-config-default)

(require &#39;web-mode)
(add-to-list &#39;auto-mode-alist &#39;(&quot;\\.tpl\\&#39;&quot; . web-mode))</code></pre>

<h4><strong>To django-mode, or not to django-mode?</strong></h4>

<p>At this time, I&#39;m not totally sure about <a href="https://github.com/myfreeweb/django-mode">django-mode</a>. The project appears to need a maintainer, and for sure is a bit off on current Django best practices. For now python-mode and web-mode seem to fill in the gaps since I don&#39;t really care about the project management bits and the manage.py helpers.</p>

<h4><strong>Custom bits</strong></h4>

<p>The final icing on the cake are a few functions which will allow you to easily switch between Python versions within Emacs, as well as one that makes multi-line commenting much easier:</p>

<pre><code>(defun use-python343 ()
  &quot;Point to Python 3.4.3 for `elpy-mode&#39;, `flycheck-mode&#39;, and `python-mode&#39;.&quot;
  (interactive)
  (setq
   elpy-rpc-python-command &quot;/opt/python343/bin/python3.4m&quot;
   elpy-rpc-pythonpath &quot;/opt/python343/lib/python3.4/site-packages&quot;
   flycheck-python-flake8-executable &quot;/opt/python343/bin/flake8&quot;
   python-check-command &quot;/opt/python343/bin/pyflakes&quot;
   python-shell-interpreter &quot;/opt/python343/bin/ipython3&quot;))

(defun use-pyenv-python3 ()
  &quot;Point to Python 3 for `elpy-mode&#39;, `flycheck-mode&#39;, and `python-mode&#39;.&quot;
  (interactive)
  (setq
   elpy-rpc-python-command &quot;~/.pyenv/versions/3.4.3/bin/python3.4m&quot;
   elpy-rpc-pythonpath &quot;~/.pyenv/versions/3.4.3/lib/python3.4/site-packages&quot;
   flycheck-python-flake8-executable &quot;~/.pyenv/versions/3.4.3/bin/flake8&quot;
   python-check-command &quot;~/.pyenv/versions/3.4.3/bin/pyflakes&quot;
   python-shell-interpreter &quot;~/.pyenv/versions/3.4.3/bin/ipython3&quot;))

(defun use-pyenv-python2 ()
  &quot;Point to Python 2 for `elpy-mode&#39;, `flycheck-mode&#39;, and `python-mode&#39;.&quot;
  (interactive)
  (setq
   elpy-rpc-python-command &quot;~/.pyenv/versions/2.7.10/bin/python2.7&quot;
   elpy-rpc-pythonpath &quot;~/.pyenv/versions/2.7.10/lib/python2.7/site-packages&quot;
   flycheck-python-flake8-executable &quot;~/.pyenv/versions/2.7.10/bin/flake8&quot;
   python-check-command &quot;~/.pyenv/versions/2.7.10/bin/pyflakes&quot;
   python-shell-interpreter &quot;~/.pyenv/versions/2.7.10/bin/ipython&quot;))

(defun use-system-python3 ()
  &quot;Use the system python3 for `elpy-mode&#39;, `flycheck-mode&#39;, and `python-mode&#39;.&quot;
  (interactive)
  (setq
   elpy-rpc-python-command &quot;/usr/bin/python3.4m&quot;
   elpy-rpc-pythonpath &quot;/usr/local/lib/python3.4/dist-packages&quot;
   flycheck-python-flake8-executable &quot;/usr/bin/flake8&quot;
   python-check-command &quot;/usr/bin/pyflakes3&quot;
   python-shell-interpreter &quot;/usr/bin/ipython3&quot;))

(defun use-system-python2 ()
  &quot;Use the system python2 for `elpy-mode&#39;, `flycheck-mode&#39;, and `python-mode&#39;.&quot;
  (interactive)
  (setq
   elpy-rpc-python-command &quot;/usr/bin/python2.7&quot;
   elpy-rpc-pythonpath &quot;/usr/local/lib/python2.7/dist-packages&quot;
   flycheck-python-flake8-executable &quot;/usr/bin/flake8&quot;
   python-check-command &quot;/usr/bin/pyflakes&quot;
   python-shell-interpreter &quot;/usr/bin/ipython&quot;))

(defun toggle-comment ()
  &quot;Toggle comments on the current line or highlighted region.&quot;
  (interactive)
  (if mark-active
      (let ((mark (mark))
            (point (point)))
        (if (&gt; (mark) (point))
            (comment-or-uncomment-region
             point
             mark)
          (comment-or-uncomment-region
           mark
           point)))
    (comment-or-uncomment-region
     (line-beginning-position)
     (line-end-position))))

(use-python343)</code></pre>

<p>With this, we can simply fire off a <code>M-x use-python-X</code> to change context to a different python version (and default to a custom built Python 3.4.3).</p>

<p>There is, of course, much more you can do (and much more that I do with my own config), but for now we&#39;re just talking about making a nice Python editor; you may tweak as needed after all this.</p>

<h3><strong>Conclusion</strong></h3>

<p>Does Emacs suffice as an intelligent, helpful development tool? Yes it totally does, and in many ways I like it better than PyCharm. Although PyCharm seems to be more tightly integrated in many ways (in particular with regard to Django) Emacs seems to fill in pretty much all of those gaps - and in some ways I like Emac&#39;s completion and error checking better! Your mileage may vary, of course, but hopefully this can serve as an example of how to get a nice, intelligent Python development editor using FOSS tools.</p>

<p>Feel free to take a gander at <a href="/init.el/">my full config</a>, and happy travels on your Emacs rabbit hole journey!</p>

<p><img alt="In action!" src="http://i.imgur.com/sVo5dsS.jpg" style="height:871px; width:866px" /></p>