Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Pythonista 1.6 Beta
-
I assume the appex module you teased on Twitter is not integrated/activated in this Beta? Anyway, it's pretty cool you're doing this and I am happy to test the Twitter integration :)
-
Feedback on the in-app "What's new in Pythonista?" docs... Change
dialgos
todialogs
and activate the hyperlink. -
@ccc, I believe omz uses the same doc generator that is used for the standard library, in which case it will automatically link once the module name is recognized.
-
@omz searching in the docs is very wonky. sometimes it works and sometimes it doesn't - just says "Searching......". (using an iPhone 5)
-
Just looking at the docs has me wowed! One tip would be to include an example script for BLE, as the protocol my be a little foreign to some.
-
A few things I've noticed so far:
- The Pythonista.app bundle is now fully moved out of the "Data" folder and no longer easily accessible (sad face)
- The Trash is invisible when empty (not really a bug, but somewhat counter-intuitive)
- The Trash didn't appear for me the first time I deleted a file until I opened the settings (thus reloading the file list I suppose)
- No way to selectively delete files from the Trash or restore multiple files at once
- The Move menu still takes ages to open
- Not specifically a beta bug, but in thumbnail view the default syntax highlight style is always used, no matter which one is selected in the settings
-
@omz for
reminders.get_reminders(completed=TRUE)
is there currently, or could there be in a future version, a way to filter completed reminders with completion date. Perhaps something like reminders completed today, or the past week, or since a given date? That could be nice for keeping track of certain projects or self-quantification, et al. Also would like to see this module in Editorial eventually. Better than using url schemes in all these reminder workflows. -
I was able to use the Bluetooth LE module to talk to a LightBlue Bean and enumerate all of its services and characteristics.
I also tried reading all the values for each characteristic and ran into one problem. The values returned may or may not be text strings and if you simply assume they are and print them to the console you can get the module to throw an exception
TypeError: must be string without null bytes, not str
Trace back says it happened at line 73 in cb.py
After that you can recover but you can also crash completely or leave the module in a bad state and unable to talk to the peripheral.
Here is my code:
import cb import sound import time import struct class LightBlueBean (object): def __init__(self): self.peripheral = None def did_discover_peripheral(self, p): print 'Discovered:', p.name if p.name and 'Bean' in p.name and not self.peripheral: self.peripheral = p print 'Connecting to Bean...' cb.connect_peripheral(p) def did_connect_peripheral(self, p): print 'Connected:', p.name print 'Discovering services...' p.discover_services() def did_fail_to_connect_peripheral(self, p, error): print 'Failed to connect: %s' % (error,) def did_disconnect_peripheral(self, p, error): print 'Disconnected, error: %s' % (error,) self.peripheral = None def did_discover_services(self, p, error): print 'Did discover services...' for s in p.services: print 'Service:', s.uuid if True: # s.uuid == '180D' print 'Discovering characteristics...' p.discover_characteristics(s) def did_discover_characteristics(self, s, error): print 'Did discover characteristics...' for c in s.characteristics: print 'Characteristic:', c.uuid, ' Value:', c.value #if c.uuid == '2A37': # self.peripheral.set_notify_value(c, True) self.peripheral.read_characteristic_value(c) def did_update_value(self, c, error): #somevalue = struct.unpack('<B', c.value[1])[0] #self.values.append(somevalue) #print 'Value: %i' % somevalue print 'Update to a value...' print 'Characteristic:', c.uuid, ' Value:', c.value mngr = LightBlueBean() cb.set_central_delegate(mngr) print 'Scanning for peripherals...' cb.scan_for_peripherals() try: while True: pass except KeyboardInterrupt: print 'keyboard interrupt - resetting' cb.reset()
Here is the console output:
Scanning for peripherals... Discovered: Bean Connecting to Bean... Connected: Bean Discovering services... Disconnected, error: (10, u'The connection has failed unexpectedly.') keyboard interrupt - resetting Scanning for peripherals... Discovered: Bean Connecting to Bean... Connected: Bean Discovering services... Did discover services... Service: F000FFC0-0451-4000-B000-000000000000 Discovering characteristics... Service: 180A Discovering characteristics... Service: A495FF10-C5B1-4B44-B512-1370F02D74DE Discovering characteristics... Service: A495FF20-C5B1-4B44-B512-1370F02D74DE Discovering characteristics... Service: 180F Discovering characteristics... Did discover characteristics... Characteristic: F000FFC1-0451-4000-B000-000000000000 Value: None Characteristic: F000FFC2-0451-4000-B000-000000000000 Value: None Did discover characteristics... Characteristic: 2A23 Value: None Characteristic: 2A24 Value: None Characteristic: 2A25 Value: None Characteristic: 2A26 Value: None Characteristic: 2A27 Value: None Characteristic: 2A28 Value: None Characteristic: 2A29 Value: None Characteristic: 2A2A Value: None Characteristic: 2A50 Value: None Did discover characteristics... Characteristic: A495FF11-C5B1-4B44-B512-1370F02D74DE Value: None Did discover characteristics... Characteristic: A495FF21-C5B1-4B44-B512-1370F02D74DE Value: None Characteristic: A495FF22-C5B1-4B44-B512-1370F02D74DE Value: None Characteristic: A495FF23-C5B1-4B44-B512-1370F02D74DE Value: None Characteristic: A495FF24-C5B1-4B44-B512-1370F02D74DE Value: None Characteristic: A495FF25-C5B1-4B44-B512-1370F02D74DE Value: None Did discover characteristics... Characteristic: 2A19 Value: None Update to a value... Characteristic: F000FFC1-0451-4000-B000-000000000000 Value: None Update to a value... Characteristic: F000FFC2-0451-4000-B000-000000000000 Value: None Update to a value... Characteristic: 2A23 Value: Update to a value... Characteristic: 2A24 Value: Bean Update to a value... Characteristic: 2A25 Value: Serial Number Update to a value... Characteristic: 2A26 Value: 201409080001 Img-B Update to a value... Characteristic: 2A27 Value: E Update to a value... Characteristic: 2A28 Value: Software Revision Update to a value... Characteristic: 2A29 Value: Punch Through Design Update to a value... Characteristic: 2A2A Value: Update to a value... Characteristic: 2A50 Value: Update to a value... Characteristic: A495FF11-C5B1-4B44-B512-1370F02D74DE Value: Update to a value... Characteristic: A495FF21-C5B1-4B44-B512-1370F02D74DE Value: Update to a value... Characteristic: A495FF22-C5B1-4B44-B512-1370F02D74DE Value: Update to a value... Characteristic: A495FF23-C5B1-4B44-B512-1370F02D74DE Value: Update to a value... Characteristic: A495FF24-C5B1-4B44-B512-1370F02D74DE Value: Update to a value... Characteristic: A495FF25-C5B1-4B44-B512-1370F02D74DE Value: Update to a value... Characteristic: 2A19 Value: 1 keyboard interrupt - resetting
-
Instead of a plain
print(data)
, try usingprint(data.replace("\x00", ""))
, withdata
being the value received from the peripheral. This simply removes any null bytes from the string to stop print from complaining. For debugging purposes you might want to replace null bytes with something like"NULL"
so you can find them in the printed text. -
Is it new in this version that the various
console.alert
"types" now return the button number (as an int)? It broke a couple of my scipts... -
Most strings you're dealing with will probably be binary data, so I'd recommend encoding them as hex before printing (
print c.value.encode('hex')
). Nevertheless, there are definitely some stability issues when you encounter exceptions in any of the callbacks. I might change this to disconnect when an exception is thrown in a callback, which might make it more likely to recover successfully.@hyshai
Is it new in this version that the various console.alert "types" now return the button number (as an int)? It broke a couple of my scipts...
The standard
alert()
function always did this, but I assume you're referring to other alert types? There are definitely some bugs with those right now, looking into it.for reminders.get_reminders(completed=TRUE) is there currently, or could there be in a future version, a way to filter completed reminders with completion date.
Right now, it's not possible, but I will at the very least add a
completion_date
attribute to theReminder
class, so you could filter them manually.I assume the appex module you teased on Twitter is not integrated/activated in this Beta?
No, this won't be in 1.6.
The Pythonista.app bundle is now fully moved out of the "Data" folder and no longer easily accessible (sad face)
That's an iOS 8 thing, nothing I can do about it, though it is still accessible if you have the correct path. Right now, you could do this with
scene.get_image_path
(which will return a path that is within the app bundle, you'd have to walk up the hierarchy a bit to get the root directory of the app). -
Also would like to see this module in Editorial eventually. Better than using url schemes in all these reminder workflows.
Yes, the
reminders
module will definitely be in the next update of Editorial as well, same goes fortwitter
and probablydialogs
. I don't plan to integratecb
in Editorial though. -
I have been working with the dialogs form_dialog and this test code:
import dialogs import datetime dt = datetime.datetime.now() fields = [ {'key' : 'the_key0', 'type' : 'switch', 'value' : 'the_value'}, {'key' : 'the_key1', 'type' : 'text', 'value' : 'the_value'}, {'key' : 'the_key2', 'type' : 'url', 'value' : 'the_value'}, {'key' : 'the_key3', 'type' : 'email', 'value' : 'the_value'}, {'key' : 'the_key4', 'type' : 'password', 'value' : 'the_value'}, {'key' : 'the_key5', 'type' : 'number', 'value' : '100' }, {'key' : 'the_key6', 'type' : 'check', 'value' : 'the_value'}, {'key' : 'the_key7', 'type' : 'datetime', 'value' : dt}, {'key' : 'the_key8', 'type' : 'date', 'value' : dt}, {'key' : 'the_key9', 'type' : 'time', 'value' : dt} ] result=dialogs.form_dialog(title='look at all this stuff', fields=fields) print 'text:', result
When I look at this, I can't help thinking that all the field data should be aligned right and that there should be labels on each one. Should there be a 'label' key added? How is the user suppose to know what each field represents?
I suppose you could use sections to implement labels, but that seems wrong. Section as a way of breaking up and labeling combinations of like fields is good.
sections = [ ('switch section', [{'key' : 'the_key0', 'type' : 'switch', 'value' : 'the_value'}]), ('text section', [{'key' : 'the_key1', 'type' : 'text', 'value' : 'the_value'}]) ] result=dialogs.form_dialog(title='look at all this stuff', sections=sections) print 'text:', result
Also - datetime requires/returns a datetime and date and time do as well. Should date and time require and return date and time objects?
Also, Also - email, url, number don't seem to do anything different then text. Shouldn't they be enforcing formatting or something?
-
How is the user suppose to know what each field represents?
There's a
'title'
key you can use, the documentation is a little incomplete right now with regards to the supported keys.Also - datetime requires/returns a datetime and date and time do as well. Should date and time require and return date and time objects?
Maybe, it was a bit easier to implement this way, and you can easily convert it to a
date
ortime
object by callingdatetime.date()
ordatetime.time()
.Also, Also - email, url, number don't seem to do anything different then text. Shouldn't they be enforcing formatting or something?
The keyboard for URL and email fields is different (e.g. the email keyboard has an additional '@' key), and they have autocorrection disabled by default.
-
text = dialogs.text_dialog(title='Name Your Reminder', autocapitalization=ui.AUTOCAPITALIZE_SENTENCES, spellchecking=None)
r = reminders.Reminder()
r.title = text
r.save()Gives me a excepted string error.
-
@techteej Did you use the Done button in the text dialog? If you cancel the dialog (via 'x'), it'll return
None
. -
It shows up while the dialog is up
-
@techteej Is that really your entire code?
-
There's a 'title' key you can use ...
The title key works perfectly. I noticed that the text color defaults to black except for the checkbox case where it is blue (or same as check color).
Looking forward to more keys assuming now that you are going to have color, font, etc. to really allow full control.
What about field validation? Popping up a special keyboard is nice, but a delegate function called on each keystroke would nail it. I used to work on named entity extraction in text and you can do a lot with simple regex matching, but you need to run code to do credit card numbers (for the checksum). I think mapping field types to entities would be super cool.
-
@omz Here is my entire code.
# coding: utf-8 import dialogs import reminders import ui class Data (ui.ListDataSource): def __init__(self, items=None): ui.ListDataSource.__init__(self, items) def tableview_cell_for_row(self, tableview, section, row): cell = ui.TableViewCell() cell.text_label.text = str(self.items[row]) return cell v = ui.load_view('reminders') def button_action(sender): if segment.selected_index == 0: todo = reminders.get_reminders(completed=False) for r in todo: full = r.title reminders_table.data_source = Data(items=[full]) reminders_table.reload() elif segment.selected_index == 1: done = reminders.get_reminders(completed=True) for r in done: full = r.title reminders_table.data_source = Data(items=[full]) reminders_table.reload() def but_action(sender): text = dialogs.text_dialog(title='Name Your Reminder', autocapitalization=ui.AUTOCAPITALIZE_SENTENCES, spellchecking=None) r = reminders.Reminder() r.title = text r.save() segment = v['segmentedcontrol1'] segment.action = button_action reminders_table = v['reminders'] create_button = ui.ButtonItem() create_button.image = ui.Image.named('ionicons-ios7-plus-empty-32') create_button.action = but_action v.right_button_items = [create_button] v.present('sheet')