Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feenkcom PythonBridge extensions #10

Open
wants to merge 66 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
f9442e2
Use github://feenkcom/OSSubprocess/repository
akgrant43 Jan 8, 2021
b47dc56
Allow the runtime directory to be used without the repository present.
akgrant43 Jan 15, 2021
f9950f3
Create the symbolic link for the module
akgrant43 Jan 15, 2021
ce4af54
Pass remote exceptions back to the calling process
akgrant43 Jan 15, 2021
4245e1e
Use #isSuccess to check the OS process status in PBPharoPlatform>>for…
akgrant43 Jan 15, 2021
91bc338
Run installation script with pipenv on PATH
khinsen Jan 17, 2021
de4e0ca
Merge pull request #1 from khinsen/pipenv-on-path
akgrant43 Jan 18, 2021
f2f11cc
Add pipenvPath and workingDirectory to PBSettings
akgrant43 Jan 22, 2021
39be56b
Allow the server installation / working directory to be specified.
akgrant43 Jan 25, 2021
06fca29
PBPharoPlatform handle application directory located in image directory.
akgrant43 Jan 25, 2021
2bc0c00
Remove unused PBPharoPlatform>>ensureApplicationSymlinks:
akgrant43 Jan 25, 2021
f97b46a
Use the specified directory when installin the environment in PBPharo…
akgrant43 Jan 26, 2021
0be62a6
Don't rely on the global command factory for every instance of PBAppl…
akgrant43 Jan 26, 2021
f793d0a
PBPharoPlatform: copy runtime files keeping file attributes
akgrant43 Jan 26, 2021
ac62e12
PBSettings>>pipenvPath: typo
akgrant43 Feb 3, 2021
be12519
PBPharoPipenvProcess>>resolvePipenvPath signalPipenvNotFound fix
akgrant43 Feb 8, 2021
998547c
Pipenv path typo
akgrant43 Feb 8, 2021
310b24a
Load the v17 tag for NeoJSON
chisandrei Feb 8, 2021
b009fea
Deprecation auto-rewrite
akgrant43 Feb 9, 2021
bfedd9f
Use the pipenvPath specified in settings
akgrant43 Feb 10, 2021
72b54eb
Enable the pipenvPath and working directory to be set in PBSettings
akgrant43 Feb 11, 2021
57ffa65
Catch primitive errors in #isPythonReady, flag process as stopped in …
akgrant43 Feb 14, 2021
badca6b
PBPharoPipenvProcess: mark all servers stopped on system startup
akgrant43 Feb 15, 2021
91511e9
Update copy command to not use -r and *
chisandrei Feb 26, 2021
7b9702c
PBPharoPlatform>>copyApplicationTo:application: common copy for Mac a…
akgrant43 Mar 6, 2021
19ee614
PBPharoPlatform: don't create the directory before copying the runtim…
akgrant43 Mar 6, 2021
f3e8843
Begin extending PythonBridge to support the DAPDebugger
akgrant43 Mar 9, 2021
27c5416
Initial support for DAPDebugger
akgrant43 Mar 11, 2021
a19938c
DAPDebugger is now abstract, use DAPPythonDebugger
akgrant43 Mar 13, 2021
2dd57a5
PBObject can be subclassed with proxies that have locally defined vie…
akgrant43 Mar 15, 2021
e13f2e8
Add convenience function pbbreak()
akgrant43 Mar 15, 2021
8cabdaa
Install debugpy as part of the python environment
akgrant43 Mar 15, 2021
521b83d
Add tfactorial.py test file
akgrant43 Mar 15, 2021
61790cc
PBPharoPipenvProcess: request the workingDirectory from the PBApplica…
akgrant43 Mar 16, 2021
a828134
Add PBPythonError>>gtTraceFor:
akgrant43 Mar 16, 2021
12bba01
PBPromise>>waitForValue signal that the DAP debugger should be used t…
akgrant43 Mar 17, 2021
83059d4
Move Gt views to Gt4PythonBridge
akgrant43 Mar 22, 2021
ba96617
Add PythonCommandStringFactory
akgrant43 Mar 27, 2021
df306c7
Quote directory names when installing the runtime to allow spaces in …
akgrant43 Mar 30, 2021
8c040ad
[Enh]: Start if Needed on `uniqueInstance` Access
seandenigris Apr 1, 2021
f698e35
Merge pull request #3 from seandenigris/enh_start-if-needed
akgrant43 Apr 6, 2021
158c224
Add PBApplication>>installModule:
akgrant43 Apr 12, 2021
487f3e4
Stop PBApplication on shutdown
seandenigris Apr 13, 2021
22b6ffe
Merge pull request #4 from seandenigris/enh_stop-on-shutdown
akgrant43 Apr 15, 2021
3b1d3f4
Restructure PythonBridge runtime
akgrant43 Jun 8, 2021
d629e0c
Avoid copying the entire disk on Mac when the repository doesn't exist
akgrant43 Jun 8, 2021
254d6cd
Add class variable: RuntimeSourceDirectory
akgrant43 Jun 8, 2021
20724b7
PBPharoPlatform class>>runtimeSourceDirectory: don't resolve a file l…
akgrant43 Jun 9, 2021
dc2c833
Update PBPharoPlatform method comments
akgrant43 Jun 9, 2021
38a5976
Add PBApplication>>pythonServerStatus
akgrant43 Jun 10, 2021
99cbf34
PBApplication>>pythonServerStatusOn: Add stdout and stderr
akgrant43 Jun 10, 2021
8468554
Improve error handling to show stdio when something goes wrong.
akgrant43 Jun 10, 2021
ce82f85
PBPythonProcessError>>printOn: print the message text if set.
akgrant43 Jun 10, 2021
1250569
PBApplication>>waitInitialization improve the error information
akgrant43 Jun 10, 2021
51fc1df
Add PBApplication class>>killAll
akgrant43 Jun 11, 2021
f8ee31a
Add killpbserver.sh script
akgrant43 Jun 11, 2021
fb2fe37
PbApplication:>>pythonServerStatusOn:process: add exit status
akgrant43 Jun 11, 2021
3ccfce1
PBPharoPlatform: set the executable bit on shell scripts
akgrant43 Jun 11, 2021
29739c9
Modify killpbservers.sh grep expression to something that should work…
akgrant43 Jun 15, 2021
0a79379
PBSettings add Settings view in inspector
akgrant43 Jun 15, 2021
b6ad2bc
Indicate when the external server executable can't be found
akgrant43 Jun 15, 2021
5b2a0d7
PBMessageBrokerTest fix broken tests
akgrant43 Jun 16, 2021
8fb1989
Add PbPythonError>>summaryText
akgrant43 Jun 17, 2021
3c5df2c
Replace GtUnixSubprocess with PBUnixSubprocess to facilitate using Py…
akgrant43 Jun 22, 2021
4d06d47
BaselineOfPythonBridge: use OSSubprocess from pharo-contributions
akgrant43 Jun 25, 2021
2b47fed
Change OSSubprocess to 'github://feenkcom/OSSubprocess:main/repository'.
akgrant43 Jun 25, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
from PythonBridge.bridge_hooks import *
from PythonBridge.object_registry import registry

def pbbreak():
print("Breaking now")
breakpoint()
print("Continuing")


class EvalCommand:
statements = ""
binding = {}
Expand Down Expand Up @@ -158,4 +164,4 @@ def run_bridge():
bridge_globals.logger.log("PYTHON: Finished command execution")

if __name__ == "__main__":
run_bridge()
run_bridge()
File renamed without changes.
36 changes: 36 additions & 0 deletions PythonBridgeRuntime/PythonBridge/tfactorial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import argparse
import threading
import time


# Calculate the factorial
def factorial(n, t):
time.sleep(n*t/4)
print("Start: " + str(t) + ": " + str(n))
if n == 1:
res = 1
if t == 1:
print("Feel free to break here")
else:
res = n * factorial(n-1, t)
return res


# Calculate the factorial and print the result
def factorial_thread(n, t):
time.sleep(2)
result = factorial(n, t)
print("Thread " + str(t) + " = "+str(result))


def launch_factorials(n):
threads = []
print("Calculate: "+str(n))
breakpoint()
for i in range(n):
threads.append(threading.Thread(target=factorial_thread, args=(n+i, i+1)))
threads[-1].start()
print("Wait for the results")
for thread in threads:
thread.join()
print("Done")
File renamed without changes.
3 changes: 2 additions & 1 deletion install_env.sh → PythonBridgeRuntime/install_env.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/bin/bash
cd "$(dirname "$0")"
export PIPENV_VENV_IN_PROJECT=1
pipenv install
pipenv install
pipenv run pip install debugpy
18 changes: 18 additions & 0 deletions PythonBridgeRuntime/killpbservers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

# Kill all the PythonBridge servers running on localhost.
# This assumes they are being run as the current user.
# Any associated debug server processes will automatically exit.

# List the processes.
# If none are found, exit successfully
ps aux | grep -E 'PythonBridgeRuntime/start_bridge\.py.*msgpack'
status=$?
if [ $status -eq 1 ]
then
exit 0
fi

# Kill them
ps aux | grep -E 'PythonBridgeRuntime/start_bridge\.py.*msgpack' | awk '{print $2}' | xargs kill
exit $?
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions src/BaselineOfPythonBridge/BaselineOfPythonBridge.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ BaselineOfPythonBridge >> baseline: spec [
do: [
spec
baseline: 'OSSubprocess'
with: [ spec repository: 'github://pharo-contributions/OSSubprocess:v1.0.0/repository' ].
with: [ spec repository: 'github://feenkcom/OSSubprocess:main/repository' ].
spec
baseline: 'Python3Generator'
with: [ spec repository: 'github://juliendelplanque/Python3Generator:v2.0.0/repository' ].
spec baseline: 'NeoJSON' with: [
spec
repository: 'github://svenvc/NeoJSON/repository' ].
repository: 'github://svenvc/NeoJSON:v17/repository' ].
spec baseline: 'MessagePack' with: [
spec
repository: 'github://msgpack/msgpack-smalltalk:v1.3.1/repository' ].
Expand Down
11 changes: 11 additions & 0 deletions src/PythonBridge-Pharo/PBMsgPackPharoBrokerTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ PBMsgPackPharoBrokerTest >> sendMessageToBroker: dict answerBlock: aBlock [
self sleepAWhile.
]

{ #category : #utils }
PBMsgPackPharoBrokerTest >> sendMessageToBroker: dict answerEquals: ansDict [
| flag |
flag := false.
self sendMessageToBroker: dict answerBlock: [ :anAssoc |
flag := true.
self assert: anAssoc value equals: ansDict ].
self sleepAWhile.
self assert: flag
]

{ #category : #utils }
PBMsgPackPharoBrokerTest >> sleepAWhile [
(Delay forMilliseconds: 50) wait
Expand Down
163 changes: 146 additions & 17 deletions src/PythonBridge-Pharo/PBPharoPipenvProcess.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,58 @@ Class {
#superclass : #PBAbstractProcess,
#instVars : [
'process',
'environmentVariables'
'environmentVariables',
'serverDebugger'
],
#classVars : [
'PipenvPath'
],
#category : #'PythonBridge-Pharo-Processes'
}

{ #category : #'class initialization' }
PBPharoPipenvProcess class >> initialize [

SessionManager default registerUserClassNamed: self name.
]

{ #category : #initialization }
PBPharoPipenvProcess class >> pipenvPath [
^ PipenvPath isEmptyOrNil
ifTrue: [ PipenvPath := self resolvePipenvPath ]
ifFalse: [ PipenvPath ]
^ PipenvPath
ifNil: [ PipenvPath := self resolvePipenvPath ]
ifNotNil: [ PipenvPath ]
]

{ #category : #initialization }
PBPharoPipenvProcess class >> pipenvPath: aString [
PipenvPath := aString
PBPharoPipenvProcess class >> pipenvPath: aFileReference [
PipenvPath := aFileReference
]

{ #category : #accessing }
PBPharoPipenvProcess class >> platform [
^ PBPharoPlatform current
]

{ #category : #initialization }
PBPharoPipenvProcess class >> reset [
<script>

PipenvPath := nil.
]

{ #category : #initialization }
PBPharoPipenvProcess class >> resolvePipenvPath [
^ (OSSUnixSubprocess new
| path |

(OSSUnixSubprocess new
command: '/usr/bin/which';
arguments: (Array with: 'pipenv');
addAllEnvVariablesFromParentWithoutOverride;
redirectStdout;
terminateOnShutdown;
runAndWaitOnExitDo: [ :command :outString | ^ outString trim ])
ifEmpty: [ self signalPipenvNotFound ]
runAndWaitOnExitDo: [ :command :outString | path := outString trim ]).
path ifEmpty: [ self signalPipenvNotFound ].
^ path asFileReference
]

{ #category : #initialization }
Expand All @@ -55,14 +72,38 @@ PBPharoPipenvProcess class >> signalPipenvNotFound [
Error signal: 'Error: Pipenv command could not be found.'
]

{ #category : #'system startup' }
PBPharoPipenvProcess class >> startUp: resuming [
"On startup any instances saved during the last session will be invalid (since the processes are terminated on shutdown). Mark them as stopped."

resuming ifTrue:
[ self allInstancesDo: [ :each | each stop ] ]
]

{ #category : #'start-stop' }
PBPharoPipenvProcess >> debuggerStateChangedAction: aDAPThreadStateChanged [
"Respond to the debugger state changed notification.
Signal all promises that the debugger has been paused."

aDAPThreadStateChanged isStopped ifTrue:
[ self application notifyDebuggerPaused: serverDebugger ]
]

{ #category : #accessing }
PBPharoPipenvProcess >> environmentVariables [
^ environmentVariables
]

{ #category : #accessing }
PBPharoPipenvProcess >> errorMessage [
^ process stderrStream contents
^ self stderr
]

{ #category : #testing }
PBPharoPipenvProcess >> hasProcess [
"Answer a boolean indicating whether the receiver has a process object"

^ process isNotNil
]

{ #category : #initialization }
Expand All @@ -72,6 +113,36 @@ PBPharoPipenvProcess >> initialize [
self setDefaultEnvironmentVariables
]

{ #category : #utils }
PBPharoPipenvProcess >> installModule: aString in: aPBApplication [
"Install the supplied module using `pipenv run pip install aString`"
| pipenvPath proc arguments stdoutStream stderrStream |

pipenvPath := aPBApplication settings pipenvPath ifNil: [ self class pipenvPath ].
arguments := { 'run'. 'pip'. 'install'. aString. }.
stdoutStream := String new writeStream.
stderrStream := String new writeStream.
proc := OSSUnixSubprocess new
command: pipenvPath fullName;
arguments: arguments;
workingDirectory: aPBApplication workingDirectory fullName;
addAllEnvVariablesFromParentWithoutOverride;
terminateOnShutdown;
redirectStdout;
redirectStderr;
yourself.
environmentVariables associationsDo: [ :assoc |
proc environmentAt: assoc key put: assoc value ].
proc run.
proc
waitForExitPollingEvery: (Delay forMilliseconds: 500)
doing: [ :aProcess :outStream :errStream |
stdoutStream nextPutAll: outStream upToEnd.
stderrStream nextPutAll: errStream upToEnd ].
proc isSuccess ifFalse:
[ self error: 'Unable to install module: ', aString asString ].
]

{ #category : #testing }
PBPharoPipenvProcess >> isRunning [
^ process
Expand All @@ -82,20 +153,28 @@ PBPharoPipenvProcess >> isRunning [
{ #category : #private }
PBPharoPipenvProcess >> newProcess [
| newProcess |
newProcess := OSSUnixSubprocess new
command: self class pipenvPath;

newProcess := PBUnixSubprocess new
command: (self settings pipenvPath ifNil:
[ self class pipenvPath ]) fullName;
arguments: self processArguments;
workingDirectory: self workingDirectory fullName;
addAllEnvVariablesFromParentWithoutOverride;
redirectStdout;
redirectStderr;
terminateOnShutdown;
yourself.
environmentVariables associationsDo: [ :assoc |
newProcess environmentAt: assoc key put: assoc value ].
^ newProcess
]

{ #category : #accessing }
PBPharoPipenvProcess >> pipenvPath [
"Answer the default pipenvPath.
This may be overridden by the application settings."

^ self class pipenvPath
]

{ #category : #accessing }
PBPharoPipenvProcess >> process [
^ process
Expand All @@ -104,10 +183,19 @@ PBPharoPipenvProcess >> process [
{ #category : #private }
PBPharoPipenvProcess >> processArguments [
| args |

args := OrderedCollection new.
args
add: 'run';
add: 'python';
add: 'python'.
self settings serverDebugMode ifTrue:
[ args addAll: {
'-m'.
'debugpy'.
'--listen'.
self settings debugSocketAddress printAddress.
'--wait-for-client'. } ].
args
add: self pythonMainFile fullName;
add: '--port';
add: self settings pythonSocketAddress port asString;
Expand All @@ -131,14 +219,55 @@ PBPharoPipenvProcess >> setDefaultEnvironmentVariables [
{ #category : #'start-stop' }
PBPharoPipenvProcess >> start [
process := self newProcess.

process run.
self settings serverDebugMode ifTrue:
[ self startServerDebugger ].
]

{ #category : #'start-stop' }
PBPharoPipenvProcess >> startServerDebugger [
"Start the debugger, tell the server to run and set up inspection on halt"

"Give the server time to start"
1 second wait.
serverDebugger := DAPPythonDebugger new
localRoot: self workingDirectory;
connectTo: #[127 0 0 1] port: self settings debugSocketAddress port.
serverDebugger announcer
when: DAPThreadStateChanged
do: [ :announcement | self debuggerStateChangedAction: announcement ].

]

{ #category : #accessing }
PBPharoPipenvProcess >> stderr [
"Answer the process stderr contents"

^ process stderr
]

{ #category : #accessing }
PBPharoPipenvProcess >> stdout [
"Answer the process stdout contents"

^ process stdout
]

{ #category : #'start-stop' }
PBPharoPipenvProcess >> stop [
process ifNil: [ ^ self ].
[process queryExitStatus ifNil: [ process terminate ]]
[ process queryExitStatus ifNil: [ process terminate ]]
on: Error
do: [ :e | "Do nothing."].
process closeAndCleanStreams
process closeAndCleanStreams.
process := nil.
]

{ #category : #'start-stop' }
PBPharoPipenvProcess >> stopServerDebugger [
"Close the debugger and deregister"

serverDebugger close.
serverDebugger announcer unsubscribe: self debuggerStateChangedAction
]
Loading