I am using vb.net and Arcobjects for my program. I am creating a button for ArcMap 10 that will convert a kml to a lyr file.
I am having problems passing variables into the python code. The variables are file paths and it works great if I hard code them in with / instead of . When the variables are dynamically passed in, the program breaks at the "/"s in the path names:
Dim Filelocation As OpenFileDialog = New OpenFileDialog()
Filelocation.Title = "Please point photo of the owner"
Filelocation.InitialDirectory = "B:\GeoSpatialData\Projects\004402 Griffiths\File Structure\Geospatial\GPS\KML"
If Filelocation.ShowDialog = DialogResult.OK Then
Dim kmlFile As String
kmlFile = Filelocation.FileName
Dim args As String
args = kmlFile & " " & kmlFile.Substring(0, kmlFile.LastIndexOf("\")) & " test"
Dim args2 As String = args.Replace("\", "/")
Dim procStartInfo As System.Diagnostics.ProcessStartInfo = New System.Diagnostics.ProcessStartInfo("C:\Python26\python", "C:\Users\KJacobsen\kml_to_shp.py " & args2)
' The following commands are needed to redirect the standard output.
' This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = True
procStartInfo.UseShellExecute = False
' Do not create the black window.
procStartInfo.CreateNoWindow = False
' Now you create a process, assign its ProcessStartInfo, and start it.
Dim proc As New System.Diagnostics.Process()
proc.StartInfo = procStartInfo
proc.Start()
proc.WaitForExit()
' Get the output into a string.
Dim result As String = proc.StandardOutput.ReadToEnd()
' Display the command output.
Console.WriteLine(result)
End If
Catch objException As Exception
' Log the exception and errors.
Console.WriteLine(objException.Message)
End Try
My python script looks like this:
import os
import arcpy
import sys
import glob
arcpy.KMLToLayer_conversion(sys.argv[1],sys.argv[2],sys.argv[3])
print
The path returned contains spaces? It seems so from your initial directory.
In that case the command arguments passed to the script could be wrong.
Try to enclose everything in double quotes and avoid direct manipulation of paths.
Use Path.GetDirectoryName() instead
Dim args As String
args = """" + kmlFile + """ "
args = args & """" & Path.GetDirectoryName(kmlFile) & """ test"
Replace "\" to "\\\"
Does it work?
Related
After watching ArjanCodes video on dataclasses,
I've been trying to add variables to a python dataclass from a json config file to format the font style of a print function printT in Jupyterlab.
I use ANSI escapes for the formatting which doesn't work anymore if I import the variables to the dataclass. Instead of formatting the text, the ANSI code get's printed out.
# config.json
{
"lb" : "\n",
"solid_line" : "'___'*20 + config.lb",
"dotted_line" : "'---'*20 + config.lb",
"BOLD" : "\\033[1m",
"END" : "\\033[0m"
}
# config.py
from dataclasses import dataclass
import json
#dataclass
class PrintConfig:
lb : str
solid_line : str
dotted_line : str
BOLD : str
END : str
def read_config(config_file : str) -> PrintConfig:
with open(config_file, 'r') as file:
data = json.load(file)
return(PrintConfig(**data))
# helper.py
from config import read_config
config = read_config('config.json')
def printT(title,linebreak= True,addLine = True, lineType = config.solid_line,toDisplay = None):
'''
Prints a line break, the input text and a solid line.
Inputs:
title = as string
linebreak = True(default) or False; Adds a line break before printing the title
addLine = True(default) or False; Adds a line after printing the title
lineType = solid_line(default) or dotted_line; Defines line type
toDisplay = displays input, doesnt work with df.info(),because info executes during input
'''
if linebreak:
print(config.lb)
print(config.BOLD + title + config.END)
if addLine:
print(lineType)
if toDisplay is not None:
display(toDisplay)
# test.ipynb
from helper import printT
printT('Hello World')
Output
\033[1mHello World\033[0m
'___'*20 + config.lb
Desired result
Hello World
It works if I use eval if addLine: print(eval(lineType)) but I'd like to get deeper insights into the mechanics here. Is there a way of getting it to work without eval?
Also this part "solid_line" : "'___'*20 + config.lb" feels wrong.
Markdown as alternative to ANSI
Here's a basic configuration system. I won't add the output since it would need a screenshot but it works on bash/macos. Inspired by and [tip_colors_and_formatting]
And from (https://misc.flogisoft.com/bash/tip_colors_and_formatting):
In Bash, the character can be obtained with the following syntaxes:
\e
\033
\x1B
\e didn't work, so I went on to use to \x1B since that worked in the linked SE answer. \033 works too, I checked.
from dataclasses import dataclass
PREFIX = "\x1B["
#these aren't configurable, they are ANSI constants so probably
#not useful to put them in a config json
CODES = dict(
prefix = PREFIX,
bold = f"1",
reset = f"{PREFIX}0m",
red = "31",
green = "32",
)
#dataclass
class PrintConfig:
bold : bool = False
color : str = ""
def __post_init__(self):
# these are calculated variables, none of client code's
# business:
self.start = self.end = ""
start = ""
if self.bold:
start += CODES["bold"] + ";"
if self.color:
start += CODES[self.color.lower()] + ";"
if start:
self.end = CODES["reset"]
#add the escape prefix, then the codes and close with m
self.start = f"{CODES['prefix']}{start}".rstrip(";") + "m"
def print(self,v):
print(f"{self.start}{v}{self.end}")
normal = PrintConfig()
normal.print("Hello World")
bold = PrintConfig(bold=1)
print(f"{bold=}:")
bold.print(" Hello World")
boldred = PrintConfig(bold=1,color="red")
print(f"{boldred=}:")
boldred.print(" Hello bold red")
#this is how you would do it from json
green = PrintConfig(**dict(color="green"))
green.print(" Little Greenie")
#inspired from https://stackoverflow.com/a/287934
print("\n\ninspired by...")
CSI = "\x1B["
print(CSI+"31;40m" + "Colored Text" + CSI + "0m")
print(CSI+"1m" + "Colored Text" + CSI + "0m")
This string consists of an actual backslash followed by the digits 033, etc.
"BOLD" : "\\033[1m",
To turn on bold on an ansi terminal, you need an escape character (octal 33) followed by [1m. In Python, you can write those escape codes with a single backslash: "\033[1m". In a json file, you must provide the unicode codepoint of the escape character, \u001b. If the rest is in order, you'll see boldface.
"BOLD" : "\u001b[1m",
"END" : "\u001b[0m"
As for the eval part, you have a string containing the expression you need to evaluate. I assume you wrote it this way because you first tried without the double quotes, e.g. ,
"dotted_line" : '---'*20 + config.lb,
and you got a json syntax error. That's not surprising: Json files are data, not code, and they cannot incorporate expressions or variable references. Either place your config in a python file that you include instead of loading json, or move the dependencies to the code. Or both.
In a python file, config.py:
config = {
"lb": "\n",
"solid_line" : '___'*20,
...
In helper.py:
...
if addLine:
print(lineType + config.lb)
I am trying to run a R code from the Python using Subprocess library.
I need to run one .R file from the python and have pass one single String value(args = ["INV28338"]).
I am new in R and so not able to figure out exact data type conversion code in both R and Python.
Please someone help me, how to pass single string/scalar value from Python to R Function/Model ?
Later I will give the shape of 'Flask REST API' for this code.
Thank you so much in advance
Python code:-
import subprocess
command = 'Rscript'
path2script = 'classification_model_code.R'
args = ["INV28338"]
cmd = [command, path2script] + args
x = subprocess.check_output(cmd, universal_newlines=True)
print('The Output is:', x)
R code:-
myArgs <- commandArgs(trailingOnly = TRUE)
nums = as.numeric(myArgs)
invoice_in_scope<-nums
#Followed by more code
my script, test2.R
myArgs <- commandArgs(trailingOnly = TRUE)
nums = as.character(myArgs)
print(nums)
you need to have args as part of the list, so append it to cmd and it works ok:
import subprocess
command = 'Rscript'
path2script = './test2.R'
args = "INV28338"
cmd = [command, path2script]
cmd.append(args)
x = subprocess.check_output(cmd, universal_newlines=True)
print('The Output is:', x)
I have a python script called "server.py" and inside it I have a function def calcFunction(arg1): ... return output How can I call the function calcFunction with arguments and use the return value in autohotkey? This is what I want to do in autohotkey:
ToSend = someString ; a string
output = Run server.py, calcFunction(ToSend) ; get the returned value from the function with ToSend as argument
Send, output ; use the returned value in autohotkey
I have looked online but nothing seems to fully answer my question. Can it even be done?
In order to send your parameters to Python, you could use arguments from within your Python script. You can do this with the sys library:
import sys
print(sys.argv[0]) # name of file
print(sys.argv[1]) # first argument
print(sys.argv[2]) # second argument...
From within your AutoHotKey script, you can send parameters to the Python script by adding them as arguments right after specifying the file name:
RunWait, server.py "This will be printed as the first argument!" "This is the second!"
Then, to get the output of the function back to AHK, you could use sys again by utilizing it's exit() function:
sys.exit(EXIT_NUMBER)
And back in AHK, you recieve the EXIT_NUMBER inside the variable ErrorLevel.
Put all together, your code should look something like this:
; AHK
RunWait, server.py "%ToSend%"
# Python
sys.exit(calcFunction(sys.argv[1]))
; AHK
MsgBox %ErrorLevel%
using python COM server, ahk can really calls python functions. directly.
you use it like this: MsgBox % pythonComServer.toUppercase("hello world")
simple example: return uppercased string
use the python part from How to program hotstrings in python like in autohotkey and use this for ahk part:
call python function uppercase.ahk
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, force
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
SetBatchLines, -1
#KeyHistory 0
ListLines Off
pythonComServer:=ComObjCreate("Python.stringUppercaser")
;or
; pythonComServer:=ComObjCreate("{C70F3BF7-2947-4F87-B31E-9F5B8B13D24F}") ;use your own CLSID
MsgBox % pythonComServer.toUppercase("hello world")
Exitapp
f3::Exitapp
customized version: (math) use SymPy to simplify Expression
read this first to understand: How to program hotstrings in python like in autohotkey
sympy com server.py
from sympy import simplify, Number, N
from sympy.parsing.sympy_parser import standard_transformations, implicit_multiplication_application, convert_xor
from sympy.parsing.sympy_parser import parse_expr
from decimal import Decimal
from winsound import MessageBeep
transformations = standard_transformations + (implicit_multiplication_application, convert_xor)
def removeTrailingZerosFromNum(num):
dec = Decimal(str(num))
tup = dec.as_tuple()
delta = len(tup.digits) + tup.exponent
digits = ''.join(str(d) for d in tup.digits)
if delta <= 0:
zeros = abs(tup.exponent) - len(tup.digits)
val = '0.' + ('0' * zeros) + digits
else:
val = digits[:delta] + ('0' * tup.exponent) + '.' + digits[delta:]
val = val.rstrip('0')
if val[-1] == '.':
val = val[:-1]
if tup.sign:
return '-' + val
return val
def removeTrailingZerosFromExpr(operatorObject):
if operatorObject.args:
return type(operatorObject)(*[removeTrailingZerosFromExpr(i) for i in operatorObject.args])
else:
try:
return Number(removeTrailingZerosFromNum(operatorObject))
except:
return operatorObject
def removeTrailingZerosFromExprOrNumber(operatorObject):
try:
return removeTrailingZerosFromNum(operatorObject)
except:
return removeTrailingZerosFromExpr(operatorObject)
class BasicServer:
# list of all method names exposed to COM
_public_methods_ = ["parExprN"]
#staticmethod
def parExprN(clipBak):
parsed = parse_expr(clipBak, transformations=transformations)
simplified = simplify(N(parsed))
finalStr = str(removeTrailingZerosFromExprOrNumber(simplified))
MessageBeep(-1)
return finalStr.replace("**", "^")
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Error: need to supply arg (""--register"" or ""--unregister"")")
sys.exit(1)
else:
import win32com.server.register
import win32com.server.exception
# this server's CLSID
# NEVER copy the following ID
# Use "print(pythoncom.CreateGuid())" to make a new one.
myClsid="{4530C817-6C66-46C8-8FB0-E606970A8DF6}"
# this server's (user-friendly) program ID, can be anything you want
myProgID="Python.SimplifyExpr"
import ctypes
def make_sure_is_admin():
try:
if ctypes.windll.shell32.IsUserAnAdmin():
return
except:
pass
exit("YOU MUST RUN THIS AS ADMIN")
if sys.argv[1] == "--register":
make_sure_is_admin()
import pythoncom
import os.path
realPath = os.path.realpath(__file__)
dirName = os.path.dirname(realPath)
nameOfThisFile = os.path.basename(realPath)
nameNoExt = os.path.splitext(nameOfThisFile)[0]
# stuff will be written here
# HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\${myClsid}
# HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{c2467d33-71c5-4057-977c-e847c2286882}
# and here
# HKEY_LOCAL_MACHINE\SOFTWARE\Classes\${myProgID}
# HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.SimplifyExpr
win32com.server.register.RegisterServer(
clsid=myClsid,
# I guess this is {fileNameNoExt}.{className}
pythonInstString=nameNoExt + ".BasicServer", #sympy com server.BasicServer
progID=myProgID,
# optional description
desc="(math) SymPy simplify Expression",
#we only want the registry key LocalServer32
#we DO NOT WANT InProcServer32: pythoncom39.dll, NO NO NO
clsctx=pythoncom.CLSCTX_LOCAL_SERVER,
#this is needed if this file isn't in PYTHONPATH: it tells regedit which directory this file is located
#this will write HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{4530C817-6C66-46C8-8FB0-E606970A8DF6}\PythonCOMPath : dirName
addnPath=dirName,
)
print("Registered COM server.")
# don't use UseCommandLine(), as it will write InProcServer32: pythoncom39.dll
# win32com.server.register.UseCommandLine(BasicServer)
elif sys.argv[1] == "--unregister":
make_sure_is_admin()
print("Starting to unregister...")
win32com.server.register.UnregisterServer(myClsid, myProgID)
print("Unregistered COM server.")
else:
print("Error: arg not recognized")
to register:
python "sympy com server.py" --register
sympy com client.ahk
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, force
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
SetBatchLines, -1
#KeyHistory 0
ListLines Off
sympyComServer:=ComObjCreate("Python.SimplifyExpr")
;or
; pythonComServer:=ComObjCreate("{4530C817-6C66-46C8-8FB0-E606970A8DF6}") ;use your own CLSID
; clipboard:=sympyComServer.parExprN("1+3*7")
clipboard:=sympyComServer.parExprN("1/3 + 1/2")
$#s::
clipboard:=sympyComServer.parExprN(clipboard)
return
f3::Exitapp
I'm trying to copy files in local network with scp.
It's working well with filenames without spaces, but it crash with.
I've tried to replace " " with "\ " as this exemple, but it don't work.
Here is my code:
def connection(locals):
a = (int(re.search(br'(\d+)%$', locals['child'].after).group(1)))
print a
perc = (Decimal(a)/100)
print (type(perc)), perc
while gtk.events_pending():
gtk.main_iteration()
FileCopy.pbar.set_text("Copy of the file in the Pi... " + str(a) + "%")
while gtk.events_pending():
gtk.main_iteration()
FileCopy.pbar.set_fraction(perc)
file_pc = "/home/guillaume/folder/a very large name of file with space .smthg"
file_pi = "pi#192.168.X.X:/home/pi/folder/a very large name of file with space .smthg"
if " " in file_pc:
file_pc = fichier_pc.replace(" ", '\\\ ') # tried '\\ ' or '\ '
file_pi = fichier_pi.replace(" ", '\\\ ') # but no way
else:
pass
command = "scp %s %s" % tuple(map(pipes.quote, [file_pc, file_pi]))
pexpect.run(command, events={r'\d+%': connection}) # this command is using to get the %
How can I fix this problem ?
Thanks
Use subprocess module and/or shlex.split():
import subprocess
subprocess.call(['scp', file_pc, file_pi])
and you don't need to worry about escaping or quoting anything
You may keep local file file_pc as is (pipes.quote will escape the spaces). The remote file should be changed:
import pipes
file_pi = 'pi#192.168.X.X:/home/pi/folder/file with space.smth'
host, colon, path = file_pi.partition(':')
assert colon
file_pi = host + colon + pipes.quote(path)
i.e., user#host:/path/with space should be changed to user#host:'/path/with space'
You might want to look into fabric, a Python library that streamlines the use of SSH.
from fabric.state import env
from fabric.operations import get
env.user = 'username'
env.key_filename = '/path/to/ssh-key'
get('/remote_path/*', 'local_path/')
I have created a string from
connectString = 'D:\Database\10.2.0\BIN\sqlplus.exe -L sys/PASSWORD'
output = str(call(connectstring))
this results from print output
stuff stuff stuff
stuff even more stuff
ORA-28009
stuff stuff
stuff and stuff
I do
output.find('ORA-28009')
but it does not find the string sequence. The only reason I can think of is because the string is multi line. How do I handle this?
try to normalise the string removing the special charachter.
i use a function like this:
def trim (str):
str = str.replace(' ', '')
str = str.replace('\s', '')
str = str.replace('\t', '')
str = str.replace('\r', '')
str = str.replace('\n', '')
return str
Maybe you can adapt it to your case.
best,
Ste
Try replacing
output = str(call(connectstring))
with
output = str(check_output(connectstring))
which returns the bytes from the output of the command.
This is what I did to solve it. The sPath variable is needed because I have two seperate instances of Oracle on the same server. To properly test the sys account password I needed to run the sqlplus contained in the specific dir with the correct password for that instance.
def startSQLHelper(self, sPath, sPassword):
print '--starting SQL helper--'
args = [sPath + 'sqlplus.exe', '-L', 'sys/'+sPassword]
return subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def checkOraPass (self, sPath, sPassword):
print '--checkOraPass--'
p = self.startSQLHelper(sPath, sPassword)
output = p.communicate()[0]
print output
if output.find('ORA-28009') != -1:
print 'Password passed'
return True
return False