I would like to be able to start a testmodule that is in my CANoe script; it works fine if I start everything without Python.
Now, my Python code can load CANoe, open the desired cfg, and start the simulation.
I tried some code from examples in the documentation and here, but it doesnt work...
# --------------------------------------------------------------------------
# Standard library imports
import os
import sys
import subprocess
# import win32com.client
import time
import threading
from win32com.client import *
from win32com.client.connect import *
my_xml_ts = r"C:\_my_path\boaz_test2.xml"
# Vector Canoe Class
class CANoe:
def __init__(self):
self.application = None
# check if there is any instance of CANoe process
# output = subprocess.check_output('tasklist', shell=True)
# if CANoe process is still available, kill the process
# if "CANoe32.exe" in str(output):
# os.system("taskkill /im CANoe32.exe /f 2>nul >nul")
# re-dispatch object for CANoe Application
self.application = win32com.client.DispatchEx("CANoe.Application")
self.ver = self.application.Version
print('Loaded CANoe version ',
self.ver.major, '.',
self.ver.minor, '.',
self.ver.Build, '...')#, sep,''
self.Measurement = self.application.Measurement.Running
print(self.Measurement)
def open_simulation(self, cfgname):
# open CANoe simulation
if (self.application != None):
# check for valid file and it is *.cfg file
if os.path.isfile(cfgname) and (os.path.splitext(cfgname)[1] == ".cfg"):
self.application.Open(cfgname)
else:
raise RuntimeError("Can't find CANoe cfg file")
else:
raise RuntimeError("CANoe Application is missing,unable to open simulation")
def set_testmodule(self):
print("set_testmodule start")
test_env = self.application.Configuration.TestSetup.TestEnvironments.Item("Test Environment")
print("set_testmodule 1")
test_env = win32com.client.CastTo(test_env, "ITestEnvironment2")
print("set_testmodule 2")
self.test_module = test_env.TestModules.Item("XML_Boaz_2")
print("set_testmodule end", self.test_module)
def test_module_run(self):
print("test_module_run start")
self.test_module.Start()
print("test_module_run end")
# {.Sequence} property returns a collection of <TestCases> or <TestGroup>
# or <TestSequenceItem> which is more generic
seq = self.test_module.Sequence
for i in range(1, seq.Count + 1):
# Cast from <ITestSequenceItem> to <ITestCase> to access {.Verdict}
# and the {.Enabled} property
tc = win32com.client.CastTo(seq.Item(i), "ITestCase")
if tc.Verdict != 1: # Verdict 1 is pass
tc.Enabled = True
print(f"Enabling Test Case {tc.Ident} with verdict {tc.Verdict}")
else:
tc.Enabled = False
print(f"Disabling Test Case {tc.Ident} since it has already passed")
def close_simulation(self):
# close CANoe simulation
if (self.application != None):
self.stop_Measurement()
self.application.Quit()
# make sure the CANoe is close properly, otherwise enforce taskkill
output = subprocess.check_output('tasklist', shell=True)
if "CANoe32.exe" in str(output):
os.system("taskkill /im CANoe32.exe /f 2>nul >nul")
self.application = None
def start_Measurement(self):
retry = 0
retry_counter = 5
# try to establish measurement within 20s timeout
while not self.application.Measurement.Running and (retry < retry_counter):
self.application.Measurement.Start()
time.sleep(1)
retry += 1
if (retry == retry_counter):
raise RuntimeWarning("CANoe start measuremet failed, Please Check Connection!")
and running that:
import Python_CANoe
import time
import random
def try2():
X = random.randrange(50)
Y = random.randrange(100)
print("start")
CANoe = Python_CANoe.CANoe()
CANoe.open_simulation(canoe_config_file)
CANoe.set_testmodule() # Doesn't work
print("CANoe script already Open")
CANoe.start_Measurement()
time.sleep(5)
CANoe.test_module_run() # Doesn't work
if __name__ == "__main__":
try2()
and this is the error code I am getting:
set_testmodule start
Traceback (most recent call last):
File "C:/Users/m.m/Documents/Python/CANoe_Python_Script/7_5_2021_3_for_stackoverflow/CANoe_Boaz_Test.py", line 133, in <module>
try2()
File "C:/Users/m.m/Documents/Python/CANoe_Python_Script/7_5_2021_3_for_stackoverflow/CANoe_Boaz_Test.py", line 77, in try2
CANoe.set_testmodule() # Doesn't work
File "C:\Users\m.m\Documents\Python\CANoe_Python_Script\7_5_2021_3_for_stackoverflow\Python_CANoe.py", line 52, in set_testmodule
test_env = self.application.Configuration.TestSetup.TestEnvironments.Item("Test Environment")
File "C:\Users\BOAZ~1.BIL\LOCALS~1\Temp\gen_py\3.7\7F31DEB0-5BCC-11D3-8562-00105A3E017Bx0x1x58.py", line 15873, in Item
ret = self._oleobj_.InvokeTypes(0, LCID, 2, (9, 0), ((12, 1),),index
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, 'TestEnvironments::Item', 'Invalid index: Item not found!', 'C:\\Program Files\\Vector CANoe 11.0\\Help01\\CANoeCANalyzer.chm', 4281, -2147467259), None)
Related
I am trying to follow a ROS2 testing tutorial which tests a topic listener to understand how ROS2 testing works. Here is a screenshot of the related code at 21:15
I have a node target_control_node which subscribes the topic turtle1/pose and then move the turtle to a new random pose.
import math
import random
import rclpy
from geometry_msgs.msg import Twist
from rclpy.node import Node
from turtlesim.msg import Pose
class TargetControlNode(Node):
def __init__(self):
super().__init__("target_control_node")
self.get_logger().info("target_control_node")
self._target_pose = None
self._cmd_vel_publisher = self.create_publisher(Twist, "turtle1/cmd_vel", 10)
self.create_subscription(Pose, "turtle1/pose", self.subscribe_target_pose, 10)
self.create_timer(1.0, self.control_loop)
def subscribe_target_pose(self, msg):
self._target_pose = msg
def control_loop(self):
if self._target_pose is None:
return
target_x = random.uniform(0.0, 10.0)
target_y = random.uniform(0.0, 10.0)
dist_x = target_x - self._target_pose.x
dist_y = target_y - self._target_pose.y
distance = math.sqrt(dist_x**2 + dist_y**2)
msg = Twist()
# position
msg.linear.x = 1.0 * distance
# orientation
goal_theta = math.atan2(dist_y, dist_x)
diff = goal_theta - self._target_pose.theta
if diff > math.pi:
diff -= 2 * math.pi
elif diff < -math.pi:
diff += 2 * math.pi
msg.angular.z = 2 * diff
self._cmd_vel_publisher.publish(msg)
def main(args=None):
rclpy.init(args=args)
node = TargetControlNode()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == "__main__":
main()
I am trying to write a simple test for the subscription part based on the tutorial above to understand how it works.
Here is my initial test code. Note inside I am using expected_output=str(msg), however, it is wrong, and I am not sure what to put there.
import pathlib
import random
import sys
import time
import unittest
import uuid
import launch
import launch_ros
import launch_testing
import pytest
import rclpy
import std_msgs.msg
from geometry_msgs.msg import Twist
from turtlesim.msg import Pose
#pytest.mark.rostest
def generate_test_description():
src_path = pathlib.Path(__file__).parent.parent
target_control_node = launch_ros.actions.Node(
executable=sys.executable,
arguments=[src_path.joinpath("turtle_robot/target_control_node.py").as_posix()],
additional_env={"PYTHONUNBUFFERED": "1"},
)
return (
launch.LaunchDescription(
[
target_control_node,
launch_testing.actions.ReadyToTest(),
]
),
{
"target_control_node": target_control_node,
},
)
class TestTargetControlNodeLink(unittest.TestCase):
#classmethod
def setUpClass(cls):
rclpy.init()
#classmethod
def tearDownClass(cls):
rclpy.shutdown()
def setUp(self):
self.node = rclpy.create_node("target_control_test_node")
def tearDown(self):
self.node.destroy_node()
def test_target_control_node(self, target_control_node, proc_output):
pose_pub = self.node.create_publisher(Pose, "turtle1/pose", 10)
try:
msg = Pose()
msg.x = random.uniform(0.0, 10.0)
msg.y = random.uniform(0.0, 10.0)
msg.theta = 0.0
msg.linear_velocity = 0.0
msg.angular_velocity = 0.0
pose_pub.publish(msg)
success = proc_output.waitFor(
# `str(msg)` is wrong, however, I am not sure what to put here.
expected_output=str(msg), process=target_control_node, timeout=1.0
)
assert success
finally:
self.node.destroy_publisher(pose_pub)
When I run launch_test src/turtle_robot/test/test_target_control_node.py, it only prints this without telling me what is actual output:
[INFO] [launch]: All log files can be found below /home/parallels/.ros/log/2023-01-02-16-37-27-631032-ubuntu-linux-22-04-desktop-1439830
[INFO] [launch]: Default logging verbosity is set to INFO
test_target_control_node (test_target_control_node.TestTargetControlNodeLink) ... [INFO] [python3-1]: process started with pid [1439833]
[python3-1] [INFO] [1672706247.877402445] [target_control_node]: target_control_node
FAIL
======================================================================
FAIL: test_target_control_node (test_target_control_node.TestTargetControlNodeLink)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/my-ros/src/turtle_robot/test/test_target_control_node.py", line 91, in test_target_control_node
assert success
AssertionError
----------------------------------------------------------------------
Ran 1 test in 1.061s
FAILED (failures=1)
[INFO] [python3-1]: sending signal 'SIGINT' to process[python3-1]
[python3-1] Traceback (most recent call last):
[python3-1] File "/my-ros/src/turtle_robot/turtle_robot/target_control_node.py", line 59, in <module>
[python3-1] main()
[python3-1] File "/my-ros/src/turtle_robot/turtle_robot/target_control_node.py", line 53, in main
[python3-1] rclpy.spin(node)
[python3-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/__init__.py", line 222, in spin
[python3-1] executor.spin_once()
[python3-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 705, in spin_once
[python3-1] handler, entity, node = self.wait_for_ready_callbacks(timeout_sec=timeout_sec)
[python3-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 691, in wait_for_ready_callbacks
[python3-1] return next(self._cb_iter)
[python3-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 588, in _wait_for_ready_callbacks
[python3-1] wait_set.wait(timeout_nsec)
[python3-1] KeyboardInterrupt
[ERROR] [python3-1]: process has died [pid 1439833, exit code -2, cmd '/usr/bin/python3 /my-ros/src/turtle_robot/turtle_robot/target_control_node.py --ros-args'].
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
I checked the source code of waitFor, but still no clue.
Is there a way to print the actual output so that I can give correct expected_output? Thanks!
To answer your question(and give some more general tips): You can always print out the msg inside the node. That said, the reason you're getting an error is because msg is a ros message type, meaning it's an object. So by doing str(msg) your expected output will be something like <object of type Pose at (some_address)>; and not the actual message values. Also since it appears you're just testing a subscriber, it doesn't usually make sense to have a unit test that's expecting stdout. I would also note that you're publishing a message before actually waiting for the result, this should always fail. The reason is because by the time your subscriber is started, the message has already been published and is gone.
Finally, you shouldn't have a publisher included in any unit tests. It adds an extra dependency and since it's a prepackaged transport layer testing if it works is irrelevant. Instead to fix your problem you should simply be calling the individual methods of your node directly. Basically import the script, instantiate the object, and don't try to deal with the whole node lifecycle.
Edit based on comments
Looking at your subscriber code, you'll need to actually print something out. Unfortunately because it's not a std_msg(i.e. it has more fields than just .data) you'll need to decide how you want to go about confirming the data is right. You could simply look at one field or all of them in order. For example you might have in your test:
success = proc_output.waitFor(
expected_output=str(msg.x),
process=target_control_node, timeout=1.0)
And in your control node:
def subscribe_target_pose(self, msg):
self._target_pose = msg
print(msg.x)
That said, this IO handling method doesn't seem like the best to me. Mainly because it relies on stdout which isn't something you always want.
I am trying to copy some files to an OCI bucket (Oracle Cloud Infrastructure).
The fist 5 files are succefully copied, but then the script hangs and the processes on the task manager dies, remaining only the main one.
from array import array
from pathlib import Path
import oci
import datetime
from multiprocessing import Process
import threading
import logging
from oci.object_storage import UploadManager
from oci.object_storage.models import CreateBucketDetails
from oci.object_storage.transfer.constants import MEBIBYTE
logging.basicConfig(filename=r'############',filemode='w', format='%(asctime)s - %(message)s', level=logging.INFO)
# Number of max processes allowed at a time
concurrency= 5
sema = threading.BoundedSemaphore(concurrency)
# The root directory path, Replace with your path
p = Path(r"#####")
# The Compartment OCID
compartment_id = "#######"
# The Bucket name where we will upload
bucket_name = "######"
config = oci.config.from_file()
object_storage_client = oci.object_storage.ObjectStorageClient(config)
part_size = 2 * MEBIBYTE
today = datetime.date.today()
today = str(today)
def upload_to_object_storage(path:str,name:str,namespace):
#upload_manager = UploadManager(object_storage_client, allow_parallel_uploads=False)
with open(path, "rb") as in_file:
logging.info("Starting upload {}".format(name))
object_storage_client.put_object(namespace,bucket_name,name,in_file)
#upload_manager.upload_file(namespace, bucket_name, name, in_file.name, part_size=part_size)
logging.info("Finished uploading {}".format(name))
sema.release()
return
def createUploadProcess(object:Path,object_storage_client,namespace,proc_list):
name = object.relative_to(p).as_posix()
sema.acquire()
process = Process(target=upload_to_object_storage, args=(object.as_posix(),name,namespace))
proc_list.append(process)
process.start()
def processDirectoryObjects(object:Path,object_storage_client,namespace,proc_list):
if object.is_file():
createUploadProcess(object,object_storage_client,namespace,proc_list)
def processDirectory(path:Path,object_storage_client,namespace,proc_list):
if path.exists():
logging.info("in directory ---- " + path.relative_to(p).as_posix())
for objects in path.iterdir():
if objects.is_dir():
processDirectory(objects,object_storage_client,namespace,proc_list)
else:
if today in objects.name:
processDirectoryObjects(objects,object_storage_client,namespace,proc_list)
if __name__ == '__main__':
config = config
object_storage_client = object_storage_client
sema = sema
namespace = object_storage_client.get_namespace().data
proc_list: array = []
if p.exists() and p.is_dir():
processDirectory(p,object_storage_client,namespace,proc_list)
for job in proc_list:
job.join()
I have aproximaly 50 files to copy, but it uploads 5 and then hangs. The execution presents the following error for the 5 processes:
Process Process-1:
Traceback (most recent call last):
File "C:\Users\#######\AppData\Local\Programs\Python\Python36\lib\multiprocessing\process.py", line 258, in _bootstrap
self.run()
File "C:\Users\#######\AppData\Local\Programs\Python\Python36\lib\multiprocessing\process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\#######\Documents\copia_bkp_oci2.py", line 49, in upload_to_object_storage
sema.release()
File "C:\Users\#######\AppData\Local\Programs\Python\Python36\lib\threading.py", line 482, in release
raise ValueError("Semaphore released too many times")
ValueError: Semaphore released too many times
I am trying to upload some files to a website and so far I've tried everything I could find and nothing is working. The html input element won't let me sendKeys to it so I found this class to try and use it.
class SystemDialog:
RECURSION_LIMIT = 20
def __init__(self, application_pid, dialog_title=None):
self.__path_to_file = None
self.__recursions = 0
self.dialog_title = "Open" if dialog_title is None else dialog_title
self.accept_button = "&SaveButton" if self.dialog_title == "Save As" else "&OpenButton"
self.decline_button = "&CancelButton"
app = pywinauto.application.Application()
app.connect(process=application_pid)
self.dialog = app.window(title=self.dialog_title)
def __wait_for_dialog(self):
start = time.time()
while not self.dialog.exists() and (time.time() - start) <= 10:
time.sleep(1)
if not self.dialog.exists():
raise Exception("System Dialog did not show in 10 seconds")
def input_file_path(self, path_to_file):
self.__wait_for_dialog()
self.__path_to_file = path_to_file
if path_to_file is not None:
self.dialog.set_focus()
self.dialog.Edit.type_keys(self.__path_to_file)
return self
def accept(self):
if self.__recursions == SystemDialog.RECURSION_LIMIT:
raise Exception("Not able to accept the System dialog.")
self.__wait_for_dialog()
self.dialog.set_focus()
self.dialog[self.accept_button].click()
if self.dialog.exists():
self.__recursions += 1
if self.__path_to_file is not None:
return self.input_file_path(self.__path_to_file).accept() # <--- FYI Recursion
else:
raise Exception("Trying to accept dialog without any inputs, not gonna work.")
self.__recursions = 0
def decline(self):
if self.__recursions == SystemDialog.RECURSION_LIMIT:
raise Exception("Not able to decline the System dialog.")
self.__wait_for_dialog()
self.dialog.set_focus()
self.dialog[self.decline_button].click()
if self.dialog.exists():
self.__recursions += 1
return self.decline() # <--- Recursion
self.__recursions = 0
Here is the HTML as well
HTML
Here is me trying to send the files in my python code:
#Upload files
click(driver, 5, By.XPATH, '//*[#id="dm-react-shared-container"]/div/div[10]/div/div[1]/div[1]/div[2]/div[1]/div/div/div[5]/div/div[2]/div/div[2]', False)
click(driver, 5, By.XPATH, '//*[#id="downshift-0-label"]/div[1]/button', False)
process = psutil.Process(driver.service.process.pid) # chromedriver pid
pid = process.children()[0].pid # chrome tab pid
dialog = SystemDialog(application_pid=pid)
dialog.input_file_path(path)
dialog.accept()
I am met with this error:
Traceback (most recent call last):
File "blaineus_v2.py", line 331, in <module>
main()
File "blaineus_v2.py", line 64, in main
uploadPDFs(destination, driver, email, password, projectName)
File "blaineus_v2.py", line 324, in uploadPDFs
dialog.input_file_path(path)
File "blaineus_v2.py", line 91, in input_file_path
self.__wait_for_dialog()
File "blaineus_v2.py", line 88, in __wait_for_dialog
raise Exception("System Dialog did not show in 10 seconds")
Exception: System Dialog did not show in 10 seconds
I'm unsure again with something what I'm sure is going to be very simple...
Basically, I'm trying to make my first script call/execute a bunch of other scripts but the problem is I want each individual script to contain its own functions not be called from the first secript...
First script/main script:
from datetime import date, timedelta
from sched import scheduler
from time import time, sleep, strftime
import random
s = scheduler(time, sleep)
random.seed()
def periodically(runtime, intsmall, intlarge, function):
## Get current time
currenttime = strftime('%H:%M:%S')
## If currenttime is anywhere between 23:40 and 23:50 then...
if currenttime > '23:40:00' and currenttime < '23:50:00':
## Call clear
clear()
## Update time
currenttime = strftime('%H:%M:%S')
## Idle time
while currenttime > '23:40:00' and currenttime < '23:59:59' or currenttime >= '00:00:00' and currenttime < '01:30:00':
## Update time
currenttime = strftime('%H:%M:%S')
runtime += random.randrange(intsmall, intlarge)
s.enter(runtime, 1, function, ())
s.run()
def callscripts():
print "Calling Functions"
errors = open('ERROR(S).txt', 'a')
try:
execfile("data/secondary.py")
except Exception as e:
errors.write(str(e))
errors.write("""
""")
errors.close()
while True:
periodically(2, -1, +1, callscripts)
Below is secondary.py
import win32con
from win32api import *
from win32gui import *
class WindowsBalloonTip:
def __init__(self, title, msg):
message_map = { win32con.WM_DESTROY: self.OnDestroy,}
# Register the window class.
wc = WNDCLASS()
hinst = wc.hInstance = GetModuleHandle(None)
wc.lpszClassName = 'PythonTaskbar'
wc.lpfnWndProc = message_map # could also specify a wndproc.
classAtom = RegisterClass(wc)
# Create the window.
style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
self.hwnd = CreateWindow(classAtom, "Taskbar", style, 0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, 0, 0, hinst, None)
UpdateWindow(self.hwnd)
# Icons managment
iconPathName = "icon1.ico" ## LOCATION TO THE ICON FILE
icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
try:
hicon = LoadImage(hinst, iconPathName, win32con.IMAGE_ICON, 0, 0, icon_flags)
except:
hicon = LoadIcon(0, win32con.IDI_APPLICATION)
flags = NIF_ICON | NIF_MESSAGE | NIF_TIP
nid = (self.hwnd, 0, flags, win32con.WM_USER+20, hicon, 'Tooltip')
# Notify
Shell_NotifyIcon(NIM_ADD, nid)
Shell_NotifyIcon(NIM_MODIFY, (self.hwnd, 0, NIF_INFO, win32con.WM_USER+20, hicon, 'Balloon Tooltip', msg, 200, title))
# self.show_balloon(title, msg)
sleep(5)
# Destroy
DestroyWindow(self.hwnd)
classAtom = UnregisterClass(classAtom, hinst)
def OnDestroy(self, hwnd, msg, wparam, lparam):
nid = (self.hwnd, 0)
Shell_NotifyIcon(NIM_DELETE, nid)
PostQuitMessage(0) # Terminate the app.
# Function
def balloon_tip(title, msg):
w=WindowsBalloonTip(title, msg)
balloon_tip("test test", "Running")
def hi():
print "hi"
hi()
Error:
global name 'WindowsBalloonTip' is not defined
Full Error:
Traceback (most recent call last):
File "C:\Main.py", line 48, in <module>
periodically(2, -1, +1, callscripts)
File "C:\Main.py", line 27, in periodically
s.run()
File "C:\Python27\lib\sched.py", line 117, in run
action(*argument)
File "Main.py", line 34, in callscripts
execfile("data/secondary.py")
File "data/secondary.py", line 93, in <module>
balloon_tip("test test", "Running")
File "data/secondary.py", line 78, in balloon_tip
w=WindowsBalloonTip(title, msg)
NameError: global name 'WindowsBalloonTip' is not defined
How would I go about fixing this?
Thanks in advance
Hyflex
First of all,
class WindowsBalloonTip:
should be
class WindowsBalloonTip(object):
because the former is an old style class, which has disappeared in Python 3 and is in recent versions of Python 2.x only for backwards compatibility.
Ethan's answer is correct, but probably unclear to you if you're asking this question. A full explanation is here.
When ballon_tip() is run, it first searches the local namespace -- balloon_tip()'s namespace -- for something called WindowsBalloonTip. When it can't find it, it searches the global namespace. Since you didn't provide anything to the globals parameter to execfile(), it defaults to the namespace of callscripts(), which doesn't have anything named WindowsBaloonTip inside of it, and errors.
To fix this, you can pass globals() as an argument to execfile, but this will pollute the global namespace of your main script, which you probably don't want. You can also declare everything inside of secondary.py to be global, but you probably don't want to do that since the whole point is to test secondary.py.
The issue is execfile. execfile is an ugly, hack-y way to do things. import is better. One solution would be to write something like this inside secondary.py:
def test_harness():
balloon_tip("test test", "Running")
hi()
then, import secondary, traceback inside your main script, and change callscripts() like this:
def callscripts():
print "Calling Functions"
errors = open("ERRORS(S).txt", "a")
try:
secondary.test_harness()
except:
errors.write(traceback.format_exc() + '\n')
EDIT in response to comment:
At the top of your script, import traceback, then:
def callscripts():
print "Calling Functions"
errors = open("ERRORS(S).txt", "a")
try:
execfile("data/secondary.py", {})
except:
errors.write(traceback.format_exc() + '\n')
The problem is execfile.
Basically, execfile is a fancy exec with a file. So when you call execfile 'secondary.py' Python executes all the lines of secondary.py in the context of where execfile was called. Which, in this case, is inside the callscripts function.
What you probably want is subprocess.
I am trying to open an existing .xls document with OpenOffice using the Python 2.7 win32com module. The following script runs perfectly through an interpreter:
from win32com import client
import time
import string
def pathnameToUrl( cPathname):
"""Convert a Windows or Linux pathname into an OOo URL."""
if len( cPathname ) > 1:
if cPathname[1:2] == ":":
cPathname = "/" + cPathname[0] + "|" + cPathname[2:]
cPathname = string.replace( cPathname, "\\", "/" )
cPathname = "file://" + cPathname
return cPathname
def PropertyValueArray(num):
'''Creates an openoffice property value array'''
l = []
for x in range(num):
_p = manager.Bridge_GetStruct("com.sun.star.beans.PropertyValue")
_p.Name = ''
_p.Value = ''
l.append(_p)
return l
wbcpath = r"C:\myexcelfile.xls"
manager = client.DispatchEx("com.sun.star.ServiceManager")
desktop = manager.CreateInstance("com.sun.star.frame.Desktop")
manager._FlagAsMethod("Bridge_GetStruct")
manager._FlagAsMethod("Bridge_GetValueObject")
p = PropertyValueArray(1)
p[0].Name = 'Hidden' # doc should run hidden
p[0].Value = True # doc should run hidden
doc = desktop.loadComponentFromURL(pathnameToUrl(wbcpath), "_blank", 0, p)
doc.store()
time.sleep(5)
doc.dispose()
When I try to schedule this under Windows Task Scheduler on Windows Server Standard 2007 SP2 if get the following error:
Traceback (most recent call last):
File "D:\report_polygon_count.py", line 216, in <module>
manager = client.DispatchEx("com.sun.star.ServiceManager")
File "C:\Python27\ArcGIS10.1\lib\site-packages\win32com\client\__init__.py", line 113, in DispatchEx
dispatch = pythoncom.CoCreateInstanceEx(clsid, None, clsctx, serverInfo, (pythoncom.IID_IDispatch,))[0]
com_error: (-2146959355, 'Server execution failed', None, None)
I am sure the issue is that the application wants to open a window and it is begin rejected because there is no user logged in. I have attempted to run it as hidden to avoid this issue. Is there a way to get round this or is it too ambitious?