from win32com.client import Dispatch
oAccess = Dispatch("Access.Application")
oAccess.Visible = False
oAccess.OpenCurrentDatabase(my_db)
oDB = oAccess.CurrentDB
for tbl in oDB.TableDefs:
print(table.Name)
tbl.RefreshLink
I've also done:
for tbl in oAccess.TableDefs:
print(table.Name)
tbl.RefreshLink
Error: 'function' object has no attribute 'TableDefs'
I'm starting to understand how to manipulate Windows using win32com, but for some reason it seems like ".TableDefs" isn't recognized. Am I going about it the wrong way?
I know this can be done in VBA. I've been tasked with switching everything over to Python.
Your first error, here, is that VBA knows CurrentDb is a method, and can't assign a method to a variable, so it invokes the method.
Python, however, has 0 problems with assigning a method to a variable, so just does so. Which means you need the parentheses to invoke the method:
oDB = oAccess.CurrentDb()
This fixes the immediate issue (same goes for tbl.RefreshLink, this likely should be tbl.RefreshLink()).
Furthermore, you never define table, only tbl, so you likely want print(tbl.Name).
Related
I am using pywin32 to automate some tasks in software that has an Automation Server technology interface (formerly OLE Automation Server).
This software comes with a somewhat detailed manual with code examples in VBA, C++ or Matlab but no Python. I have built a Python library that can do most of the functionalities built into the software but there are some parts I cannot do in Python.
I cannot change the value of a property if this property is contained in a iterable COM object.
What I can do:
[Documentation for Visibility property]
import win32com.client
app = win32com.client.Dispatch('NAME_OF_APP')
app.Visibility = True
As an example, with this code, I can change the visibility parameter of the software: if it runs with or without GUI.
What I cannot do:
[Documentation for getting and setting current device]
import win32com.client
app = win32com.client.Dispatch('NAME_OF_APP')
app.CurrentDevice(0) = 'NAME OF DEVICE'
I then get the following error:
SyntaxError: cannot assign to function call here. Maybe you meant '==' instead of '='?
This error makes sense to me but I cannot find a way to set any of these software properties when they come in the form of an iterable object. As soon as I have to specify an index, I don't know how to set the value.
From what I understand, in C++ we are able to change the value because of pointers but how can we achieve the same thing in Python? Is it possible or do I have to use some C++ code in parallel to my Python to run my library? I don't know anything in C++ so if I could avoid doing that, it would be good.
What I have tried
Of course, the 1st thing I tried was to change () to [] or {} which logically didn't work.
Then I used the Evaluate function in PyCharms to see what was hiding behind my app.CurrentDevice. I was hoping to find sub-attributes that I could then set but I don't see anything inside the object:
[Result of Evaluate on the CurrentDevice object]
Finally, I have tried the following:
import win32com.client
app = win32com.client.Dispatch('NAME_OF_APP')
curr_device = app.CurrentDevice(0)
curr_device = 'NAME OF DEVICE'
I wanted to affect the object to a variable and then change the value but of course, this only rewrites the variable curr-device with 'NAME OF DEVICE' but loses any link to COM Object.
I feel like my questions are similar to the following unanswered question:
How can I set the value of an indexed property of a COM object in Python?
It looks as if win32com is struggling to set the property if there is an additional argument to the put function, which is a little surprising.
First thing to do is to use
app = win32com.client.gencache.EnsureDispatch('NAME_OF_APP')
This creates a Python wrapper for the COM object (rather than just firing function calls at the object and hoping). This may in itself clear up your issue.
If not, here is a quite ugly way of working around. As you have identified, the relevant part of the type library is:
[id(0x00000018),propput, helpstring("property CurrentDevice")]
HRESULT CurrentDevice([in] long lAcq, [in] VARIANT pVal);
And you can use this to set the property at a low level.
win32com dispatch objects are a wrapper for the PyIDispatch object. All dispatch objects support the Invoke method, and you can use this to call the function yourself. NB. Since I don't have access to your COM object, I can't test, so this answer may need some tweaking (!).
The PyIDispatch documentation
Try:
import win32com.client as wc
import pythoncom
app = wc.gencache.EnsureDispatch('NAME OF APP')
app.Visibility=TRUE
newVal = wc.VARIANT(pythoncom.VT_VARIANT,'NAME OF DEVICE')
app._oleobj_.Invoke(24,0,pythoncom.INVOKE_PROPERTYPUT,0,0,newVal)
There are a lot of 'magic' numbers here, but basically:
24 = 0x00000018 in decimal: this is the Id of the property
0 = the LCID, the Locale Id ... I always set it to 0
pythoncom.INVOKE_PROPERTYPUT = the type of call.
0 = whether you care about the return type (you probably don't = False)
0 = first parameter, lAcq, as in CurrentDevice(0)
newVal = second paramter,pVal, the new device name as a VARIANT
I haven't tried this, but pythoncom is pretty good about converting VARIANT types, so you might not need the VARIANT creation, and can just use NAME OF DEVICE directly as the parameter.
I was trying to find out the methods of the pywin32 object of a userform ComboBox in Excel, but I honestly has no idea what I'm doing and got nowhere.
VBA Code (Sending combobox object to python):
Private Sub ComboBox1_Change()
s = test(ComboBox1)
End Sub
Python Code :
#xw.func
def test(obj):
print(obj._dict__)
So, the print above returned this :
{'_oleobj_': <PyIDispatch at 0x03957A90 with obj at 0x01218C8C>, '_username_': 'IMdcCombo', '_olerepr_': <win32com.client.build.LazyDispatchItem object at 0x03FB0FD0>, '_mapCachedItems_': {}, '_builtMethods_': {}, '_enum_': None, '_unicode_to_string_': None, '_lazydata_': (<PyITypeInfo at 0x03957B50 with obj at 0x0121919C>, <PyITypeComp at 0x03957B68 with obj at 0x012196F4>)}
I guess I was expecting to see the same methods/properties found in VBA, but I have no idea what to take from this.
Anyone knows a way to manipulate userform/controls directly from python using xlwings?
Specifically I'm looking for dynamically adding new controls to the userform, reading/modifying controls attributes, and ideally modifying their events, all through python.
I guess I was expecting to see the same methods/properties found in VBA, but I have no idea what to take from this.
You can take anything from this, but this isn't a real Combobox nor something from COM environment - it's just a "wrapper" object over a COM object, implemented via IDispatch interface, and it's possibily thanks to the win32com dependency.
Because of that there's no an "intellisense"-like feature, but you're still able to use properties/methods:
#xw.func
def test(obj):
# accesing method
obj.AddItem('Hello world!')
# accesing property
obj.Enabled = False
also you can pass an UserForm as obj to add a new control to it:
#xw.func
def test(obj):
# add new label
control = obj.Add('Forms.Label.1')
# accesing property
control.Caption = 'Hello world!'
When looking under the documentation for xlWings under the Shapethere does seem to be access to all properties.
Under missing features, you can find a workaround using .api to access all vba methods. Through this you could create and modify controls, just like you would do in VBA.
Also what you could do is using the macro(name)-function you could create functions in VBA to modify, create comboboxes and pass values to the function, i.e to create a combobox at position x, y , width, height and pass these parameters trough python.
As it seems, you cannot access events trough xlWings. But i've found IronPython, it uses the .NET interop facilities to access the excel object and events. As you can see under the documentation, you can work with the excel object as you would do in C#, VB.NETetc..
So as a conclusion, i would suggest you looking up the documentations of both. As they both reveal the excel object to python you should be able to do what you want with one of them.
I'm writing a small app in Django and I'm keeping the state saved in a few variables I declare out of the methods in views.py. Here is the important part of this file:
from app.playerlist import fullList
auc_unsold = fullList[:]
auc_teams = []
auc_in_progress = []
auc_current_turn = -1
print(auc_in_progress)
def auc_action(request):
data = json.loads(request.GET["data"])
# ...
elif data[0] == "start":
random.shuffle(auc_teams)
print(auc_unsold)
print(auc_in_progress)
auc_in_progress = [None, 0, None]
print(auc_in_progress)
The auc_unsold and auc_teams variables work fine; the auc_in_progress variable is not seen by this method, though, giving the error in the title. If I take out the print statement and let this code assign a value to it, the exception will be thrown somewhere else in the code as soon as I use that variable again.
I have tried making another variable and this new one seems to suffer from this problem as well.
What is happening?
Edit: I found a solution: if I write global auc_in_progress just before the print statements, then everything works fine. If I try writing that as I declare the variable above it doesn't work, though, for some reason.
I am unsatisfied with this, because I don't know why this happens and because I dislike using global like that, but eh. Someone has an explanation?
You should absolutely not be doing this, either your original code or your proposed solution with global.
Anything at module level will be shared across requests, not only for the current user but for all users for that process. So everyone will see the same auction, etc.
The reason for your error is because you assign to that variable within your function, which automatically makes it a local variable: see this question for more details. But the solution recommended there, which is the same as your workaround - ie use global - is not appropriate here; you should store the data somewhere specifically associated with the user, eg the session.
Python 3.5.1
Could you have a look at the code and the picture.
This is some Django code, but the question relates to Python.
Well, I get the error:
Exception Value:
name 'objects' is not defined
Exception Location:
/home/michael/workspace/pharchive/pharchive/general/templatetags/md_aux.py in get_aux_info, line 17
Line 17 is context = Context({"objects": objects}). In the picture it is visible.
I tried to add objects=[] a little above. But that didn't help. In this case objects was really empty. So, I commented it out.
Well, in the screenshot we can what we get if we stop at the breakpoint. We can see that objects var is really accessible in the context. And it contains something.
Anyway, I got stuck with variable scope.
I don't understand:
1. Why objects=[] didn't help me.
2. Why I get this error whereas objects is accessible.
Could you give me a kick here?
#register.simple_tag
def get_aux_info(master_document, aux_type):
md = MasterDocument.objects.get(pk=master_document)
template = get_template("general/md_tags.html")
#objects = []
code = "objects = md." + aux_type +"s.all()"
exec(code)
context = Context({"objects": objects})
return template.render(context)
A much easier approach than building and executing the code as a string would be to access the attribute using the built-in getattr function. This makes it clearer what's going on and side-steps your current scope issues entirely:
objects = getattr(md, aux_type + 's').all()
Python has extensive support for this kind of introspection; using exec (and eval) is usually a warning that you're approaching something in the wrong way.
I want to make a single database object available across many python modules.
For a related example, I create globl.py:
DOCS_ROOT="c:\docs" ## as an example
SOLR_BASE="http://localhost:8636/solr/"
Any other module which needs it can do a
from globl import DOCS_ROOT
Now this example aside, I want to do the same thing with database connection objects, share them across many modules.
import MySQLdb
conn = MySQLdb.connect (host="localhost"...)
cursor = conn.cursor()
I tried this on the interpreter:
from globl import cursor
and it seems to work. But I suspect that this will cause the same module to be executed each time one imports from it. So is this the proper way?
Even if the import doesn't run the code multiple times, this is definitely not the correct way.
You should instead hide the process of obtaining a connection or cursor behind a function. You can then implement this function using either a Singleton or Object Pool design pattern.
So it would be something like this:
db.py:
_connection = None
def get_connection():
global _connection
if not _connection:
_connection = MySQLdb.connect(host="localhost"...)
return _connection
# List of stuff accessible to importers of this module. Just in case
__all__ = [ 'getConnection' ]
## Edit: actually you can still refer to db._connection
## if you know that's the name of the variable.
## It's just left out from enumeration if you inspect the module
someothermodule.py:
import db
conn = db.get_connection() # This will always return the same object
By the way, depending on what you are doing, it may not be so much of a good idea to share
your connection object rather than create a new one every time you need one.
But, that's why you'd want to write a get_connection() method, to abstract from these issues in the rest of your code.
You suspect wrongly. The code will only be executed once - subsequent imports just refer to the module via sys.modules, and don't re-run it.
(Note that this is the case as long as you always use the same path to import the module - if you do from globl import cursor in one place, and from my.fullyqualified.project.global import cursor in another, you probably will find the code is re-executed.)
Edit to add as S.Lott says in the comment, this is a perfectly good way to handle a global object.
I think Daniel already answered the question, while I'd like to add few comments about the cursor object you want to share.
It is generally not a good idea to share the cursor object that way. Certainly it depends on what your program is, but as a general solution I'd recommend you to hide this cursor object behind a "factory" producing cursors. Basically you can create a method cursor() or get_cursor() instead of making the cursor a global variable. The major benefit (but not the only one) - you can hide a more complex logic behind this "factory" - pooling, automatic re-connection in case the connection is dropped, etc. Even if you don't need it right away - it will be very easy to add it later if you start using this approach now, and while for now you can keep this function implementation as simple as return _cursor.
And yes, still, the module itself will be imported once only.