Using the tabulate python module it is possible to have the following "inline" workaround: ------------8<------------8<------------8<------------8<------------8<------------8<------------8<------------ #+BEGIN_SRC python :results raw import pandas as pd import numpy as np from tabulate import tabulate df = pd.DataFrame(np.random.random((4,3)), columns=['A','B','C']) print("foo") return(tabulate(df, headers="keys", tablefmt="orgtbl")) #+END_SRC #+RESULTS: | | A | B | C | |---+----------+----------+----------| | 0 | 0.754799 | 0.492722 | 0.144595 | | 1 | 0.198475 | 0.417721 | 0.083459 | | 2 | 0.645011 | 0.444857 | 0.278874 | | 3 | 0.314883 | 0.7521 | 0.789418 | ------------8<------------8<------------8<------------8<------------8<------------8<------------8<------------ However, this is not optimal, mainly because it pollutes the code block. Note, that the :results is set to `raw`. A brief discussion with Dov, yielded the following better workaround: ------------8<------------8<------------8<------------8<---- --------8<------------8<------------8<------------ (setq org-babel-python-wrapper-method " def main(): %s res = main() if 'pandas.core.frame.DataFrame' in str(type(res)): from tabulate import tabulate out = tabulate(res, headers='keys', tablefmt='orgtbl') else: out = str(res) open('%s', 'w').write(out)") ------------8<------------8<------------8<------------8<---- --------8<------------8<------------8<------------ This allows a nice output of pandas.DataFrame (again when using :results raw). Unfortunately, this wrapper has no influence in the case when :session is used. To that end, it is possible to hack ------------8<------------8<------------8<------------8<---- --------8<------------8<------------8<------------ (defun org-babel-python-evaluate-session (session body &optional result-type result-params) "Pass BODY to the Python process in SESSION. If RESULT-TYPE equals 'output then return standard output as a string. If RESULT-TYPE equals 'value then return the value of the last statement in BODY, as elisp." (let* ((send-wait (lambda () (comint-send-input nil t) (sleep-for 0 5))) (dump-last-value (lambda (tmp-file pp) (mapc (lambda (statement) (insert statement) (funcall send-wait)) (if pp (list "import pprint" (format "open('%s', 'w').write(pprint.pformat(_))" (org-babel-process-file-name tmp-file 'noquote))) (list (format "_org_tmp = _; if 'pandas.core.frame.DataFrame' in str(type(_org_tmp)): from tabulate import tabulate _org_out = tabulate(_org_tmp, headers='keys', tablefmt='orgtbl') else: _org_out = _org_tmp open('%s', 'w').write(str(_org_out))" (org-babel-process-file-name tmp-file 'noquote))))))) (input-body (lambda (body) (mapc (lambda (line) (insert line) (funcall send-wait)) (split-string body "[\r\n]")) (funcall send-wait))) (results (case result-type (output (mapconcat #'org-babel-trim (butlast (org-babel-comint-with-output (session org-babel-python-eoe-indicator t body) (funcall input-body body) (funcall send-wait) (funcall send-wait) (insert org-babel-python-eoe-indicator) (funcall send-wait)) 2) "\n")) (value (let ((tmp-file (org-babel-temp-file "python-"))) (org-babel-comint-with-output (session org-babel-python-eoe-indicator nil body) (let ((comint-process-echoes nil)) (funcall input-body body) (funcall dump-last-value tmp-file (member "pp" result-params)) (funcall send-wait) (funcall send-wait) (insert org-babel-python-eoe-indicator) (funcall send-wait))) (org-babel-eval-read-file tmp-file)))))) (unless (string= (substring org-babel-python-eoe-indicator 1 -1) results) (org-babel-result-cond result-params results (org-babel-python-table-or-string results))))) ------------8<------------8<------------8<------------8<---- --------8<------------8<------------8<------------ This works, but I would be surprised if this hack meets org-mode's standards. Nevertheless, maybe someone would find it useful. What do you think? How can it be improved? Best, Dror