File: .dir-locals.el

package info (click to toggle)
python-gnuplotlib 0.39-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 5,264 kB
  • sloc: python: 2,238; lisp: 101; makefile: 32
file content (146 lines) | stat: -rw-r--r-- 6,295 bytes parent folder | download | duplicates (2)
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
;; I need some advices to be able to generate all the images. I'm not using the org
;; exporter to produce the html, but relying on github's limited org parser to
;; display everything. github's parser doesn't do the org export, so I must
;; pre-generate all the figures with (org-babel-execute-buffer) (C-c C-v C-b).

;; This requires advices to:

;; - Generate unique image filenames
;; - Communicate those filenames to Python
;; - Display code that produces an interactive plot (so that the readers can
;;   cut/paste the snippets), but run code that writes to the image that ends up in
;;   the documentation

;; There're some comments below, and a mailing list post:

;; https://lists.gnu.org/archive/html/emacs-orgmode/2020-03/msg00086.html

;; This triggered a bug/feature in emacs where the file-local eval was too big, and
;; wasn't happening automatically. Problem description:

;; https://lists.gnu.org/archive/html/emacs-devel/2020-03/msg00314.html
(( org-mode . ((eval .
  (progn
            (setq org-confirm-babel-evaluate nil)
            (org-babel-do-load-languages
             'org-babel-load-languages
              '((python  . t)
                (shell   . t)))
  ;; This is all very convoluted. There are 3 different advices, commented in
  ;; place
  ;;
  ;; THIS advice makes all the org-babel parameters available to python in the
  ;; _org_babel_params dict. I care about _org_babel_params['_file'] specifically,
  ;; but everything is available
  (defun dima-org-babel-python-var-to-python (var)
    "Convert an elisp value to a python variable.
    Like the original, but supports (a . b) cells and symbols
  "
    (if (listp var)
        (if (listp (cdr var))
            (concat "[" (mapconcat #'org-babel-python-var-to-python var ", ") "]")
          (format "\"\"\"%s\"\"\"" var))
      (if (symbolp var)
          (format "\"\"\"%s\"\"\"" var)
        (if (eq var 'hline)
            org-babel-python-hline-to
          (format
           (if (and (stringp var) (string-match "[\n\r]" var)) "\"\"%S\"\"" "%S")
           (if (stringp var) (substring-no-properties var) var))))))
  (defun dima-alist-to-python-dict (alist)
    "Generates a string defining a python dict from the given alist"
    (let ((keyvalue-list
           (mapcar (lambda (x)
                     (format "%s = %s, "
                             (replace-regexp-in-string
                              "[^a-zA-Z0-9_]" "_"
                              (symbol-name (car x)))
                             (dima-org-babel-python-var-to-python (cdr x))))
                   alist)))
      (concat
       "dict( "
       (apply 'concat keyvalue-list)
       ")")))
  (defun dima-org-babel-python-pass-all-params (f params)
    (cons
     (concat
      "_org_babel_params = "
      (dima-alist-to-python-dict params))
     (funcall f params)))
  (unless
      (advice-member-p
       #'dima-org-babel-python-pass-all-params
       #'org-babel-variable-assignments:python)
    (advice-add
     #'org-babel-variable-assignments:python
     :around #'dima-org-babel-python-pass-all-params))
  ;; This sets a default :file tag, set to a unique filename. I want each demo to
  ;; produce an image, but I don't care what it is called. I omit the :file tag
  ;; completely, and this advice takes care of it
  (defun dima-org-babel-python-unique-plot-filename
      (f &optional arg info params)

    (let ((info-local (or info (org-babel-get-src-block-info t))))
      (if (and info-local
               (string= (car info-local) "python")
               (not (assq :file (caddr info-local))))
          ;; We're looking at a python block with no :file. Add a default :file
          (funcall f arg info
                   (cons (cons ':file
                               (format "guide-%d.svg"
                                       (condition-case nil
                                           (setq dima-unique-plot-number (1+ dima-unique-plot-number))
                                         (error (setq dima-unique-plot-number 0)))))
                         params))
        ;; already have a :file or not python. Just do the normal thing
        (funcall f arg info params))))

  (unless
      (advice-member-p
       #'dima-org-babel-python-unique-plot-filename
       #'org-babel-execute-src-block)
    (advice-add
     #'org-babel-execute-src-block
     :around #'dima-org-babel-python-unique-plot-filename))
  ;; If I'm regenerating ALL the plots, I start counting the plots from 0
  (defun dima-reset-unique-plot-number
      (&rest args)
      (setq dima-unique-plot-number 0))
  (unless
      (advice-member-p
       #'dima-reset-unique-plot-number
       #'org-babel-execute-buffer)
    (advice-add
     #'org-babel-execute-buffer
     :before #'dima-reset-unique-plot-number))
  ;; I'm using github to display guide.org, so I'm not using the "normal" org
  ;; exporter. I want the demo text to not contain the hardcopy= tags, but clearly
  ;; I need the hardcopy tag when generating the plots. I add some python to
  ;; override gnuplotlib.plot() to add the hardcopy tag somewhere where the reader
  ;; won't see it. But where to put this python override code? If I put it into an
  ;; org-babel block, it will be rendered, and the :export tags will be ignored,
  ;; since github doesn't respect those (probably). So I put the extra stuff into
  ;; an advice. Whew.
  (defun dima-org-babel-python-set-demo-output (f body params)
    (with-temp-buffer
      (insert body)
      (beginning-of-buffer)
      (when (search-forward "import gnuplotlib as gp" nil t)
        (end-of-line)
        (insert
         "\n"
         "if not hasattr(gp.gnuplotlib, 'orig_init'):\n"
         "    gp.gnuplotlib.orig_init = gp.gnuplotlib.__init__\n"
         "gp.gnuplotlib.__init__ = lambda self, *args, **kwargs: gp.gnuplotlib.orig_init(self, *args, hardcopy=_org_babel_params['_file'] if 'file' in _org_babel_params['_result_params'] else None, **kwargs)\n"))
      (setq body (buffer-substring-no-properties (point-min) (point-max))))
    (funcall f body params))

  (unless
      (advice-member-p
       #'dima-org-babel-python-set-demo-output
       #'org-babel-execute:python)
    (advice-add
     #'org-babel-execute:python
     :around #'dima-org-babel-python-set-demo-output))
  )))))