If you are using cx_Oracle ( https://oracle.github.io/python-cx_Oracle/ ) then
the code could be like this:
import cx_Oracle
# make a connection & create cursor
conn = cx_Oracle.connect('username', 'password', 'db')
cur = conn.cursor()
# variable to colect serveroutputs into
dbmsRet = ''
# SET SERVEROUTPUT ON
cur.callproc("dbms_output.enable")
# Pl/SQL Block
mPlSql = """-- testing serveroutput --
Declare
TestMsg VarChar2(50);
Begin
TestMsg := 'Test no. 1';
DBMS_OUTPUT.PUT_LINE(TestMsg);
TestMsg := Chr(9) || TestMsg || Chr(10) || Chr(9) || 'Test no. 2';
DBMS_OUTPUT.PUT_LINE(TestMsg);
End;
"""
# Execute
mCmd = "cur.execute(mPlSql)"
exec(mCmd)
chunk = 100
# create variables to hold the output
mLine = cur.arrayvar(str, chunk)
mNumLines = cur.var(int)
mNumLines.setvalue(0, chunk)
# fetch the text that was added by PL/SQL
while True:
cur.callproc("dbms_output.get_lines", (mLine, mNumLines))
num_lines = int(mNumLines.getvalue())
lines = mLine.getvalue()[:num_lines]
for line in lines:
dbmsRet = dbmsRet + line + '\n'
if num_lines < chunk:
break
# got it
print(dbmsRet)
# R e s u l t :
# Test no. 1
# Test no. 1
# Test no. 2
Asking about pandas - if you add
import pandas as pd
and change the end of the code to
myList = []
for line in lines:
myList.append(line)
dbmsRet = dbmsRet + line + '\n'
if num_lines < chunk:
break
# got it
df = pd.DataFrame(myList)
print(df)
print(type(df))
# The Result would be
# 0
# 0 Test no. 1
# 1 \tTest no. 1\n\tTest no. 2
# <class 'pandas.core.frame.DataFrame'>
dbms_outputis possible but very cumbersome and very fragile (things start breaking as soon as you call another procedure that writes todbms_outputfor debugging purposes). It would be vastly more sensible (and common and stable) to have your procedure do something like return asys_refcursoras an output parameter and have the client application fetch data from that.sys_refcursorinto a pandas dataframe than to pull some randomdbms_outputin.