How do I use text inputted into my kivy GUI as a string to use elsewhere? - python-3.x

I have created a very simple GUI in kivy and am trying to use it to send an e-mail to a specific user, how do I use the text inputted into the GUI as I am unfamiliar with GUI.
This is my code so far below:
import textwrap
import time
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
class Main(GridLayout):
def __init__(self,**kwargs):
super(Main, self).__init__(**kwargs)
self.cols = 2
self.add_widget(Label(text = "Who"))
self.Who = TextInput(multiline = True)
self.add_widget(self.Who)
self.add_widget(Label(text = "What"))
self.What = TextInput(multiline = True)
self.add_widget(self.What)
self.add_widget(Label(text = "Where"))
self.Where = TextInput(multiline = True)
self.add_widget(self.Where)
self.add_widget(Label(text = "When"))
self.When = TextInput(multiline = True)
self.add_widget(self.When)
self.add_widget(Label(text = "How"))
self.How = TextInput(multiline = True)
self.add_widget(self.How)
class AMAPP(App):
def build(self):
return Main()
def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
import smtplib
"""this is some test documentation in the function"""
message = textwrap.dedent("""\
From: %s
To: %s
Subject: %s
%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT))
# Send the mail
server = smtplib.SMTP(SERVER)
server.starttls()
server.login('E-mail', 'Password')
server.sendmail(FROM, TO, message)
server.quit()
FROM = 'me'
TO = 'you'
SUBJECT = 'test'
TEXT = (Who, What, Where, When, How)
SERVER = 'smtp.gmail.com'
sendMail(FROM,TO,SUBJECT,TEXT,SERVER)
if __name__ == "__main__":
AMAPP().run()
whenever I run this I get the same error:
line 66, in __init__
TEXT = (Who,What,Where,When,How)
NameError: name 'Who' is not defined

You have to give id to the Textinput widgets as you create them so that you can reference them to extract the text. Add a button so that you invoke the sendEmail method. Please refer to the example below for details.
Example
main.py
import textwrap
import time
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
FROM = 'me'
TO = 'you'
SUBJECT = 'test'
TEXT = ""
SERVER = 'smtp.gmail.com'
def sendMail(FROM, TO, SUBJECT, TEXT, SERVER):
import smtplib
"""this is some test documentation in the function"""
message = textwrap.dedent("""\
From: %s
To: %s
Subject: %s
%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT))
# Send the mail
server = smtplib.SMTP(SERVER, 587)
server.starttls()
server.login('E-mail', 'Password')
server.sendmail(FROM, TO, message)
server.quit()
class Main(BoxLayout):
def send_eMail(self):
global TEXT
print(self.ids.Who.text)
print(self.ids.What.text)
print(self.ids.Where.text)
print(self.ids.When.text)
print(self.ids.How.text)
TEXT = (self.ids.Who.text, self.ids.What.text,
self.ids.Where.text, self.ids.When.text, self.ids.How.text)
sendMail(FROM, TO, SUBJECT, TEXT, SERVER)
class AMAPP(App):
def build(self):
return Main()
if __name__ == "__main__":
AMAPP().run()
amapp.kv
#:kivy 1.10.0
<Main>:
orientation: "vertical"
GridLayout:
cols: 2
Label:
text: "Who"
TextInput:
id: Who
multiline: True
Label:
text: "What"
TextInput:
id: What
multiline: True
Label:
text: "Where"
TextInput:
id: Where
multiline: True
Label:
text: "When"
TextInput:
id: When
multiline: True
Label:
text: "How"
TextInput:
id: How
multiline: True
Button:
text: "Send Mail"
on_release: root.send_eMail()
Output

You were actually quite close with your code. Rather than doing a rewrite to kv code (which might be better practice), I simply added the button, fixed your dedent call, added the self.Field.text references, and it worked fine. Here's the edited code.
import textwrap
import time
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button # ADDED
EMAIL="<senders email address>" # ADDED
PASSWORD="<senders password>" # ADDED
class Main(GridLayout):
def __init__(self,**kwargs):
super(Main, self).__init__(**kwargs)
self.cols = 2
self.add_widget(Label(text = "Who"))
self.Who = TextInput(multiline = True)
self.add_widget(self.Who)
self.add_widget(Label(text = "What"))
self.What = TextInput(multiline = True)
self.add_widget(self.What)
self.add_widget(Label(text = "Where"))
self.Where = TextInput(multiline = True)
self.add_widget(self.Where)
self.add_widget(Label(text = "When"))
self.When = TextInput(multiline = True)
self.add_widget(self.When)
self.add_widget(Label(text = "How"))
self.How = TextInput(multiline = True)
self.add_widget(self.How)
self.add_widget(Button(text="Send",on_press=self.sendmail)) # ADDED
# ADDED function callable by the button press:
def sendmail(self,*args):
FROM = 'me'
TO = '<receivers email address>'
SUBJECT = 'test'
TEXT = '\n'.join([self.Who.text, self.What.text,
self.Where.text, self.When.text, self.How.text])
SERVER = 'smtp.gmail.com'
sendMail(FROM,[TO],SUBJECT,TEXT,SERVER) # watch out for the TO argument
class AMAPP(App):
def build(self):
return Main()
def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
import smtplib
"""this is some test documentation in the function"""
message = textwrap.dedent("""\
From: %s
To: %s
Subject: %s
%s
""") % (FROM, ", ".join(TO), SUBJECT, TEXT) # FIXED the dedent call
# Send the mail
server = smtplib.SMTP(SERVER)
server.starttls()
server.login(EMAIL,PASSWORD)
server.sendmail(FROM, TO, message)
server.quit()
if __name__ == "__main__":
AMAPP().run()
Warning, it is more involved if you want to send data TO the kivy GUI, because kivy has to know the data has changed. But that's beyond the scope of this question.

Related

GET request by QWebEngineHttpRequest (PyQt5)

I want to send a http GET request using QWebEngineHttpRequest.
I know it is possible, as I found this question with a POST request using it.
So, I've ended up with some code but it doesn't work. Let's say I want to make a get request to facebook webpage and print the answer, which should be the HTML content of the page.
import sys
from PyQt5 import *
def handle_response():
print(bytes(replyObject.readAll()).decode("utf-8"))
if __name__ == "__main__":
def app():
app = QApplication(sys.argv)
req = QtWebEngineCore.QWebEngineHttpRequest(QUrl("https://stackoverflow.com/questions/51686198/",
method=QWebEngineHttpRequest.Get)
req.setHeader(QByteArray(b'Content-Type'),QByteArray(b'application/json'))
web = QWebEngineView()
web.loadFinished.connect(on_load_finished) # will be error
sys.exit(app.exec_())
Ok, I found how to make this:
import sys
from PyQt5.QtCore import QByteArray, QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineCore import QWebEngineHttpRequest
from PyQt5.QtWebEngineWidgets import QWebEnginePage
class Render(QWebEnginePage):
def __init__(self, url):
app = QApplication(sys.argv)
QWebEnginePage.__init__(self)
self.loadFinished.connect(self._loadFinished)
self._html = ""
username = "username"
password = "password"
base64string = QByteArray(("%s:%s" % (username, password)).encode()).toBase64()
request = QWebEngineHttpRequest(QUrl.fromUserInput(url))
equest.setHeader(b"Authorization", b"Basic: %s" % (base64string,))
self.load(request)
app.exec_()
#property
def html(self):
return self._html
def _loadFinished(self):
self.toHtml(self.handle_to_html)
def handle_to_html(self, html):
self._html = html
QApplication.quit()
def main():
url = "http://www.google.com"
r = Render(url)
print(r.html)
if __name__ == "__main__":
main()
Thanks to link

How to call functions inside the kivy code

When i click on the Button: Profile, one error appears, i need the function to call the button to be pressed, the function checks if the variable is correct, and sends the person to another window
I've tried to put the function inside the kivy code but it doesn't recognize it, I don't know what else to do I just want to check the login and change the page, can someone help me?
Images:
Thats my code:
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
txtuser = 'Root'
def verified_Login():
if txtuser == 'Root':
root.manager.current = 'profile'
else:
print("oi")
screen_helper = """
ScreenManager:
LoginScreen:
ProfileScreen:
<LoginScreen>:
name: 'login'
MDRectangleFlatButton:
text: 'Profile'
pos_hint: {'center_x':0.5,'center_y':0.5}
on_press: verified_Login()
<ProfileScreen>:
name: 'profile'
MDLabel:
text: 'Test'
halign: 'center'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x':0.5,'center_y':0.2}
on_press: root.manager.current = 'login'
"""
class LoginScreen(Screen):
pass
class ProfileScreen(Screen):
pass
sm = ScreenManager()
sm.add_widget(LoginScreen(name='menu'))
sm.add_widget(ProfileScreen(name='profile'))
class DemoApp(MDApp):
def build(self):
screen = Builder.load_string(screen_helper)
return screen
DemoApp().run()
The Error when i click on the button:
line 57, in custom_callback
exec(__kvlang__.co_value, idmap)
File "<string>", line 12, in <module>
NameError: name 'verified_Login' is not defined
You need to import the verified_Login() method in your screen_helper. At the beginning of that string add:
#:import verified_Login file_name.verified_Login
where file_name is the name of the file containing your code (without the .py extension).
You also need to fix your verified_Login() method:
def verified_Login():
if txtuser == 'Root':
MDApp.get_running_app().root.current = 'profile'
else:
print("oi")
By the way, the following lines:
sm = ScreenManager()
sm.add_widget(LoginScreen(name='menu'))
sm.add_widget(ProfileScreen(name='profile'))
are building an unused instance of your App and can be removed. The actual App is built in the build() method by the line:
screen = Builder.load_string(screen_helper)

WTForms doesn't validate the input

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import InputRequired, Length, Email, EqualTo
class RegistrationForm(FlaskForm):
username = StringField("Username", validators=[InputRequired(), Length(min=2, max=10)])
email = StringField("Email", validators=[InputRequired(), Email()])
password = PasswordField("Password", validators=[InputRequired()])
confirm_password = PasswordField("Confirm Password", validators=[InputRequired(), EqualTo(password)])
remember = BooleanField("Remember Me")
submit = SubmitField("Sign Up")
#app.route("/register/", methods = ['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
flash('Account created for ' + form.username.data + '!', 'success')
return redirect(url_for('home'))
else:
print(form.errors)
print("not valid")
return render_template("register.html", title = "Register", form = form)
'''It produces following errors:
{'email': ['This field is required.'], 'confirm_password': ["Invalid field name ']})>'."]}'''
'''
I am new to Flask and python in general so, i apologize in advance if problem is obvious. Thanks for you time.'''
it appears you're following corey schafer's FLASK tutorial (it (and Corey Schafer) is a great resource).
In my code, instead of InputRequired() I use DataRequired(), and it works well. let me know if you are still working on this.

Python Telegram API ReplyKeyboardMarkup

I am new to python. I am trying to send a response showing a custom keyboard with two buttons to the user in Telegram app but it gives me an error about encode.
I would like to know where is my mistake.
import json
from urllib.request import urlopen
from urllib.parse import quote, unquote
import time
def Decode(telegram_response):
decoded=''
for line in telegram_response:
decoded=decoded+line.decode('utf-8')
return decoded
TOKEN = 'mytoken'
URL = 'https://api.telegram.org/bot{}/'.format(TOKEN)
cmd = 'getme'
telegram_response = urlopen(URL + cmd)
decoded = Decode(telegram_response)
gtm = json.loads(decoded)
status = True
while status:
cmd = 'getUpdates'
telegram_response = urlopen(URL + cmd)
decoded = Decode(telegram_response)
upds = json.loads(decoded)
new_message = len(upds['result'])
if new_message !=0:
msg = upds['result'][0]['message']
chat_id = str(msg['chat']['id'])
reply_markup = {'keyboard': [[{'text':'first button'}],[{'text':'second button'}]], 'resize_keyboard': True, 'one_time_keyboard': True}
reply_markup = json.dumps(reply_markup)
params = ({'chat_id': chat_id, 'reply_markup': reply_markup, 'disable_web_page_preview': 'true'})
myresponse =urlopen(URL + 'sendMessage' + quote((params).encode('utf-8')))
Easy way to build powerful bots is to use python-telegram-bot library.
I re-writed your code with few major fixes and features. Hope it help you to learn bots more deeper.
my version of bot:
###############################################################################
!#/usr/bin/python3
from sys import exc_info as error
from urllib.request import urlopen
from urllib.parse import urlencode
import json
TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX'
URL = 'https://api.telegram.org/bot{}'.format(TOKEN)
STATUS = True
OFFSET = 0
def call_api_method(method='getMe', data=None):
# Call API method with data.
data = urlencode(data).encode("utf-8") if data else data
response = urlopen('{}/{}'.format(URL, method), data)
return json.loads(response.read())
def get_me():
# Get bot info.
bot = call_api_method()
return type('Bot', (), dict(bot['result']))
def get_updates():
# Get new updates from Telegram.
data = {'offset': OFFSET, 'limit': 0, 'timeout': 0}
return type('Updates', (), call_api_method('getUpdates', data))
def handle(update):
# Make usefull objects.
message = type('Message', (object,), dict(update['message']))
user = type('User', (), dict(update['message']['from']))
chat = type('Chat', (), dict(update['message']['chat']))
return message, user, chat
def send_message(chat_id, message):
# Send message to specific chat.
data = {'text': message,
'chat_id': chat_id,
'parse_mode': 'Markdown',
'disable_web_page_preview': True}
call_api_method('sendMessage', data)
def send_keyboard(chat_id, message, keyboard):
# Send message and keyboard to specific chat.
data = {'text': message,
'chat_id': chat_id,
'parse_mode': 'Markdown',
'reply_markup': reply_markup(keyboard),
'disable_web_page_preview': 'true'}
call_api_method('sendMessage', data)
def reply_markup(keyboard):
# Serialize keyboard data to JSON.
return json.dumps({'keyboard': keyboard,
'resize_keyboard': True,
'one_time_keyboard': True,
'selective': True})
def main_keyboard():
# Main menu.
return [first_button(), second_button()]
def one_line_keyboard():
# Menu with buttons in one line.
return [two_buttons()]
def first_button():
# Single keyboard button.
return ['first button']
def second_button():
# Single keyboard button.
return ['second button']
def two_buttons():
# Two buttons on one line.
return ['left button', 'right button']
while STATUS:
# Get updates forever. Except if get Error.
try:
if not OFFSET:
OFFSET = 1
# Print bot info on the start.
bot = get_me()
print('Bot #{} is running...'.format(bot.username))
updates = get_updates()
for update in updates.result:
# Handle last update.
OFFSET = update['update_id'] + 1
message, user, chat = handle(update)
# Greeting user by full name.
greeting = 'Hello, {} {}!'.format(user.first_name, user.last_name)
#send_message(chat.id, greeting)
send_keyboard(chat.id, greeting, one_line_keyboard())
except:
STATUS = False
print('\nERROR:\t', error()[1])
###############################################################################
you can this code: I hope useful for you .
i change :
params = ({'chat_id': chat_id, 'reply_markup': reply_markup, 'disable_web_page_preview': 'true'})
myresponse =urlopen(URL + 'sendMessage' + quote((params).encode('utf-8')))
with:
params = ({'text': 'ss', 'chat_id': chat_id, 'reply_markup': reply_markup, 'disable_web_page_preview': 'true'})
data = urllib.parse.urlencode(params).encode("utf-8")
myresponse = urlopen(URL + 'sendMessage', data)
complate code :
import json
import urllib
from urllib.parse import quote
from urllib.request import urlopen
def Decode(telegram_response):
decoded = ''
for line in telegram_response:
decoded = decoded + line.decode('utf-8')
return decoded
TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX'
URL = 'https://api.telegram.org/bot{}/'.format(TOKEN)
cmd = 'getme'
telegram_response = urlopen(URL + cmd)
decoded = Decode(telegram_response)
gtm = json.loads(decoded)
status = True
while status:
cmd = 'getUpdates'
telegram_response = urlopen(URL + cmd)
decoded = Decode(telegram_response)
upds = json.loads(decoded)
new_message = len(upds['result'])
if new_message != 0:
msg = upds['result'][0]['message']
chat_id = str(msg['chat']['id'])
reply_markup = {'keyboard': [[{'text': 'first button'}], [{'text': 'second button'}]], 'resize_keyboard': True,
'one_time_keyboard': True}
reply_markup = json.dumps(reply_markup)
params = ({'text': 'ss', 'chat_id': chat_id, 'reply_markup': reply_markup, 'disable_web_page_preview': 'true'})
data = urllib.parse.urlencode(params).encode("utf-8")
myresponse = urlopen(URL + 'sendMessage', data)

How can I disable a section in Kivy settings?

I have a kivy app with settings and I wish to disable some settings (for example 'General') for certain users. I have tried to 'walk' through the children of settings (to use the disabled setting) but I cannot seem to do so.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen
from kivy.uix.settings import SettingsWithSidebar
import json
settings_general = json.dumps([
{'type': 'title',
'title': 'Set general preferences'},
{'type': 'bool',
'title': 'Use widgets',
'desc': 'Allow the use of widgets in the application',
'section': 'general',
'key': 'use widgets'},
{'type': 'bool',
'title': 'Print log',
'desc': 'Print log on closing application',
'section': 'general',
'key': 'print log'}
])
settings_appearance = json.dumps([
{'type': 'title',
'title': 'Appearance preferences'},
{'type': 'bool',
'title': 'Use colour',
'desc': 'Allow the use of colour in the application',
'section': 'appearance',
'key': 'use colour'}
])
class MainFrame(Screen):
def __init__(self, **kwargs):
super(MainFrame, self).__init__(**kwargs)
pass
def on_settings_button_click(self):
settings = self.app.settings_cls
print('type settings', type(settings))
print('is SettingsWithSidebar', isinstance(settings,
SettingsWithSidebar))
self.app.open_settings()
def on_quit_button_click(self):
quit()
class Settings(object):
def build_config(self, config):
config.setdefaults('general',
{
'use widgets': 0,
'print log': 0
})
config.setdefaults('appearance',
{
'use colour': 0
})
def build_settings(self, parent, settings):
settings.add_json_panel('General',
parent.config,
data=settings_general)
settings.add_json_panel('Appearance',
parent.config,
data=settings_appearance)
class BasicApp(App):
def build(self):
main_frame = MainFrame()
main_frame.app = self
self.settings_cls = SettingsWithSidebar
self.use_kivy_settings = False
return main_frame
def build_config(self, config):
self.settings = Settings()
self.settings.build_config(config)
def build_settings(self, settings):
self.settings.build_settings(self, settings)
if __name__ == '__main__':
BasicApp().run()
My kv file is:
<MainFrame>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Settings'
on_press: root.on_settings_button_click()
Button:
text: 'Click to close'
on_press: root.on_quit_button_click()
Can someone please suggest an approach that I can use?
[This section does not need to be read]
I have to enter more text before I am allowed to post this (ratio of code to text I think). It seems a shame because the question is so simple and I wanted to provide a basic working example of the application which is, of necessity, quite verbose.
[end of extra text]
You can disable the items in a panel with the disabled attribute.
settings_general = json.dumps([
{'type': 'title',
'title': 'Set general preferences'},
{'type': 'bool',
'disabled': True,
'title': 'Use widgets',
'desc': 'Allow the use of widgets in the application',
'section': 'general',
'key': 'use widgets'}])
The second item is disabled in this example.
However, I did not find an intuitive way to disable the whole Appearance section, for example.
So I went for a hackery method.
First was to walk the settings widget tree, to find that label.
tab = list(self.app.settings.walk(loopback=True))[5]
I found out that the label is the 6th element in this case.
But it was not enough to set disable attribute to True. It grays the label out, but it still works to click it, since they used the on_touch_down method.
So we can override the on_touch_down method.
I added a switch to the mainframe and a toggle method in the app class, to test this.
<MainFrame>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Settings'
on_press: root.on_settings_button_click()
Switch:
on_active: app.toggle_setting(self.active)
Button:
text: 'Click to close'
on_press: root.on_quit_button_click()
I found the original on_touch_down method here
def on_touch_down(touch, self):
# we need to write this method to override back to the original method
# the original method was found in kivy/uix/settings.py.
# look at the link above
if not self.collide_point(*touch.pos):
return
self.selected = True
self.menu.selected_uid = self.uid
class MainFrame(Screen):
def on_settings_button_click(self):
self.app.open_settings()
tab = list(self.app.settings.walk(loopback=True))[5]
if not self.app.toggle: # if switch is inactive
tab.disabled = True
tab.on_touch_down = lambda x: False
else:
tab.disabled = False
# we need partial from functools, so we can pass the tab as self
tab.on_touch_down = partial(on_touch_down,self=tab)
def on_quit_button_click(self):
quit()
The complete code:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen
from kivy.uix.settings import SettingsWithSidebar
from kivy.lang import Builder
import json
from functools import partial
settings_general = json.dumps([
{'type': 'title',
'title': 'Set general preferences'},
{'type': 'bool',
'disabled': True,
'title': 'Use widgets',
'section': 'general',
'key': 'use widgets'}
])
settings_appearance = json.dumps([
{'type': 'title',
'title': 'Appearance preferences'},
{'type': 'bool',
'title': 'Use colour',
'section': 'appearance',
'key': 'use colour'}
])
def on_touch_down(touch, self):
if not self.collide_point(*touch.pos):
return
self.selected = True
self.menu.selected_uid = self.uid
class MainFrame(Screen):
def on_settings_button_click(self):
self.app.open_settings()
tab = list(self.app.settings.walk(loopback=True))[5]
if not self.app.toggle:
tab.disabled = True
tab.on_touch_down = lambda x: False
else:
tab.disabled = False
tab.on_touch_down = partial(on_touch_down,self=tab)
def on_quit_button_click(self):
quit()
Builder.load_string("""
<MainFrame>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Settings'
on_press: root.on_settings_button_click()
Switch:
on_active: app.toggle_setting(self.active)
Button:
text: 'Click to close'
on_press: root.on_quit_button_click()
""")
class BasicApp(App):
toggle = False
def build(self):
self.main = MainFrame()
self.main.app = self
self.settings_cls = SettingsWithSidebar
self.use_kivy_settings = False
return self.main
def build_config(self, config):
self.config = config
self.config.setdefaults('general',{'use widgets': 0,'print log': 0})
self.config.setdefaults('appearance',{'use colour': 0})
def build_settings(self, settings):
self.settings = settings
self.settings.add_json_panel('General', self.config, data=settings_general)
self.settings.add_json_panel('Appearance', self.config, data = settings_appearance)
def toggle_setting(self, active):
self.toggle = active
BasicApp().run()

Resources