I made it with pythonista 3.
Using the template for Xcode (found on github)
deleted unnessary files, and finally updating objc_util.py in the template folder (look in site packages) with the copy from pythonista on phone.
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.
I made it with pythonista 3.
Using the template for Xcode (found on github)
deleted unnessary files, and finally updating objc_util.py in the template folder (look in site packages) with the copy from pythonista on phone.
So, I was thinking of a chemistry app.
With a similar interface as this:
https://phet.colorado.edu/en/simulation/balancing-chemical-equations
But, of course the student should be able to use his/her own chemistry equation to balance.
That could be an input text field, OR, take a picture of the equation, and then text
recognition.
Anyone with experience in this? :)
Hi!
I just wan't to tell, that my very first app was just accepted in iTunes store.
I could not have done it without you!
Thanks for getting help to access the printning utility.
Thanks for fixing the IPv6 issue ! That was a app killer. ;)
So now I have tried the whole path from idea to App release. Now it is time to get better ideas :)
Merry Christmas
I ended up with this, which functions as expected.
# Create a tableview, with data
self.tv = ui.TableView()
self.tv.row_height = 30
self.tv.data_source = MyTableViewDataSource(self.tv.row_height)
self.tv.delegate = MyTableViewDelegate()
# Update tableview data
self.tv.data_source.items = sorted(self.c.read_vouchers(), key=itemgetter(0), reverse=True)
# Do not allow selection on the TableView
#self.tv.allows_selection = False
self.tv.allows_selection = True
# Add the table
self.add_subview(self.tv)
# Define the class for the Table Data
class MyTableViewDataSource(object):
def __init__(self, row_height):
self.row_height = row_height
self.width = None
def tableview_number_of_rows(self, tableview, section):
return len(tableview.data_source.items)
def tableview_cell_for_row(self, tableview, section, row):
self.width, height = ui.get_screen_size()
cell = ui.TableViewCell()
cell.bounds = (0, 0, self.width, self.row_height)
for i in range(3):
self.make_labels(cell, tableview.data_source.items[row][i], i)
return cell
def make_labels(self, cell, text, pos):
label = ui.Label()
label.border_color = 'lightgrey'
label.border_width = 0.5
label.text = str(text)
if pos == 0:
label.frame = (self.width*0/5, 0, self.width/5, self.row_height)
elif pos == 1:
label.frame = (self.width*1/5, 0, self.width*2/5, self.row_height)
elif pos == 2:
label.frame = (self.width*3/5, 0, self.width*2/5, self.row_height)
label.alignment = ui.ALIGN_CENTER
cell.content_view.add_subview(label)
class MyTableViewDelegate(object):
@ui.in_background
def tableview_did_select(self, tableview, section, row):
select_voucher_index, select_voucher = tableview.data_source.items[row][:2]
Common().write_config('select_voucher_index', select_voucher_index)
Common().write_config('select_voucher', select_voucher)
MyTableView().refresh_last_voucher()```
Hi.
I have a table. It contains 3 columns.
I would like to make an interaction.
When I click a row in the table, the 3 column information should be stored in a dict.
# Create a tableview, with data
self.tv = ui.TableView()
self.tv.row_height = 30
self.tv.data_source = MyTableViewDataSource(self.tv.row_height)
#self.tv.delegate = MyTableViewDelegate()
# Update tableview data
self.tv.data_source.items = sorted(self.c.read_vouchers(), key=itemgetter(0), reverse=True)
# Do not allow selection on the TableView
self.tv.allows_selection = False
#self.tv.allows_selection = True
# Add the table
self.add_subview(self.tv)
And class
class MyTableViewDataSource(object):
def __init__(self, row_height):
self.row_height = row_height
self.width = None
def tableview_number_of_rows(self, tableview, section):
return len(tableview.data_source.items)
def tableview_cell_for_row(self, tableview, section, row):
self.width, height = ui.get_screen_size()
cell = ui.TableViewCell()
cell.bounds = (0,0,self.width,self.row_height)
for i in range(3):
self.make_labels(cell, tableview.data_source.items[row][i], i)
return cell
def make_labels(self, cell, text, pos):
label = ui.Label()
label.border_color = 'lightgrey'
label.border_width = 0.5
label.text = str(text)
if pos == 0:
label.frame = (self.width*0/5, 0, self.width/5, self.row_height)
elif pos == 1:
label.frame = (self.width*1/5, 0, self.width*2/5, self.row_height)
elif pos == 2:
label.frame = (self.width*3/5, 0, self.width*2/5, self.row_height)
label.alignment = ui.ALIGN_CENTER
cell.content_view.add_subview(label)
#class MyTableViewDelegate(object):
# def tableview_did_select(self, tableview, section, row):
# print 'select'
# def tableview_did_deselect(self, tableview, section, row):
# print 'deselect'
How would I do this?
And now the last modification..
Making exceptions work as well.
https://gist.github.com/tlinnet/aff5decf31d07d0c0cccfad7961353f7
I got it to work with, headers, ios basic authentication and parameters, and saving the response.
Thanks!
https://gist.github.com/tlinnet/31b35136e206ea2b4829a13799c89316
Now getting a return.
Don't know how to exactly to implement a "wait", but here is a try
import objc_util
from urlparse import urlparse
from urllib import urlencode
from ctypes import c_void_p
import time
class Web(object):
def __init__(self, url=None, params=None):
self.data = None
if params:
params_encoded = urlencode(params)
else:
params_encoded = ""
url = objc_util.nsurl("{}?{}".format(url, params_encoded))
request = objc_util.ObjCClass("NSURLRequest").request(URL=url)
configuration = objc_util.ObjCClass("NSURLSessionConfiguration").defaultSessionConfiguration()
session = objc_util.ObjCClass("NSURLSession").session(Configuration=configuration)
completionHandler = objc_util.ObjCBlock(self.responseHandlerBlock, restype=None, argtypes=[c_void_p, c_void_p, c_void_p, c_void_p])
objc_util.retain_global(completionHandler)
dataTask = session.dataTask(Request=request, completionHandler=completionHandler)
dataTask.resume()
def responseHandlerBlock(self, _cmd, data, response, error):
if error is not None:
error = objc_util.ObjCInstance(error)
print(error)
return
response = objc_util.ObjCInstance(response)
data = objc_util.ObjCInstance(data)
self.data = (str(objc_util.nsdata_to_bytes(data)))
def return_data(self):
return self.data
url = "http://validate.jsontest.com"
params = {"json" : {"first" : "lukas", "last" : "kollmer"}}
#validate(url, None, responseHandlerBlock)
#validate(url, params, responseHandlerBlock)
call = Web(url, params)
wait = True
while wait:
data = call.return_data()
if data != None:
print data
wait = False
print "Done"```
WOW!!!!
Thanks! :)
This works as expected. :)
I get a json back, I can work with.
I will try to implement this, and see if it passes the Apple review.
Thanks!
import objc_util
from urlparse import urlparse
from urllib import urlencode
from ctypes import c_void_p
NSURLRequest = objc_util.ObjCClass("NSURLRequest")
NSURLSession = objc_util.ObjCClass("NSURLSession")
NSURLSessionConfiguration = objc_util.ObjCClass("NSURLSessionConfiguration")
def validate(url, params, responseHandler):
if params:
params_encoded = urlencode(params)
else:
params_encoded = ""
url = objc_util.nsurl("{}?{}".format(url, params_encoded))
request = NSURLRequest.request(URL=url)
configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
session = NSURLSession.session(Configuration=configuration)
completionHandler = objc_util.ObjCBlock(responseHandler, restype=None, argtypes=[c_void_p, c_void_p, c_void_p, c_void_p])
objc_util.retain_global(completionHandler)
dataTask = session.dataTask(Request=request, completionHandler=completionHandler)
dataTask.resume()
def responseHandlerBlock(_cmd, data, response, error):
if error is not None:
error = objc_util.ObjCInstance(error)
print(error)
return
response = objc_util.ObjCInstance(response)
data = objc_util.ObjCInstance(data)
print(str(objc_util.nsdata_to_bytes(data)))
url = "http://validate.jsontest.com"
params = {"json" : {"first" : "lukas", "last" : "kollmer"}}
#validate(url, None, responseHandlerBlock)
validate(url, params, responseHandlerBlock)
I am here at the moment
from objc_util import *
class Web(object):
def __init__(self, root=None, method=None, headers=None):
#NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
self.request = ObjCClass('NSMutableURLRequest').alloc().initWithURL_(nsurl(root))
#[request setHTTPMethod:@"POST"];
self.request.setHTTPMethod_(method)
# Make headers
for key in headers:
#[request setValue:@"es" forHTTPHeaderField:@"Accept-Language"];
self.request.setValue_forHTTPHeaderField_(key, headers[key])
# Make request
#NSURLConnection * theConnection = [[NSURLConnection alloc] initWithRequest:imageRequest delegate:self];
#self.conn = ObjCClass('NSURLConnection').alloc().initWithRequest_delegate_(self.request, self)
self.conn = ObjCClass('NSURLConnection').alloc().initWithRequest_delegate_startImmediately_(self.request, self, True)
#[connection autorelease];
self.conn.autorelease()
But I dont know how to unpack or return the request?
So I get the response from the server?
Hi.
Since pythonista does not handle ipv6, I would like to make a method for objc_util, that can be a replacement for python request.
A objc_util replacement for a call like this:
import requests
root='http://validate.jsontest.com'
url=root+''
params = {'json':str({"key":"value"})}
r = requests.get(url, params=params)
print r.json()
@JonB said:
confdefs.h
No luck in finding confdefs.h or any setting with IPV6.
There is:
PythonistaAppTemplate/PythonistaKit.framework/pylib/_sysconfigdata.py
'ENABLE_IPV6': 1,```
But the header says:
# [omz] NOTE: This is required by site.py, but the values are not correct.
# It's a copy of the default OS X _sysconfigdata, but there shouldn't
# be much need for this on iOS anyway.
# system configuration generated and used by the sysconfig module
I will look into if Xcode can be manipulated to compile with ipv6 .
The road by using objc util instead, could be a solution. But I am simply lost there, and don't know how to bug track.
@omz can you confirm the ipv6 problem?
Has any apps been released to the app store, which use request?
The very first problem for this issue.
To establish an ipv6-only environment, when my router WAN is only ipv4.
So testing is difficult!
But it seems pythonista is shipped without ipv6 support. At least in the iOS app.
Another try, but still failing
https://gist.github.com/tlinnet/c1aaa1d4494548217b3ed91301f64eb2
This is difficult!
How to figure out how this is working in objc_util?
I think I have prepared a request, but now I want to make the request.
But I am lost....
This is where I am at the moment.
https://gist.github.com/tlinnet/92c0654081a6c49aa5b39a984018b253
Hi.
I am trying to submit an app for Apple app store.
It uses the python request module.
Apple request that such an app should support IPv6-only Networks.
https://developer.apple.com/news/?id=05042016a
The following snippet shows that ipv6 is not included.
It shows:
socket.has_ipv6 = False
error message: "error: getsockaddrarg: bad family"
import requests, socket
# Test of python has ipvp
print("Has ipv6?: %s\n"%socket.has_ipv6)
root='http://ipv6.whatismyv6.com/'
url=root
params = {}
try:
r = requests.get(url, params=params)
print("Request works\n")
except requests.exceptions.RequestException as e:
print("ERROR: Request does not work!")
print(str(e.message))
I have tested this on pythonista 3.0 and in the 2.7 and 3.5 interpreter.
So I made an initial script "strip_pylib.py".
This script should be runned in pythonista at the phone.
It will make a "pylib_clean.sh" file, which should be copied to:
"PATH/PythonistaAppTemplate/PythonistaKit.framework"
at the Xcode project.
And then issue:
source pylib_clean.sh
rm pylib_clean.sh
(Note: pylib_clean.sh should be deleted in the PythonistaKit.framework folder afterwards,
or there will be problems with signing and sending to App store.)
pylib_clean.sh will delete a lot of files.
After compilation in Xcode, the program did not work.
I had to manually copy back the directory: "/pylib/encodings" from another copy of PythonistaAppTemplate, and then it worked.
The compilation in Xcode is a lot faster. :)
And the app size went from 60 MB to 30 MB.
There are still some files left, but I am not sure why they survived.
strip_pylib.py
# Clear all
# To get pythonista to work again, restart the app
import sys
sys.modules[__name__].__dict__.clear()
# Now import
import sys
import inspect
import importlib
splitstr = "PythonistaKit.framework"
pyt_mods = [
"os",
"datetime",
"json",
"requests",
"operator",
"time",
]
pythonista_mods = [
"ui",
"console",
"dialogs",
"objc_util"
]
all_mods = pyt_mods + pythonista_mods
keep_list = []
for imods in all_mods:
try:
m = importlib.import_module(imods)
dirpath, filepath = inspect.getfile(m).split(splitstr)
keep_list.append(filepath)
except TypeError as e:
#print(e)
pass
# Get the imported modules
dict = sys.modules
for key in dict:
val = dict[key]
if val == None:
continue
else:
try:
filepath = inspect.getfile(val)
if splitstr in filepath:
filepath_append = filepath.split(splitstr)[1]
keep_list.append(filepath_append)
else:
pass
except TypeError as e:
#print(e)
pass
# Make uniq and sort
keep_list = sorted(set(keep_list))
# Now find all files
import os
fp = dirpath+splitstr
extensions = [".py", ".pyo"]
all_files = []
for path, dirs, files in os.walk(fp):
for f in files:
filename, file_extension = os.path.splitext(f)
if "/pylib/" in path or "/pylib_ext/" in path:
if file_extension in extensions:
stringfp = os.path.join(path, f)
dirpath, filepath = stringfp.split(splitstr)
all_files.append(filepath)
# Make uniq and sort
all_files = sorted(set(all_files))
# Make a delete list
dellist = [x for x in all_files if x not in keep_list]
# Write delete file
fname = 'pylib_clean.sh'
f = open(fname,'w')
f.write("#!/usr/bin/env bash\n")
for idel in dellist:
f.write("rm ."+idel+"\n")
f.close()
f = open(fname, "r")
for line in f:
print(line),
f.close()
I got this started.
Running this snippet on the phone, give me the file paths.
import inspect
import importlib
pyt_mods = [
"os",
"datetime",
"json",
"requests",
"operator",
"time",
]
pythonista_mods = [
"ui",
"console",
"dialogs",
"objc_util"
]
all_mods = pyt_mods + pythonista_mods
keep_list = []
for imods in all_mods:
try:
module_obj = importlib.import_module(imods)
filepath = inspect.getfile(module_obj).split("PythonistaKit.framework")[1]
keep_list.append(filepath)
except TypeError as e:
print(e)
for filep in keep_list:
print(filep)```