QClipboard works funny under GNU/Linux - linux

#!/usr/bin/python
from PyQt4.QtGui import QApplication, QClipboard
import sys
app = QApplication(sys.argv)
QApplication.clipboard().setText('yo', mode=QClipboard.Clipboard)
input() #wait for input
When I set mode=QClipboard.Clipboard (the default one), it doesn't work. It leaves old data in the clipboard and in the selection clipboard.
When I change it to mode=QClipboard.Selection (the one specific to X), it replaces both selection and primary clipboard with yo.
Question: why the "main thing" (mode defaults to QClipboard.Clipboard after all) doesn't work, while something that should work only conditionally (QClipboard.supportsSelection()) does the job? How can I make this work properly?

I can't actually reproduce the problem on my Linux system: it all works fine for me.
However, the docs say that the clipboard needs an event-loop on X11:
the X11 clipboard is event driven, i.e. the clipboard will not
function properly if the event loop is not running. Similarly, it is
recommended that the contents of the clipboard are stored or retrieved
in direct response to user-input events, e.g. mouse button or key
presses and releases. You should not store or retrieve the clipboard
contents in response to timer or non-user-input events.
So you might be able get your example working on your system by forcing the processing of queued events like this:
app.clipboard().setText('yo')
app.processEvents()
input()
Obviously that is a contrived "solution", though, and the correct way to do things is to start the event-loop and follow the advice in the docs.

Related

How do I avoid losing program focus after subprocess.call?

I am trying to extract data from a program; its raw data files are encrypted XMLs so my plan is to start the program, then use mouse control commands (e.g. pyautogui) to copy / paste the data.
So far I'm falling at the first hurdle; when I run subprocess.call to start the program, the program gets window focus and my subsequent code doesn't execute until I manually close the program.
workingFolder = self.get_working_folder() # get path where raw data is
subprocess.call('Path\Program.exe') # works, Program.exe starts
print(workingFolder) # this doesn't execute until I close the Program window
EDIT: After further testing I have answered my own question - subprocess.Popen was in fact what I needed, despite my initial doubts about it! Thanks to anyone who looked at my question :).
workingFolder = self.get_working_folder()
subprocess.Popen('Path\Program.exe')
print('This works')

Press enter stops computing python

I'm doing some engineering analysis with the help of a FEA program and Python. When the analysis ends I need to press a key to continue. But this is not a normal press any key to continue. Every code executed with the scripts stops. Like a handput debug break. Nothing runs until I press something or switch windows.
I cant use send keys and subprocesses because running code completely stops. Only solution I could come up with is to use another script in another command window with simple send keys command. This extra script is useless if computer is used or another window is active.
I'm a beginner level programmer and maybe I'm missing something simple. I guess the problem is caused by the FEA programs code but I'm not sure. So is there any way to prevent my code from stopping? Thank you for your time.
It seems that the FEA program does the windowing and you cannot do much about it. I actually automate scripting in DIANA FEA. For this program I would try something like pywinauto.
https://github.com/pywinauto/pywinauto
And call your python script from another python script.
from pywinauto import Desktop, Application
import time
app = Application().start("FEA_program.exe my_python_script.py")
while True:
time.sleep(5)
# send key presses to the app every arbitrary seconds

How to change the Sublime Text 3 StatusBar message in a command or macro (no plugin)?

addressing Sublime Text 3 users here.
I wrote a couple of macros to enable spell-check and load a specific dictionary, as I constantly swap between French and English and I wanted a simple shortcut for this (instead of browsing the menu or two successive commands in the command pallet).
My macros work as expected (french-spellcheck.sublime-macro, english-spellcheck.sublime-macro).
But I would like to display a message in the Status Bar, for instance "Switched to French" or "Switched to English" (for some time, let say 5 sec).
I looked everywhere I know and I tried for some time, but apparently there is no way to do this in a command (that could be added at the end of the macro), as the set_status internal ST3's Python API command (from Window package) is only available for plugins...
Does any one has an idea of how to display a message to the SublimeText3 StatusBar in a command/macro and not with a plugin? Thanks!
There is no built in command that invokes the API methods for doing this (at least not a documented one), so there's no way to go about this without a plugin of some sort.
That said, in order to do what you want, the following is all you would need to save into a file named e.g. set_status.py in your Packages/User folder (alongside your macros). This provides a set_status command that takes a value named value for the text to display, as mentioned in the commented out portion of your macro file.
import sublime, sublime_plugin
class SetStatusCommand(sublime_plugin.TextCommand):
def run(self, edit, value="set_status: use arg 'value' to set text"):
self.view.window ().status_message (value)
This uses a different API than the one you mention in your macro file comments; status_message does the work of displaying a message in the status bar, waiting a few seconds, and then removing it, which makes the command simple to implement.
If you wanted more control (i.e. to change the duration) you would need to modify this to invoke the API commands your macro files already mention: view.set_status() and sublime.set_timeout().

Control - Z In Python Code

In IDLE, there's no clear screen, and after reading the forums the best method is plainly to print a ton of "\n"s. However, after playing with IDLE, I made a discovery. When my game was waiting for an input after printing out instructions using print statements, instead of inputting any useful character, I entered 'control-z,' and IDLE began to remove the text that was display by the print statements, one by one.
My main question is, how do I manually in the code itself enter 'control-z', so I can utilize this functionality?
If you're confused by my story, here's some example code and try it yourself by hitting control-z.
print("Some Text")
print("More Text")
input("The Input (Hit Control - Z Here):")
^Z is a bit of a mess. The ascii control char ^D is usually interpreted as EOT, end of transmission, which on Unix and many other systems means end of file, close the application. Ascii ^Z is meant to be interpreted as SUB, substitute, whatever that means. Editors ofter use it as UNDO (meaning undo a ^X cut). Microsoft (and a few other old systems) at least sometimes interprets ^Z as end of file, with the same effect as ^D on *nix.
The Windows console closes a text app after ^Z . ^D is passes on to the app. IDLE, as a cross-platform app, closes on ^D. IDLE used to close on ^Z on Windows, but now, for me, it only erases the prompt. (I don't know if this alternative is intended.) I do not see the progressive deletion you report. What OS and what Python version are you running?
To answer your main question: you can't. input is usually used in assignment statements: string = input('prompt'). The way to imitate input statements is to directly assign 'user input': s = 'simulated user input'. However, this does not work for characters that get intercepted by the programs managing the input window and never sent to the python program.
IDLE's Shell generally imitates Python's interactive console. The latter (at least on Windows) makes everything, except the current input, read-only. Shell follows suite. Imitation is especially strict as regards executing user code. It is intended that user code tested in IDLE should run in Python without IDLE. It would be wrong for IDLE to clear the interactive shell in response to user code when Python cannot.
For editor and output windows, ^A (select all) followed by Backspace (delete), Delete, or ^X (cut) do clear the window.
Shell does, however, has more editing commands than many (most? all?) consoles and a menu system. These additions are allowed since they are interactive only and not accessible from user code. There have been various proposals and patches to enable clearing part or all of the shell window. https://bugs.python.org/issue6143 has some of the discussions and proposals.

Copy-Paste In Python

I am new to python. So I wanted to improve my skills. Before posting this question I tried to find some code or an idea that would guide me with what I intend to do. I did see some examples and posts on SO and other sites. But they all(the ones I came across) showed how to do it for single object. Below is what I want to do.
I want to write a utility in python that would allow me to choose from content I want to paste based on what my last 10,say, copy commands were for.
suppose I clicked copy when selecting a folder and then later I selected some text and pressed ctrl+c. Now I want to get option that would let me paste both the folder as well as the text.
Is that possible?
Thanks.
You could save the last 10 text items from a clipboard using tkinter:
#!/usr/bin/env python3
from tkinter import Tk
from collections import deque
def call_repeatedly(root, delay, func, *args):
func(*args)
root.after(delay, call_repeatedly, root, delay, func, *args)
def poll_clipboard(root, items):
text = root.clipboard_get()
if not items or items[-1] != text:
items.append(text)
def main():
root = Tk()
root.withdraw() # hide GUI
clipboard_items = deque(maxlen=10) # save last 10 clipboard items
call_repeatedly(root, 50, poll_clipboard, root, clipboard_items) # ms
call_repeatedly(root, 1000, print, clipboard_items) # print every second
root.after(10000, root.destroy) # exit in 10 seconds
root.mainloop()
main()
It polls clipboard every 50 ms. Polling is bad in general if there is an alternative interface that could allow you to subscribe to the clipboard events to be notified when new item is copied into the clipboard.
will it work for any kind of content, text, images etc. ?
This code works with text only. In general, you could get/set other types e.g., images (gtk, qt might provide a cross-platform way to do it).
Will it allow me to copy-paste text across all the applications ?
You are working with a clipboard so yes, it should work across all applications that can
work with a clipboard.
Can we make it work as normal ctrl+c (copy command)
Copy command can be implemented using a set command e.g., from pyperclip.py:
def gtkSetClipboard(text):
cb = gtk.Clipboard()
cb.set_text(text)
cb.store()
gtkSetClipboard(text) copies text to the clipboard.

Resources