Tôi đang làm việc trên tập dữ liệu từ MOOC. Tôi có rất nhiều đoạn mã python3 mà tôi cần để chạy và nhận được kết quả từ đó. Để làm điều này tôi đã viết một kịch bản python lặp lại trên mỗi đoạn mã. Đối với mỗi đoạn mã I:Mã chạy an toàn trong một quy trình, chuyển hướng stdout trong multithreading.Process
- Tạo mới StringIO đối tượng
- Đặt
sys.stdout
vàsys.stderr
để đệm StringIO tôi - Execute đoạn mã trong một đối tượng
threading.thread
Tham gia vào chủ đề- Log các kết quả trong bộ đệm chuỗiIOIO
- Khôi phục thiết bị xuất chuẩn và tiêu chuẩn cảnh quan
này hoạt động tốt cho mã "đúng", nhưng điều này có vấn đề trong trường hợp khác:
- Khi mã có một vòng lặp vô hạn, Thread.Join không diệt các sợi. Chủ đề là một chuỗi daemon, vì vậy nó chạy lặng lẽ trong nền cho đến khi vòng lặp của tôi kết thúc.
- Khi mã có vòng lặp vô hạn với
print()
, chủ đề bắt đầu ghi đè lên giá trị thực của tôi khi tôi đặt nó trở về mặc định (cách xa bộ đệm StringIO). Điều này gây ô nhiễm cho báo cáo của tôi.
Đây là mã hiện tại của tôi:
def execCode(code, testScript=None):
# create file-like string to capture output
codeOut = io.StringIO()
codeErr = io.StringIO()
# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr
def worker():
exec(code, globals())
if testScript:
# flush stdout/stderror
sys.stdout.truncate(0)
sys.stdout.seek(0)
# sys.stderr.truncate(0)
# sys.stderr.seek(0)
exec(testScript)
thread = threading.Thread(target=worker, daemon=True)
# thread = Process(target=worker) #, stdout=codeOut, stderr=codeErr)
thread.start()
thread.join(0.5) # 500ms
execError = codeErr.getvalue().strip()
execOutput = codeOut.getvalue().strip()
if thread.is_alive():
thread.terminate()
execError = "TimeError: run time exceeded"
codeOut.close()
codeErr.close()
# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
# restore any overridden functions
restoreBuiltinFunctions()
if execError:
return False, stripOuterException(execError)
else:
return True, execOutput
Để xử lý trường hợp này, tôi đã cố gắng sử dụng multithreading.Process
và/hoặc contextlib.redirect_stdout
để chạy mã trong một quá trình (sau đó tôi có thể gọi process.terminate()
) nhưng tôi không có bất kỳ thành công nào trong việc thu thập stdout/stderr.
Vì vậy, câu hỏi của tôi là: Làm thế nào tôi có thể chuyển hướng hoặc chụp stdout/stderr từ một quá trình? Ngoài ra, có cách nào khác tôi có thể đi về cố gắng để chạy và nắm bắt đầu ra của mã tùy ý?
(Và vâng, tôi biết đây là một ý tưởng tồi nói chung; Tôi đang chạy nó trong một máy ảo chỉ trong trường hợp có mã độc trong một nơi nào đó)
phiên bảnPython là 3.5.3
cập nhật
Nó xảy ra với tôi rằng có một chút linh hoạt hơn trong tình huống này. Tôi có một hàm, preprocess(code)
chấp nhận việc gửi mã dưới dạng chuỗi và thay đổi nó. Chủ yếu là tôi đã sử dụng nó để hoán đổi giá trị của một số biến bằng cách sử dụng cụm từ thông dụng.
Đây là một thực hiện ví dụ:
def preprocess(code):
import re
rx = re.compile('earlier_date\s*=\s*.+')
code = re.sub(rx, "earlier_date = date(2016, 5, 3)", code)
rx = re.compile('later_date\s*=\s*.+')
code = re.sub(rx, "later_date = date(2016, 5, 24)", code)
return code
tôi có thể sử dụng chức năng preprocess để giúp chuyển hướng STDOUT
Bạn đã xem 'đăng nhập' chưa? – igrinis
Tôi có một số đăng nhập. Công việc hiện tại của tôi xung quanh là bật đăng nhập khi tôi gặp phải một vòng lặp vô hạn. Tôi sử dụng tính năng ghi nhật ký để theo dõi và xóa đoạn mã vi phạm nhưng đây là quy trình thủ công không thể tự động được (Nếu tôi có thể tự động hóa, tôi sẽ không cần đăng nhập bất kỳ thứ gì, tôi có thể hủy bỏ, xóa bản ghi và tiếp tục) – Zack
Còn về ['subprocess.check_output'] (https://docs.python.org/3/library/subprocess.html#subprocess.check_output)? Bạn có thể gọi 'python -c {snippet}' với nó, hoặc nếu nó dài hơn, chỉ cần viết đoạn mã vào một tệp '.py' tạm thời. 'check_output' (và thực sự, tất cả các hàm khác trong' subprocess') có tham số 'timeout'. –