What is the equivalent to os.system in Scala? - scala

I am writing a scala program in which I would to run a system command, reading the input from stdin, and writing it's output to stdout. (So, basically just like running the command in the shell."
In python, os.system("command") has this behavior. For instance, os.system("python") opens another Python REPL when run.
In Scala, running "python" !! seems to run the process and halt immediately. What is the easiest way to do the equivalent of os.system in Scala? I feel like this can probably be done with scala.sys.process.ProcessIO, but I haven't been able to find any clear examples anywhere of how this can be done.

As long as you don't need this to work in the Scala REPL, then !< should be all you need.
%> cat so.sc
import sys.process._
object Obj extends App {
Seq("python3","-i").!<
}
%> scalac so.sc
%> scala Obj
Python 3.6.8 (default, Aug 20 2019, 17:12:48)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 4
>>> print('x: ' + str(x))
x: 4
>>> <CTL-D>
%>
Python isn't being invoked in a terminal/TTY environment so the -i option is needed to force it into interactive mode.

Related

How to use Micropython Classes in separate files

Getting started with MicroPython and having problems with classes in separate files:
In main.py:
import clientBase
import time
if __name__ == "__main__":
time.sleep(15) # Delay to open Putty
print("Starting")
print("Going to class")
cb = clientBase.ClientBaseClass
cb.process()
In clientBase.py:
class ClientBaseClass:
def __init__(self):
print("init")
def process(self):
print("Process")
Compiles and copies to Pico without errors but does not run. Putty output: No idea how to run Putty (or other port monitor) without blocking port!
MPY: soft reboot
Traceback (most recent call last):
Thanks
Python Conslole:
"C:\Users\jluca\OneDrive\Apps\Analytical Engine\Python\Client\venv\Scripts\python.exe" "C:\Program Files\JetBrains\PyCharm Community Edition 2021.2.4\plugins\python-ce\helpers\pydev\pydevconsole.py" --mode=client --port=59708
import sys; print('Python %s on %s' % (sys.version, sys.platform))
sys.path.extend(['C:\Users\jluca\OneDrive\Apps\Analytical Engine\Python\Client', 'C:\Users\jluca\AppData\Roaming\JetBrains\PyCharmCE2021.2\plugins\intellij-micropython\typehints\stdlib', 'C:\Users\jluca\AppData\Roaming\JetBrains\PyCharmCE2021.2\plugins\intellij-micropython\typehints\micropython', 'C:\Users\jluca\AppData\Roaming\JetBrains\PyCharmCE2021.2\plugins\intellij-micropython\typehints\rpi_pico', 'C:/Users/jluca/OneDrive/Apps/Analytical Engine/Python/Client'])
PyDev console: starting.
Python 3.10.3 (tags/v3.10.3:a342a49, Mar 16 2022, 13:07:40) [MSC v.1929 64 bit (AMD64)] on win32
The first problem I see here is that you're not properly instantiating the ClientBaseClass object. You're missing parentheses here:
if __name__ == "__main__":
time.sleep(15) # Delay to open Putty
print("Starting")
print("Going to class")
cb = clientBase.ClientBaseClass # <-- THIS IS INCORRECT
cb.process()
This is setting the variable cb the class ClientBaseClass, rather than creating a new object of that class.
You need:
if __name__ == "__main__":
time.sleep(15) # Delay to open Putty
print("Starting")
print("Going to class")
cb = clientBase.ClientBaseClass()
cb.process()
I don't know if that's your only problem or not; seeing your traceback will shed more details on the problem.
If I fix that one problem, it all seems to work. I'm using ampy to transfer files to my Pico board (I've also repeated the same process using the Thonny edit, which provides a menu-driven interface for working with Micropython boards):
$ ampy -p /dev/usbserial/3/1.4.2 put main.py
$ ampy -p /dev/usbserial/3/1.4.2 put clientBase.py
$ picocom -b 115200 /dev/usbserial/3/1.4.2
I press return to get the Micropython REPL prompt:
<CR>
>>>
And then type CTRL-D to reset the board:
>>> <CTRL-D>
MPY: soft reboot
And then the board comes up, the code executes as expected:
<pause for 15 seconds>
Starting
Going to class
init
Process
MicroPython v1.18 on 2022-01-17; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>>
(note that if you replace MicroPython with CircuitPython,the Pico will show up as a drive and you can just drag-and-drop files on it.)
Tried micropython and circuitpython with Pycharm, Thonny and VisualStudio code. The only thing that reliably works is CircuitPython with Mu editor. I think its all about the way the .py files are copied to the Pico board and life's too short to do more diagnostics. Mu is pretty basic but it works! Thanks for the help.

Scala: run external script with dash multiple arguments

As reported here Execute external command
in order to run an external shell command or script in Scala the right code should be:
import scala.sys.process._
val cmd = "ls -l /home" // Your command
val output = cmd.!! // Captures the output
I've noticed this works for some commands but not for others like "java -version" (especially if they have dash "-" before arguments)
Is there a correct way to execute commands like "python --version" or a more complex python script like "python /path/to/my_script.py -x value -y value" ?
Seems to work with dashes
$ scala
Welcome to Scala 2.13.6 (Eclipse OpenJ9 VM, Java 1.8.0_292).
Type in expressions for evaluation. Or try :help.
scala> import scala.sys.process._
import scala.sys.process._
scala> "java -version".!!
openjdk version "1.8.0_292"
...
scala> "python3 --version".!!
val res1: String =
"Python 3.8.5
"

Trouble invoking command with quoted string using Scala's sys.process API

As can be seen in the following console session, the same command invoked from Scala produces different results than when run in the terminal.
~> scala
Welcome to Scala 2.12.6 (OpenJDK 64-Bit Server VM, Java 1.8.0_172).
Type in expressions for evaluation. Or try :help.
scala> import sys.process._
import sys.process._
scala> """emacsclient --eval '(+ 4 5)'""".!
*ERROR*: End of file during parsingres0: Int = 1
scala> :quit
~> emacsclient --eval '(+ 4 5)'
9
Has anyone encountered this issue and/or know of a work around?
I thought this may have been a library bug, so opened an issue as well: https://github.com/scala/bug/issues/10897
It seems that Scala's sys.process api doesn't support quoting. The following works: Seq("emacsclient", "--eval", "(+ 4 5)").!.

How to work with Scala and Jcurses?

I want to use Jcurses with Scala on a 64-bit Ubuntu.
Unfortunately i didn't find any tutorial about this subject. Can anybody help me!
My test program "testjcurses.scala"
import jcurses.system._
object TestJcurses {
def main(args:Array[String]) {
println("okay")
Toolkit.init()
}
}
I processed it the following way:
fsc -cp ~/software/Java/jcurses/lib/jcurses.jar:~/software/Java/jcurses/src -d . -Djava.library.path=~/software/Java/jcurses/lib testjcurses.scala
scala -cp ~/software/Java/jcurses/lib/jcurses.jar:~/software/Java/jcurses/src:. -Djava.library.path=~/software/Java/jcurses/lib TestJcurses
The result is:
okay
java.lang.NullPointerException
at jcurses.system.Toolkit.getLibraryPath(Toolkit.java:97)
at jcurses.system.Toolkit.<clinit>(Toolkit.java:37)
at TestJcurses$.main(testjcurses.scala:9)
at TestJcurses.main(testjcurses.scala)
..........
Can anybody help me?
Unfortunately you can't use ~ in bash like that — ~ is expanded to your home dir only right after an (unquoted) space (technically, at the beginning of a bash word, but "after a space" is the simple version). Look how your command line is expanded:
$ echo scala -cp ~/software/Java/jcurses/lib/jcurses.jar:~/software/Java/jcurses/src:. -Djava.library.path=~/software/Java/jcurses/lib TestJcurses
scala -cp /Users/pgiarrusso/software/Java/jcurses/lib/jcurses.jar:~/software/Java/jcurses/src:. -Djava.library.path=~/software/Java/jcurses/lib TestJcurses
As you can see, the ~ is there in the expanded version, and will arrive unchanged to your program, which will be unable to interpret it as anything since tilde expansion is a job for the shell.
Also, you shouldn't need the source directory ~/software/Java/jcurses/src in your classpath (since source files aren't needed to run the program). So try:
scala -cp ~/software/Java/jcurses/lib/jcurses.jar:. -Djava.library.path=$HOME/software/Java/jcurses/lib TestJcurses

How to start a Scala method from command line?

This question may sound a bit stupid, but I couldn't figure out, how to start a Scala method from the command line.
I compiled the following file Test.scala :
package example
object Test {
def print() {
println("Hello World")
}
}
with scalac Test.scala.
Then, I can run the method print with scala in two steps:
C:\Users\John\Scala\Examples>scala
Welcome to Scala version 2.9.2 (Java HotSpot(TM) Client VM, Java 1.6.0_32).
Type in expressions to have them evaluated.
Type :help for more information.
scala> example.Test.print
Hello World
But what I really like to do is, to run the method directly from the command line with one command like scala example.Test.print.
How can I achieve this goal ?
UPDATE:
Suggested solution by ArikG does not work for me - What I am missing ?
C:\Users\John\Scala\Examples>scala -e 'example.Test.print'
C:\Users\John\AppData\Local\Temp\scalacmd1874056752498579477.scala:1: error: u
nclosed character literal
'example.Test.print'
^
one error found
C:\Users\John\Scala\Examples>scala -e "example.Test.print"
C:\Users\John\AppData\Local\Temp\scalacmd1889443681948722298.scala:1: error: o
bject Test in package example cannot be accessed in package example
example.Test.print
^
one error found
where
C:\Users\John\Scala\Examples>dir example
Volume in drive C has no label.
Volume Serial Number is 4C49-8C7F
Directory of C:\Users\John\Scala\Examples\example
14.08.2012 12:14 <DIR> .
14.08.2012 12:14 <DIR> ..
14.08.2012 12:14 493 Test$.class
14.08.2012 12:14 530 Test.class
2 File(s) 1.023 bytes
2 Dir(s) 107.935.760.384 bytes free
UPDATE 2 - Possible SOLUTIONs:
As ArikG correctly suggested, with scala -e "import example.Test._; print" works well with Windows 7.
See answer of Daniel to get it work without the import statement
Let me expand on this solution a bit:
scala -e 'example.Test.print'
Instead, try:
scala -cp path-to-the-target-directory -e 'example.Test.print'
Where the target directory is the directory where scala used as destination for whatever it compiled. In your example, it is not C:\Users\John\Scala\Examples\example, but C:\Users\John\Scala\Examples. The directory example is where Scala will look for classes belonging to the package example.
This is why things did not work: it expected to find the package example under a directory example, but there were no such directory under the current directory in which you ran scala, and the classfiles that were present on the current directory were expected to be on the default package.
The best way to do this is to extend App which is a slightly special class (or at least DelayedInit which underlies it is):
package example
object Test extends App {
println("Hello World")
}
It's still possible to add methods to this as well, the body of the object is executed on startup.
Here you go:
scala -e 'example.Test.print'