summaryrefslogtreecommitdiffstats
path: root/emacs/.emacs.d/site-lisp/oni-python.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs/.emacs.d/site-lisp/oni-python.el')
-rw-r--r--emacs/.emacs.d/site-lisp/oni-python.el203
1 files changed, 203 insertions, 0 deletions
diff --git a/emacs/.emacs.d/site-lisp/oni-python.el b/emacs/.emacs.d/site-lisp/oni-python.el
new file mode 100644
index 0000000..6a0ff03
--- /dev/null
+++ b/emacs/.emacs.d/site-lisp/oni-python.el
@@ -0,0 +1,203 @@
+;;; oni-python.el --- Extra Python commands -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2015 Tom Willemse
+
+;; Author: Tom Willemse <tom@ryuslash.org>
+;; Keywords:
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Here are some extra Emacs commands for working with Python source
+;; code.
+
+;;; Code:
+
+(require 'python)
+
+;;;###autoload
+(defun oni:add-import-from (package import)
+ "Add a Python import statement at the beginning of the module."
+ (interactive
+ (list (completing-read "From package: " (oni:collect-from-imports))
+ (read-string "Import: ")))
+ (save-excursion
+ (goto-char (point-min))
+ (search-forward (concat "from " package " import ("))
+ (insert "\n " import ",")
+ (oni:sort-imports)))
+
+(defun oni:collect-from-imports ()
+ "Find all modules from which names are imported in the current file."
+ (let (results)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "from \\(.+\\) import" nil :noerror)
+ (push (buffer-substring-no-properties (match-beginning 1)
+ (match-end 1)) results)))
+ results))
+
+;;;###autoload
+(defun oni:make-import-multiline (from-point to-point)
+ "Turn an import statement into a multi-line import statement."
+ (interactive (list (line-beginning-position)
+ (line-end-position)))
+ (goto-char from-point)
+ (search-forward "import" to-point)
+ (insert " (\n")
+ (delete-horizontal-space)
+ (let ((imports-start (point)) imports-end)
+ (while (search-forward "," to-point :noeror)
+ (insert "\n")
+ (delete-horizontal-space))
+ (end-of-line)
+ (insert ",\n")
+ (setf imports-end (point))
+ (insert ")")
+ (python-indent-shift-right imports-start imports-end)
+ (forward-line -1)
+ (oni:sort-imports)))
+
+;;;###autoload
+(defun oni:sort-imports ()
+ "Sort python multiline imports using `()'."
+ (interactive)
+ (save-excursion
+ (sort-lines nil (1+ (search-backward "("))
+ (1- (search-forward ")")))))
+
+;;; Tests
+
+(ert-deftest oni:add-import-from ()
+ (with-temp-buffer
+ (python-mode)
+ (insert "from myaethon2.core.administration.models import (
+ Client,
+ Contact,
+ Individual,
+ Location,
+)")
+ (oni:add-import-from "myaethon2.core.administration.models" "Debtor")
+ (should (equal (buffer-substring-no-properties (point-min) (point-max))
+ "from myaethon2.core.administration.models import (
+ Client,
+ Contact,
+ Debtor,
+ Individual,
+ Location,
+)"))))
+
+(ert-deftest oni:collect-from-imports ()
+ (with-temp-buffer
+ (python-mode)
+ (insert "import calendar as cal
+import datetime
+
+from django.conf import settings
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required, permission_required
+from django.core.context_processors import csrf
+from django.core.exceptions import PermissionDenied
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
+from django.core.urlresolvers import reverse
+from django.db import transaction
+from django.db.models import Q
+from django.shortcuts import get_object_or_404, render
+from django.utils import formats
+from django.utils.translation import ugettext as _
+
+from myaethon2.core.business_units import BU
+from myaethon2.core.forms import MultiFormWrapper
+from myaethon2.core.models import AUser, Service
+from myaethon2.core.planning.models import Booking, JOB_TYPES
+from myaethon2.core.util import simplify_timedelta
+from myaethon2.core.views import SearchAndSortListView
+from myaethon2.jobs import forms, status
+from myaethon2.jobs.models import Assignment, Job, JobGroup
+from myaethon2.jobs.util import JobFactory
+from myaethon2.workers.models import Worker
+from myaethon2.export import Exporter, XLSGenerator
+
+from django.http import (
+ HttpResponseForbidden,
+ HttpResponseNotAllowed,
+ HttpResponseRedirect,
+)
+
+from django.views.generic import (
+ CreateView,
+ DeleteView,
+ DetailView,
+ ListView,
+ UpdateView,
+)
+
+from myaethon2.core.administration.models import (
+ Client,
+ Contact,
+ Debtor,
+ Individual,
+ Location,
+)
+
+from myaethon2.core.decorators import (
+ json_response,
+ protect_with,
+ with_help_text,
+)")
+ (should (equal (sort (oni:collect-from-imports) #'string-lessp)
+ '("django.conf"
+ "django.contrib"
+ "django.contrib.auth.decorators"
+ "django.core.context_processors"
+ "django.core.exceptions"
+ "django.core.paginator"
+ "django.core.urlresolvers"
+ "django.db"
+ "django.db.models"
+ "django.http"
+ "django.shortcuts"
+ "django.utils"
+ "django.utils.translation"
+ "django.views.generic"
+ "myaethon2.core.administration.models"
+ "myaethon2.core.business_units"
+ "myaethon2.core.decorators"
+ "myaethon2.core.forms"
+ "myaethon2.core.models"
+ "myaethon2.core.planning.models"
+ "myaethon2.core.util"
+ "myaethon2.core.views"
+ "myaethon2.export"
+ "myaethon2.jobs"
+ "myaethon2.jobs.models"
+ "myaethon2.jobs.util"
+ "myaethon2.workers.models")))))
+
+(ert-deftest oni:make-import-multiline ()
+ (with-temp-buffer
+ (python-mode)
+ (insert "from myaethon2.core.administration.models import Contact, Individual, Client, Location")
+ (oni:make-import-multiline (line-beginning-position) (line-end-position))
+ (should (equal (buffer-substring-no-properties (point-min) (point-max))
+ "from myaethon2.core.administration.models import (
+ Client,
+ Contact,
+ Individual,
+ Location,
+)"))))
+
+(provide 'oni-python)
+;;; oni-python.el ends here