I want to collect all inventory hosts groups variables in hierarchy data struct and send them to Consul to make them available in runtime.
Calling this method - https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory/manager.py#L160 I got the error
inventory.get_vars()
Traceback (most recent call last):
File "<input>", line 1, in <module>
inventory.get_vars()
File "<>/.virtualenvs/ansible27/lib/python2.7/site-packages/ansible/inventory/manager.py", line 160, in get_vars
return self._inventory.get_vars(args, kwargs)
AttributeError: 'InventoryData' object has no attribute 'get_vars'
my script
import pprint
pp = pprint.PrettyPrinter(indent=4).pprint
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
loader = DataLoader()
inventory = InventoryManager(loader=loader, sources='inventories/itops-vms.yml')
variable_manager = VariableManager(loader=loader, inventory=inventory)
# shows groups as well
pp(inventory.groups)
# shows dict as well with content
pp(variable_manager.get_vars())
# creates an unhandled exception
inventory.get_vars()
How to do that right way?
Python 2.7.15
ansible==2.6.2
OS Mac High Siera
The error itself seems to be caused by a bug - the get_vars method of the inventory object calls get_vars method of the InventoryData object which is not implemented.
You need to specify the group, for example:
>>> inventory.groups['all'].get_vars()
{u'my_var': u'value'}
You can create a dictionary with that data:
{g: inventory.groups[g].get_vars() for g in inventory.groups}
The above gets only the variables defined in the inventory itself (which is what the question asks about). If you wanted to get a structure with variables from group_vars, host_vars, etc. (as you indicated in your comment I want to get something similar to $ ansible-inventory -i inventories/itops-vms.yml --graph --vars you'd need to collect the data from different sources, just like Ansible does.
I tried to change the texture of an object in the blender game engine.
I thought it would be a good idea to use the Texture Replacement from the Video Texture (bge.texture).
I tried to run the following script:
def createTexture(cont):
obj = cont.owner
# get the reference pointer (ID) of the internal texture
ID = texture.materialID(obj, 'Kraftwerk2.png')
# create a texture object
object_texture = texture.Texture(obj, ID)
# create a new source with an external image
url = logic.expandPath(new_file)
new_source = texture.ImageFFmpeg(url)
# the texture has to be stored in a permanent Python object
logic.texture = object_texture
# update/replace the texture
logic.texture.source = new_source
logic.texture.refresh(False)
def removeTexture(cont):
"""Delete the Dynamic Texture, reversing back the final to its original state."""
try:
del logic.texture
except Exception as e:
print(e)
but it failed with the following error message:
Python script error - object 'Plane', controller 'Python': Traceback
(most recent call last): File
"F:\Benutzer\Merlin\MW-Industries\Blender
Dateien\Cinema\Render-Blend\MoonSpace.ble nd\Test.py", line 19, in
createTexture AttributeError: 'VideoTexture.Texture' object has no
attribute 'materialID'
Is there a way to solve the problem?
Environment
Windows 10 + python 3.6.3 64 bit (also tried 32 bit). I am a python developer trying to use COM for (nearly) the first time and hit this huge blocker.
Problem
I have had various errors when trying to use an IRTDServer implemented in a dll (not written by me), via either win32com or comtypes. Using win32com turned out to be more difficult. I have an included an example unittest for both libraries below.
Accessing the server from Excel 2016 works as expected; this returns the expected value:
=RTD("foo.bar", , "STAT1", "METRIC1")
Code using win32com library
Here is a simple test case which should connect to the server but doesn't. (This is just one version, as I have changed it many times trying to debug the problem.)
from unittest import TestCase
class COMtest(TestCase):
def test_win32com(self):
import win32com.client
from win32com.server.util import wrap
class RTDclient:
# are these only required when implementing the server?
_com_interfaces_ = ["IRTDUpdateEvent"]
_public_methods_ = ["Disconnect", "UpdateNotify"]
_public_attrs_ = ["HeartbeatInterval"]
def __init__(self, *args, **kwargs):
self._comObj = win32com.client.Dispatch(*args, **kwargs)
def connect(self):
self._rtd = win32com.client.CastTo(self._comObj, 'IRtdServer')
result = self._rtd.ServerStart(wrap(self))
assert result > 0
def UpdateNotify(self):
print("UpdateNotify() callback")
def Disconnect(self):
print("Disconnect() called")
HeartbeatInterval = -1
_rtd = RTDclient("foo.bar")
_rtd.connect()
Result:
Traceback (most recent call last):
File "env\lib\site-packages\win32com\client\gencache.py", line 532, in EnsureDispatch
ti = disp._oleobj_.GetTypeInfo()
pywintypes.com_error: (-2147467263, 'Not implemented', None, None)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test\test.py", line 23, in test_win32com
_rtd.connect()
File "test\test.py", line 16, in connect
self._rtd = win32com.client.CastTo(dispatch, 'IRtdServer')
File "env\lib\site-packages\win32com\client\__init__.py", line 134, in CastTo
ob = gencache.EnsureDispatch(ob)
File "env\lib\site-packages\win32com\client\gencache.py", line 543, in EnsureDispatch
raise TypeError("This COM object can not automate the makepy process - please run makepy manually for this object")
TypeError: This COM object can not automate the makepy process - please run makepy manually for this object
Following those directions, I ran the makepy script successfully:
> env\Scripts\python.exe env\lib\site-packages\win32com\client\makepy.py "foo.bar"
Generating to C:\Users\user1\AppData\Local\Temp\gen_py\3.5\longuuid1x0x1x0.py
Building definitions from type library...
Generating...
Importing module
(I replaced the UUID on stackoverflow for privacy. This UUID is the same as the typelib UUID for "foo.bar".)
The generated file contains various the function and type definitions of both IRtdServer and IRTDUpdateEvent. But in this file, both interfaces are subclasses of win32com.client.DispatchBaseClass, while according to OleViewDotNet, they should be subclasses of IUnknown?
However, when I attempted to run the unittest again, I received the exact same error as before. It is as if the lookup mechanism is not finding the generated module?
Also, GetTypeInfo returning Not implemented is alarming me. From my understanding, win32com uses that method (part of IDispatch COM interface) to determine the argument and return types for all other functions in other interfaces, including IRtdServer. If it's not implemented, it would be unable to determine the types correctly. Yet, the generated file seems to include this information, which is also perplexing.
Code using comtypes library
from unittest import TestCase
class COMtest(TestCase):
def test_comtypes(self):
import comtypes.client
class RTDclient:
# are these for win32com only?
_com_interfaces_ = ["IRTDUpdateEvent"]
_public_methods_ = ["Disconnect", "UpdateNotify"]
_public_attrs_ = ["HeartbeatInterval"]
def __init__(self, clsid):
self._comObj = comtypes.client.CreateObject(clsid)
def connect(self):
self._rtd = self._comObj.IRtdServer()
result = self._rtd.ServerStart(self)
assert result > 0
def UpdateNotify(self):
print("UpdateNotify() callback")
def Disconnect(self):
print("Disconnect() called")
HeartbeatInterval = -1
_rtd = RTDclient("foo.bar")
_rtd.connect()
Result:
File "test\test.py", line 27, in test_comtypes
_rtd.connect()
File "test\test.py", line 16, in connect
self._rtd = self._comObj.IRTDServer()
File "env\lib\site-packages\comtypes\client\dynamic.py", line 110, in __getattr__
dispid = self._comobj.GetIDsOfNames(name)[0]
File "env\lib\site-packages\comtypes\automation.py", line 708, in GetIDsOfNames
self.__com_GetIDsOfNames(riid_null, arr, len(names), lcid, ids)
_ctypes.COMError: (-2147352570, 'Unknown name.', (None, None, None, 0, None))
Some other solutions I've tried
(Based on googling and answers in the comments below)
(Re-)Registered the DLL
Registered the 32 bit version of the DLL and tried python 32 bit
Set compatibility mode of python.exe to Windows XP SP3
Tried not instantiating IRtdServer, that is, replacing these two lines:
self._rtd = self._comObj.IRtdServer()
result = self._rtd.ServerStart(self)
with:
result = self._comObj.ServerStart(self)
The error this time is:
TypeError: 'NoneType' object is not callable
That would seem to indicate that the ServerStart function exists, but is undefined? (Seems really weird. There must be more to this mystery.)
Tried passing interface="IRtdServer" parameter to CreateObject:
def __init__(self, clsid):
self._comObj = comtypes.client.CreateObject(clsid, interface="IRtdServer")
def connect(self):
result = self._comObj.ServerStart(self)
...
The error received is:
File "test\test.py", line 13, in __init__
self._comObj = comtypes.client.CreateObject(clsid, interface="IRtdServer")
File "env\lib\site-packages\comtypes\client\__init__.py", line 238, in CreateObject
obj = comtypes.CoCreateInstance(clsid, clsctx=clsctx, interface=interface)
File "env\lib\site-packages\comtypes\__init__.py", line 1223, in CoCreateInstance
p = POINTER(interface)()
TypeError: Cannot create instance: has no _type_
Tracing code in the comtypes library, that would seem to indicate that the interface parameter wants an interface class, not a string. I found various interfaces defined in the comtypes library: IDispatch, IPersist, IServiceProvider. All are subclasses of IUnknown. According to OleViewDotNet, IRtdServer is also a subclass of IUnknown. This leads me to believe that I need to similarly write an IRtdServer class in python in order to use the interface, but I don't know how to do that.
I noticed the dynamic parameter of CreateObject. The code indicates this is mutually exclusive to the interface parameter, so I tried that:
def __init__(self, clsid):
self._comObj = comtypes.client.CreateObject(clsid, dynamic=True)
def connect(self):
self._rtd = self._comObj.IRtdServer()
result = self._rtd.ServerStart(self)
But the error is the same as my original error: IRtdServer has _ctypes.COMError: (-2147352570, 'Unknown name.', (None, None, None, 0, None))
Any help or clues would be greatly be appreciated. Thank you in advance.
(Not really knowing what I'm doing,) I tried to use OleViewDotNet to look at the DLL:
I ran into same problem.
I also tried using win32com to get excel run that for me, that's a bit unstable to be honest...I cannot even touch my Excel.
Therefore I spent some time looking into this. The problem lies with CastTo. Think that COM object you (and I) loaded just does not contain enough information to be casted (some methods like GetTypeInfo are not implemented etc...)
Therefore I created a wrapper that makes methods of those COM objects callable...not obvious. And this seems working for me.
Client code is modified from a project called pyrtd, which didn't work for various reasons (think due to change of RTD model...return of RefreshData is just completely different now).
import functools
import pythoncom
import win32com.client
from win32com import universal
from win32com.client import gencache
from win32com.server.util import wrap
EXCEL_TLB_GUID = '{00020813-0000-0000-C000-000000000046}'
EXCEL_TLB_LCID = 0
EXCEL_TLB_MAJOR = 1
EXCEL_TLB_MINOR = 4
gencache.EnsureModule(EXCEL_TLB_GUID, EXCEL_TLB_LCID, EXCEL_TLB_MAJOR, EXCEL_TLB_MINOR)
universal.RegisterInterfaces(EXCEL_TLB_GUID,
EXCEL_TLB_LCID, EXCEL_TLB_MAJOR, EXCEL_TLB_MINOR,
['IRtdServer', 'IRTDUpdateEvent'])
# noinspection PyProtectedMember
class ObjectWrapperCOM:
"""
This object can act as a wrapper for an object dispatched using win32com.client.Dispatch
Sometimes the object written by 3rd party is not well constructed that win32com will not be able to obtain
type information etc in order to cast the object to a certain interface. win32com.client.CastTo will fail.
This wrapper class will enable the object to call its methods in this case, even if we do not know what exactly
the wrapped object is.
"""
LCID = 0x0
def __init__(self, obj):
self._impl = obj # type: win32com.client.CDispatch
def __getattr__(self, item):
flags, dispid = self._impl._find_dispatch_type_(item)
if dispid is None:
raise AttributeError("{} is not a valid property or method for this object.".format(item))
return functools.partial(self._impl._oleobj_.Invoke, dispid, self.LCID, flags, True)
# noinspection PyPep8Naming
class RTDUpdateEvent:
"""
Implements interface IRTDUpdateEvent from COM imports
"""
_com_interfaces_ = ['IRTDUpdateEvent']
_public_methods_ = ['Disconnect', 'UpdateNotify']
_public_attrs_ = ['HeartbeatInterval']
# Implementation of IRTDUpdateEvent.
HeartbeatInterval = -1
def __init__(self, event_driven=True):
self.ready = False
self._event_driven = event_driven
def UpdateNotify(self):
if self._event_driven:
self.ready = True
def Disconnect(self):
pass
class RTDClient:
"""
Implements a Real-Time-Data (RTD) client for accessing COM data sources that provide an IRtdServer interface.
"""
MAX_REGISTERED_TOPICS = 1024
def __init__(self, class_id):
"""
:param classid: can either be class ID or program ID
"""
self._class_id = class_id
self._rtd = None
self._update_event = None
self._topic_to_id = {}
self._id_to_topic = {}
self._topic_values = {}
self._last_topic_id = 0
def connect(self, event_driven=True):
"""
Connects to the RTD server.
Set event_driven to false if you to disable update notifications.
In this case you'll need to call refresh_data manually.
"""
dispatch = win32com.client.Dispatch(self._class_id)
self._update_event = RTDUpdateEvent(event_driven)
try:
self._rtd = win32com.client.CastTo(dispatch, 'IRtdServer')
except TypeError:
# Automated makepy failed...no detailed construction available for the class
self._rtd = ObjectWrapperCOM(dispatch)
self._rtd.ServerStart(wrap(self._update_event))
def update(self):
"""
Check if there is data waiting and call RefreshData if necessary. Returns True if new data has been received.
Note that you should call this following a call to pythoncom.PumpWaitingMessages(). If you neglect to
pump the message loop you'll never receive UpdateNotify callbacks.
"""
# noinspection PyUnresolvedReferences
pythoncom.PumpWaitingMessages()
if self._update_event.ready:
self._update_event.ready = False
self.refresh_data()
return True
else:
return False
def refresh_data(self):
"""
Grabs new data from the RTD server.
"""
(ids, values) = self._rtd.RefreshData(self.MAX_REGISTERED_TOPICS)
for id_, value in zip(ids, values):
if id_ is None and value is None:
# This is probably the end of message
continue
assert id_ in self._id_to_topic, "Topic ID {} is not registered.".format(id_)
topic = self._id_to_topic[id_]
self._topic_values[topic] = value
def get(self, topic: tuple):
"""
Gets the value of a registered topic. Returns None if no value is available. Throws an exception if
the topic isn't registered.
"""
assert topic in self._topic_to_id, 'Topic %s not registered.' % (topic,)
return self._topic_values.get(topic)
def register_topic(self, topic: tuple):
"""
Registers a topic with the RTD server. The topic's value will be updated in subsequent data refreshes.
"""
if topic not in self._topic_to_id:
id_ = self._last_topic_id
self._last_topic_id += 1
self._topic_to_id[topic] = id_
self._id_to_topic[id_] = topic
self._rtd.ConnectData(id_, topic, True)
def unregister_topic(self, topic: tuple):
"""
Un-register topic so that it will not get updated.
:param topic:
:return:
"""
assert topic in self._topic_to_id, 'Topic %s not registered.' % (topic,)
self._rtd.DisconnectData(self._topic_to_id[topic])
def disconnect(self):
"""
Closes RTD server connection.
:return:
"""
self._rtd.ServerTerminate()
There seems to already be both server/client for Excel 2002.
pyrtd
Looking at that source, once you create a dispatch object, then it seems to be cast to IRtdServer.
Extract related parts, it becomes below.
from win32com import client, universal
from win32com.server.util import wrap
def __init__(self, classid):
self._classid = classid
self._rtd = None
def connect(self, event_driven=True):
dispatch = client.Dispatch(self._classid)
self._rtd = client.CastTo(dispatch, 'IRtdServer')
if event_driven:
self._rtd.ServerStart(wrap(self))
else:
self._rtd.ServerStart(None)
Please refer to client.py and examples/rtdtime.py of the following sources.
pyrtd - default
pyrtd/rtd/client.py
pyrtd/examples/rtdtime.py
The code below is used as part of a SimpleXMLRPCServer to receive commands from a Java client I've written. The Java client will just call this execute function and pass in a function name from the CameraAssembler class.
from nsCamera.CameraAssembler import CameraAssembler
class MyFunctions:
ca = None
def initialize(self):
# Create Camera object
self.ca = CameraAssembler(commname=COMM, boardname=BOARD, sensorname=SENSOR, verbose=True)
return True
def execute(self, code):
func = getattr(self.ca,code)
output = func()
return output
myfuncs = MyFunctions()
myfuncs.initialize()
output = myfuncs.execute('arm()')
print(output)
Output:
Traceback (most recent call last):
File "pyTestServer.py", line 31, in <module>
output = myfuncs.execute("arm()")
File "pyTestServer.py", line 21, in execute
func = getattr(MyFunctions.ca,code)
AttributeError: CameraAssembler instance has no attribute 'arm()'
Your parentheses are in the wrong place. The attribute is not called arm(), it's called arm; you need to call the result of getting that attribute.
output = myfuncs.execute('arm')()
(Note, this code isn't particularly idiomatic. In particular, I can't see why you're setting ca as a class attribute, rather than an instance one. Also, initialisation usually goes in an __init__ method, which is called automatically on instantiation.)
Trying to use stackless python (2.7.2) with SPickle to send a test method over celery for execution on a different machine. I would like the test method (code) to be included with the pickle and not forced to exist on the executing machines python path.
Been referencing following presentation:
https://ep2012.europython.eu/conference/talks/advanced-pickling-with-stackless-python-and-spickle
Trying to use the technique shown in the checkpointing slide 11. The RPC example doesn't seem right given that we are using celery:
Client code:
from stackless import run, schedule, tasklet
from sPickle import SPickleTools
def test_method():
print "hello from test method"
tasks = []
test_tasklet = tasklet(test_method)()
tasks.append(test_tasklet)
pt = SPickleTools(serializeableModules=['__test_method__'])
pickled_task = pt.dumps(tasks)
Server code:
pt = sPickle.SPickleTools()
unpickledTasks = pt.loads(pickled_task)
Results in:
[2012-03-09 14:24:59,104: ERROR/MainProcess] Task
celery_tasks.test_exec_method[8f462bd6-7952-4aa1-9adc-d84ee4a51ea6] raised exception:
AttributeError("'module'
object has no attribute 'test_method'",)
Traceback (most recent call last):
File "c:\Python27\lib\site-packages\celery\execute\trace.py", line 153, in trace_task
R = retval = task(*args, **kwargs)
File "c:\Python27\celery_tasks.py", line 16, in test_exec_method
unpickledTasks = pt.loads(pickled_task)
File "c:\Python27\lib\site-packages\sPickle\_sPickle.py", line 946, in loads
return unpickler.load()
AttributeError: 'module' object has no attribute 'test_method'
Any suggestions on what I am doing incorrect or if this is even possible?
Alternative suggestions for doing dynamic module loading in a celeryd would also be good (as an alternative for using sPickle). I have experimented with doing:
py_mod = imp.load_source(module_name,'some script path')
sys.modules.setdefault(module_name,py_mod)
but the dynamically loaded module does not seem to persist through different calls to celeryd, i.e. different remote calls.
You must define test_method within its own module. Currently sPickle detects whether test_method is defined in a module that can be imported. An alternative way is to set the __module__ attribute of the function to None.
def test_method():
pass
test_method.__module__ = None