Sublime Text accessing view file name error - python

I am new to Python, and Sublime Text plugin development, and I don't know what I'm doing wrong here. I am using Sublime Text 3. I'm trying to create a plugin that will copy the file name to the clipboard. Can anyone help me understand this python error and/or offer a solution?
import sublime, sublime_plugin
class Filename_to_clipboardCommand(sublime_plugin.TextCommand):
def run(self, edit):
sublime.set_clipboard(sublime.View.file_name())
sublime.message_dialog("The full file path was copied to the clipboard")
and the error, when I call the plugin from the console, is:
>>> view.run_command('filename_to_clipboard')
Traceback (most recent call last):
File "/Applications/Sublime Text.app/Contents/MacOS/sublime_plugin.py", line 549, in run_
return self.run(edit)
File "/Users/ivan/Library/Application Support/Sublime Text 3/Packages/Filename_to_clipboard/filename_to_clipboard.py", line 5, in run
sublime.set_clipboard(sublime.View.file_name())
TypeError: file_name() missing 1 required positional argument: 'self'
When I do:
sublime.set_clipboard(view.file_name())
from the conosole, it works! Why?

Try self.view.file_name() rather than sublime.View.file_name(). You have a reference to an instance of the view for your TextCommand. It was written for ST2, but you may want to take a look at this tutorial
http://net.tutsplus.com/tutorials/python-tutorials/how-to-create-a-sublime-text-2-plugin/

I don't know anything about the Sublime Text API, but it looks like your problem here is that file_name() is an instance method, and sublime.View is a class so sublime.View.file_name() fails.
In Python, when you call an instance method you are implicitly passing the instance as the first argument, which is why it says you are missing the argument self. You could even write the call explicitly. For example, view.file_name() could also be written sublime.View.file_name(view), but that's kind of silly.
Good luck with your plugin :)

I hate to see all your effort wasted, but this functionality already exists in ST3. If you right-click in the edit area, Copy File Path is one of the options on the context menu. To create a keyboard shortcut, open Preferences -> Key Bindings - User and add the following item:
{ "keys": ["super+i"], "command": "copy_path" }
You can of course change the key binding to whatever you want. If the key bindings file is empty when you open it, just add opening and closing square brackets:
[
{ "keys": ["super+i"], "command": "copy_path" }
]
However, I still encourage you to learn Python and plugin programming, they're both quite rewarding and great fun! Good luck!
EDIT
Based on a comment by #skuroda, here's how I discovered the command to use:
I already knew there was a Copy File Path option in the context menu, but looking through Preferences -> Key Bindings - Default I couldn't find any shortcuts or macros already assigned to that action, and I didn't know exactly what the command's name was. So, I hit Ctrl` to open the console, then ran
sublime.log_commands(True)
to have all actions logged to the console. I then right-clicked and selected Copy File Path, and
command: copy_path
showed up, along with a message regarding the mouse's location when the context menu event occurred. I assigned the key combination, ran it, and it worked. To finish up, I run
sublime.log_commands(False)
so the console doesn't get clogged with unnecessary info, then hit Ctrl` again to close the console.

Related

How can you open a saved .py file in idle3 without it defaulting to normal text?

I recently started using idle3 to follow along with some course material as recommended by the instructor. Opening a new shell and running python code works just fine, the problem is when i save the file and later try to reopen it to continue on with the course work.
When ever i open the designated .py file, it only loads up in regular text, i can no longer execute new code, the line break doesn't have the ">>>" before each line, it won't even give any output
How can i open a saved file and continue on implementing code?
The basic use of the IDLE is for 2 thing, text editor and interactive console.
The interactive console allow you to write any python code and see it running immediately, great quick calculation and/or testing code until you get the desired result.
The save option (File -> Save) is deceptive however, because it save everything as you see including the >>> so saving as .py just doesn't work, or not without some extra work, namely removing all the >>> and all other undesired stuff, so is more like screenshot of sort.
The text editor mode is, well, just that but specialized for python with its syntax highlight and whatnot, use it to write your modules or whatever else, save it as .py and run the code by pressing F5 in order to test it, which will open a new interactive console with all that code loaded into it or would load it into a previously open one in which case it will reset it first, and that means that anything not in the file will be discarded (but you can scroll up can copy-pasted again if needed)
So for example, in a file you have
def greetings(name):
print("hello",name)
and you open it with the text editor mode of IDLE, simply run (F5) and you now have access to that function in the interactive console
>>> greetings("bob")
hello bob
>>> a=23
>>>
and lets make a new variable with some value
Now lets said we go back to the file and add some more stuff and now it looks like
def greetings(name):
print("hello",name)
def add(a,b):
return a+b
b=42
and run it again, this reset the console, which is indicated a msj like this containing the path of the loaded file
====== RESTART: C:\Users\Copperfield\Documents\StackOverflow\example.py =====
>>>
now we have the greetings and add function but the variable a from before is now loss
>>> a
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
a
NameError: name 'a' is not defined
>>>
but you have b
>>> b
42
>>>
So, use the text editor mode to write all the stuff you want to keep and in the interactive console play with it to test that is indeed the thing you want, and if not just go and edit it some more...

IDLE autocomplete in a new file do not work

If I testing my codes on IDLE the autocomplete its works but if I open a new file don't.
See there pictures below:
I just press CTRL + SPACE.
So.. don't work in this case:
I'll think there are some configuration for solve this, any one knows?
Python idle doesn't work that way. You get autocomplete in idle shell because values are deduced in every run. When you use files your program is not evaluated until you run. Because you can assign any type to a variable at run time, there is no way for idle to confirm the type of variable.
Understand with an example
>> a = dict()
>> a = set()
>> a. # <-- autocomplete knows type of a is set
but the same code in a file
a = dict()
a = set()
a. # <-- How does idle come to know what this variable is without running
but when you run this file once your global variables will show autocomplete feature, but not the local scope variables.
Have you tried saving the script as a *.py file before trying to use IDLE's autocomplete?
More than that, have you considered using a text editor with Python plugins, like Sublime Text and Atom? Or even a python-compatible IDE, like PyCharm, Spyder or even JupyterNotebook.

pywinauto find_elements() returns ElementNotFoundError

I'm trying to automate a simple app using pywinauto & Python 3.6. The app has a Windows "Open" dialog like this and I want to click on the "Cancel" button:
I used SWAPY to get the class_name and control_id attributes for the button.
Now the problem is that when I call the find_element() method with these parameters it raises an ElementNotFoundError. Here's my code:
cancel_button = pywinauto.findwindows.find_element(class_name="button", control_id=2)
I've tried (class_name="button", control_id="2"), (class_name="Button", control_id=2) but they all give the same error. The same problem occurs for any other element I try to find on this dialog.
So how do I use the attributes read from SWAPY? I didn't find the official pywinauto documentation to be very useful. It doesn't explain a lot of things clearly.
EDIT: I decided not to use the find_elements method and instead used find_windows() to get a handle to the Open dialog.
w_open_handle = pywinauto.findwindows.find_windows(title=u'Open', class_name='#32770')[0]
I then get a WindowSpecification object using this handle:
w_open = app.window_(handle=w_open_handle)
I then call:
w_open['Cancel'].click()
and this works. Now I want to enter a file name in the "File name:" edit box and click on Open button to open that file. So I do this:
w_open['File name:'].type_keys("abc.txt")
This works. I printed out the control identifiers using print_control_identifiers() and got the name for Open button. So using draw_outline() I draw a boundary outside it and it shows the correct button.
w_open['SplitButton6'].draw_outline()
But calling .click() method on 'SplitButton6' throws a WindowSpecification class has no 'click' method error. Any idea what's causing this? The error seems to be misleading since WindowSpec class does have a .click method.
Correct answer is that you missed top_level_only=False (it's True by default because higher level API calls it at least twice). Then you may have 2 controls matching this criterion (maybe from different applications). find_element is a low level function. I wouldn't recommend its direct usage (the code is too long, there are many pitfalls that were taken into account on a higher level API).
>>> pywinauto.findwindows.find_element(class_name="Button", control_id=2, top_level_only=False)
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "...\pywinauto\findwindows.py", line 98, in find_element
raise exception
ElementAmbiguousError: There are 2 elements that match the criteria {'class_name': 'Button', 'control_id': 2, 'top_level_only': False}
>>> pywinauto.findwindows.find_element(class_name="Button", title='Cancel', top_level_only=False)
<win32_element_info.HwndElementInfo - 'Cancel', Button, 395554>
Using higher level API (Application object and WindowSpecifications described in the Guide) you shouldn't care about passing process id, backend name and other things to find_element every time.
P.S. In my mind SWAPY could be significantly improved, but it's not maintained last year. I hope to re-write it in the future with smaller code base and MS UI Automation support. But currently fully automatic script generator is a higher priority.
EDIT:
This button w_open['SplitButton6'].draw_outline() could be detected as general HwndWrapper object instead of ButtonWrapper. You can check it using this:
w_open['SplitButton6'].wrapper_object()
And this is what exactly written in the Getting Started Guide (which you said you've read).
Fortunately you can use method .click_input() for any control:
w_open['SplitButton6'].click_input()
I can say more: WindowSpecification does NOT have click method. It's a method of ButtonWrapper which is instantiated dynamically. For example these statements work the same way (but Python can hide .wrapper_object() call):
w_open['SplitButton6'].wrapper_object().click_input()
w_open['SplitButton6'].click_input()
And again this is all described in the Getting Started Guide. Please read the whole guide. You will find many useful high level things. I can advise for some corner cases if something is still not clear.

Writing a plugin to open a new file

In Sublime Text 3 I have a few packages that open new files within the window. They have functions that look like:
class BufferCommand(sublime_plugin.WindowCommand):
def run(self):
view = self.window.new_file()
...
I grabbed this for something I am working on, and couldn't get a new file to generate, even though that works for the plugin I snagged it from, and is similar to how it is used in Packages/Default/new_templates.py. After some more searching, I found the following code, and it works as expected
class TestCommand(sublime_plugin.TextCommand):
def run(self,edit):
view = self.view.window().new_file()
Can somebody tell me why?
It might be the way you are running your command? If you are entering
view.run_command("buffer")
into the python console, then nothing will happen if BufferCommand is not a TextCommand.
Instead try this:
window.run_command("buffer")
This should fix your problem.

Show Python doc strings for the current function in Sublime Text 2?

I just found Sublime Text 2 and it's awesome. The only thing I really miss is the ability to view the doc string of the function I'm dealing with. Are there any plugins that can do this?
for example:
def f(x):
'''a doc string for f'''
print x
f # << at this point, either automatically or with a keystroke,
# I would like to be able to somehow view "a doc string for f"
Edit: I've already attempted to using SublimeCodeIntel and SublimeRope, neither have such support.
Edit2: It should also work for other modules in the open project.
Something like this will point to the correct place in the documentation, but if you really need documentation integrated into your environment, I would consider using an IDE. However, I too am a fan of Sublime and just pop open a browser when needed.
Install anaconda for sublime.
Then on Sublime3, navigate to Preferences > Package Settings > Anaconda > Settings-User and add the following lines to the text file just opened.
{
"anaconda_linting" : false,
"enable_signatures_tooltip" : true,
"merge_signatures_and_doc" : true,
"python_interpreter":"/home/miladiouss/anaconda3/bin/python"
}
Save, restart Sublime, and enjoy the best IDE for Python!
By tweaking SublimeCodeIntel, you can disable the "jump" to the file where the function is defined -- this will allow you to see the function definition in the status bar upon alt-clicking.
To do this, select Preferences > Browse Packages and then open SublimeCodeIntel/SublimeCodeIntel.py.
Go to class GotoPythonDefinition(sublime_plugin.TextCommand): and add a return at line 890 so that the first lines of _trigger read:
def _trigger(defns):
if defns is not None:
defn = defns[0]
if defn.name and defn.doc:
msg = "%s: %s" % (defn.name, defn.doc)
logger(view, 'info', msg, timeout=3000)
return
(you can also tweak the msg string formatting and remove the defn.name to save a bit of status bar space).
It's a bit disorienting to have to look down at the status bar to see the definition... also, the status bar won't be able to display long definitions. However, it's a start. Hopefully, tooltip/popup control will be made available through the API so that definitions can appear in the view next to alt-clicked functions.

Categories

Resources