• trey

    I’ve enjoyed working with Pythonista over the past year, so today when I needed to do some Markdown editing, I purchased Editorial.

    I may just be mad, but for the life of me, I can’t find the files I’m creating. I want to find them so I can modify and add to them via Shortcuts and Share widgets.

    But while I’ve created some files of all types, naming them with unusual strings and including unusual strings in them so that I should be able to locate them in Files via text search, I can’t. They aren’t there, in Recents, in On My iPad, or on iCloud Drive.

    I found a configuration setting about Dropbox syncing, so I gave that a try, but the default folder (/Apps/Editorial) wasn’t created in Dropbox. So I created it, and tried to do a sync cycle, but nothing happened. So then I dropped a random Markdown file into that folder, and it showed up in Editorial, and if I modified it the modifications showed up in Dropbox. But the other files in Editorial aren’t there.

    It’s very strange... it seems like it isn’t writing out files at all, but I force-quit Editorial and restarted it, and the Markdown documents still show up, so it must be storing the files... somewhere.

    Is it using some strange hidden files or something, and if so, can I change that behavior so it just acts like Pythonista, Edidown, or any other iPad app where I can get to my files via the Files app?

    I apologize if I’m missing something very basic—since no one else has mentioned this on the forum as far as I can see, I imagine I’m just not looking in the right place or forgot to toggle some setting or something. I’d very much appreciate the hint! Thanks!

    posted in Editorial read more
  • trey

    I inadvertently broke pytest — I can still long-press Run and do “Run Doctests” and they work, but if I do “Run Unit Tests” I get the traceback below,, ending with PermissionError: [Errno 1] Operation not permitted: '/private/var/mobile/Library/Mobile Documents/pytest.ini'.

    I know I broke it myself: I used StaSh (with Python 3) to do a pip install pytest because I was previously (when it worked) running into a bug I saw pytest had fixed. I can’t figure out how to back out the changes inflicted by running this.

    Can anyone help me to fix this? Thanks!

    Traceback (most recent call last):
      File "/private/var/containers/Bundle/Application/1F6E6781-AC43-4C6A-86CC-E1540DE81702/Pythonista3.app/pythonista_pytest.py", line 52, in <module>
      File "/private/var/containers/Bundle/Application/1F6E6781-AC43-4C6A-86CC-E1540DE81702/Pythonista3.app/pythonista_pytest.py", line 17, in main
        pytest.main(['--verbose', script_path, '--junitxml=%s' % (log_path,), '-p', 'no:cacheprovider'])
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/_pytest/config/__init__.py", line 143, in main
        config = _prepareconfig(args, plugins)
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/_pytest/config/__init__.py", line 319, in _prepareconfig
        pluginmanager=pluginmanager, args=args
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/pluggy/hooks.py", line 286, in __call__
        return self._hookexec(self, self.get_hookimpls(), kwargs)
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/pluggy/manager.py", line 93, in _hookexec
        return self._inner_hookexec(hook, methods, kwargs)
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/pluggy/manager.py", line 87, in <lambda>
        firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/pluggy/callers.py", line 203, in _multicall
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/_pytest/helpconfig.py", line 100, in pytest_cmdline_parse
        config = outcome.get_result()  # type: Config
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/pluggy/callers.py", line 80, in get_result
        raise ex[1].with_traceback(ex[2])
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/pluggy/callers.py", line 187, in _multicall
        res = hook_impl.function(*args)
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/_pytest/config/__init__.py", line 1003, in pytest_cmdline_parse
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/_pytest/config/__init__.py", line 1280, in parse
        self._preparse(args, addopts=addopts)
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/_pytest/config/__init__.py", line 1157, in _preparse
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/_pytest/config/__init__.py", line 1080, in _initini
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/_pytest/config/findpaths.py", line 184, in determine_setup
        rootdir, inipath, inicfg = locate_config([ancestor])
      File "/private/var/mobile/Containers/Shared/AppGroup/D9BD8947-DFD5-470C-B1D9-66DA93B008C0/Pythonista3/Documents/site-packages-3/_pytest/config/findpaths.py", line 105, in locate_config
        if p.is_file():
      File "/var/containers/Bundle/Application/1F6E6781-AC43-4C6A-86CC-E1540DE81702/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/pathlib.py", line 1346, in is_file
        return S_ISREG(self.stat().st_mode)
      File "/var/containers/Bundle/Application/1F6E6781-AC43-4C6A-86CC-E1540DE81702/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/pathlib.py", line 1140, in stat
        return self._accessor.stat(self)
      File "/var/containers/Bundle/Application/1F6E6781-AC43-4C6A-86CC-E1540DE81702/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/pathlib.py", line 391, in wrapped
        return strfunc(str(pathobj), *args)
    PermissionError: [Errno 1] Operation not permitted: '/private/var/mobile/Library/Mobile Documents/pytest.ini'

    posted in Pythonista read more
  • trey

    A more direct answer, perhaps: As the StaSh README says, StaSh runs by default in Python 2, because not all of its functions work in Python 3.

    But I’ve simply taken the launch_stash.py script, and copied it to launch_stash3.py, then edited the latter so that the first line is:


    if you do the same, when you run launch_stash.py you’ll get it in Python 2, and launch_stash3.py in Python 3. If you run pip in a Python 3 StaSh, it will install Python 3 libraries.

    You can also use six by running pip -6 install…, but I’ve found modules installed into Python 3 that way from Python 2 StaSh to be unreliable. You can import them, but sometimes they don’t work, and pip list doesn’t show them in either StaSh 2 or 3. So I just wouldn’t do it.

    posted in Pythonista read more
  • trey

    I have a Scene-based program where I’d like to distinguish between finger and Pencil touch events.

    An example from omz showed how to do this in a ui.View; in the touch_* methods, use ObjCInstance on the touch argument:

        def touch_moved(self, touch):
            ui_touch = ObjCInstance(touch)

    then, I have verified, you can check the value of ui_touch.type() to determine if the touch is from a finger (0) or a Pencil (2).

    Unfortunately, I found out if you attempt to do the same in a Scene, the touch argument to the methods is not compatible with ObjCInstance. You get:

    ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type

    so, I’m wondering how I can get at a Touch object I can use the ObjC bridge with via a Scene?

    posted in Pythonista read more
  • trey

    @mikael said:

    @trey, to start with:




    posted in Pythonista read more
  • trey

    @JonB said:

    See some of the examples in this thread

    Those are exactly some of the cases I mentioned in my original post that make use of consoleViewController and I said didn’t work. But you write:

    In particular, consoleViewController is a objc method of the app delegate. There are some examples of how to get the default font.

    As I wrote initially, I saw this, and none of that code works for me—the traceback says consoleViewController does not exist. I concluded that given how old it was—and that some other forum posts I found earlier mentioned it had been removed—that it was no longer workable and couldn’t be made workable.

    Does it work for you, and if so, did you need to make modifications?

    There are some methods to load true type fonts... Under UIFont iirc.

    As I mentioned, I tried that as well; I could at best get a path to a ttf file, but couldn’t turn that into something that I could use in console, canvas or ui display.

    posted in Pythonista read more
  • trey

    I’m quite stumped as to how to list or select fonts inside a program or from the console. There are some examples here that are said to work, but they’re from posts that are years old and depend on a consoleViewController() method that appears to no longer exist and for which I can’t find a replacement.

    There are a few fonts used in Examples programs, but unless I missed something, all of them are hardcoded.¹

    Of course I can use the plus sign in the editor to select a font, but short of selecting each in turn and hardcoding them into my program so that they can, in turn, be chosen from, I can’t figure out how to give the user of my program a font chooser. (And since I have extra fonts that may not be the same as your extra fonts, even that hardcoding tactic is unlikely to work.)

    When I saw that ImageFont.truetype() had been modified for Pythonista, I thought perhaps I could use matplotlib.font_manager to find TrueType files, but it appears the matplotlib FontManager can only see files inside the matplotlib distribution (mostly Vera fonts), and even so, the FontManager’s outputs can’t be used in a console.set_font() call or a truetype() call—I haven’t tried other font methods outside matplotlib, but I assume they’d act the same.

    A code snippet that would simply list assign the known fonts to a list and then use one of them would at least get me started. Apologies if I’m missing something very obvious.

    Btw: is there a reason that console.set_font() either can be run with 2 valid arguments (which changes the font), or 0 arguments (which resets the font to default), but if you run, say, console.set_font('NoSuchFont', 18), you simply get a null-op—it neither throws an exception, nor resets the font? (Also, I can’t find a console.get_font() equivalent, even by digging through the guts of console—it seems like the currently selected font isn’t stored anywhere.)

    ¹ Not all of them are directly hardcoded; some are stored in variables that then get used. But they’re all hardcoded in appearing in the text of the program rather than being programmatically found.

    posted in Pythonista read more
  • trey

    @cvp To be fair, that is what we’ve been telling you for the last 27 messages in this thread. “Have you checked it’s plugged in?” is not unhelpful, but at some point you need to believe what people are telling you. :-)

    posted in Pythonista read more
  • trey

    @cvp said:

    @trey said:
    Please, first, try this little script without external keyboard, by pressing &h*, you will see a θ
    in your input field, in any app, if you use this script as custom keyboard.


    Then, don't change which keyboard is active (no globe key) and connect your Bluetooth keyboard. If your keyboard is coherent with the Pythonista QWERTY standard keyboard, the script will also work.

    No—I get normal QWERTY behavior from the hardware keyboard.

    For me, it does not because if I tap & or * on my keyboard, other keys are generated.

    Okay, but you can work around that. Here’s a script that—if it works as you say—should put asterisks before any character you type, and since it doesn’t care about the character, it shouldn’t matter QWERTY, AZERTY, or whatever:

    import keyboard
    import ui
    class KeyboardInfoView(ui.View):
        def __init__(self, *args, **kwargs):
            super().__init__(self, *args, **kwargs)
            self.background_color = '#00436e'
        def kb_should_insert(self, text):
            return '*'
    if __name__ == '__main__':
        v = KeyboardInfoView()
        keyboard.set_view(v, mode='minimized')

    Thus, with external keyboard, we get data but not obviously the same key as expected.

    I don’t believe that’s true. Try the above script. If it outputs * when you type hardware keyboard keys, then you are right. But it doesn’t for me. Your AZERTY keyboard shouldn’t matter in this case.

    posted in Pythonista read more
  • trey

    @cvp said:

    @trey said:

    with an external keyboard, it does absolutely nothing that I can see.

    I can't test anything, I don't have any external keyboard

    You really don’t have access to a single Bluetooth keyboard, nor a “Camera connection” dongle whose USB port you can use to hook up your desktop USB keyboard? You don’t need a special iPad or iOS-compatible keyboard.

    I’m speed throttled from replying to your multiple messages, so I’ll reply here:

    Could you give an example, please

    I did give three examples, in the words immediately after the ones you copy-pasted—“like Vim or Emacs offer, or RFC 1345 encoding”.

    If you mean how would it work, in RFC1345 encoding you type some character to enter RFC1345 encoding—ampersand is common—and then you type a sequence of from one to three ASCII characters that mnemonically get you a character elsewhere in Unicode space. For instance, to type θ, you press &h*—all the Greek letters are the matching letter followed by asterisk, so capital Θ is typed &H*. There are no ambiguous subsequences, so when you finish you immediately get the character and can continue typing ASCII or another sequence starting &.

    It’s slow for typing full texts in other languages, but for cases like International Phonetic Alphabet, math notation, or programming languages that use non-ASCII unicode, it’s quite handy. Even things like typing characters that require the ⌥ key on Macs into ASCII-only inputs.

    posted in Pythonista read more
  • trey

    @JonB said:

    Did the input_changed method get called at all?

    No, not if I hid the onscreen keyboard. (At least, assuming playing a sound on each input_changed() call—which works with the software keyboard—should also work with the HW keyboard.) My bluetooth keyboard has a button to toggle it on and off, though the Apple keyboards do not have such a key. (I presume there’s a normal key combo I don’t know to do this, from the way other special keys work. Not the globe key—this toggle key on my keyboard, I believe, either tells iPadOS “show me the onscreen keyboard even with the Bluetooth keyboard active”, or it changes its HID/SPP presentation so it’s a secondary keyboard. I’m not sure.)

    But the crucial takeaway is that, even when the onscreen keyboard is visible and active, keypresses on the hardware keyboard do not trigger input_changed().

    The only reason I think there really should be some way to interact with the hardware keyboard is that, when you switch keyboards to Pythonista or any other third-party software keyboard, the hardware keyboard goes to plain QWERTY—when I have it set up via Settings (General → Keyboard → Hardware Keyboard) to do Dvorak. Yet, when I’m using the default Apple keyboard setup, the onscreen keyboard is QWERTY but the hw keyboard remains in Dvorak. Literally at this moment I type this, I have the Apple standard onscreen keyboard showing QWERTY, but I’m typing in Dvorak. (And if I do peck at the screen, the keys come out as shown in QWERTY, not Dvorak. I have it set up that way, you can make the the software keyboard Dvorak too, if you so choose.)

    Honestly, it is not clear that the kb would get callbacks from an external keyboard -- i can't find anything in iOS docs that says it would. Since a kb extension is for converting user interaction into text, I can see reasons for not passing direct entry through a separate set of callbacks. Also, if the kb is not on screen, I'm not sure it is being called at all.

    That would comport exactly with the behavior I’m seeing. That would really be disappointing. It would explain, though, why there are no hardware-kb-compatible keyboards on the App Store for things like unusual/custom keymaps or for languages Apple doesn’t directly support, like many Native American languages and Esperanto—if the OS doesn’t support it at all for App Store keyboards, Pythonista can’t do it either.

    posted in Pythonista read more
  • trey

    I was interested in this same question and created a forum account intending to ask it when I saw this thread already active.

    So, I just tried the “BEF END” test script above (the latter one, “A little bit better), and it works as advertised in some programs (such as the Pythonista editor itself) when you tap “return” on the onscreen keyboard, except for one thing—it makes the text view jump down so that the typed text is offscreen.

    In other apps (such as typing into this very text field in the forum using Safari), it only partially works with the software keyboard—it inserts BEF, but never END.

    But with an external keyboard, it does absolutely nothing that I can see. Well, it does do one thing: my standard layout is Dvorak, but switching to Pythonista keyboard, the HW keyboard becomes QWERTY again.

    I tried the key_command mentioned, too, and it is never called.

    Btw, the problem I was hoping to solve was a multilingual keyboard—using switchable input methods like Vim and Emacs offer, or RFC 1345 encoding, letting me type multilingual text without having to learn the native keyboard layouts for each script.

    posted in Pythonista read more
  • trey

    I know this thread is 4 years old so I probably shouldn’t expect the code to work, but if I just run it I get:

    Traceback (most recent call last):
      File "_ctypes/callbacks.c", line 234, in 'calling callback function'
      File "/var/containers/Bundle/Application/1F6E6781-AC43-4C6A-86CC-E1540DE81702/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/objc_util.py", line 1066, in OMMainThreadDispatcher_invoke_imp
        retval = func(*args, **kwargs)
      File "/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/my-tools/find-on-docpage.py", line 68, in add_search_button
        doc_vc = get_docs_vc()
      File "/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/my-tools/find-on-docpage.py", line 49, in get_docs_vc
        if not tab_vc.documentationViewController():
      File "/var/containers/Bundle/Application/1F6E6781-AC43-4C6A-86CC-E1540DE81702/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/objc_util.py", line 798, in __call__
        method_name, kwarg_order = resolve_instance_method(obj, self.name, args, kwargs)
      File "/var/containers/Bundle/Application/1F6E6781-AC43-4C6A-86CC-E1540DE81702/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/objc_util.py", line 405, in resolve_instance_method
        raise AttributeError('No method found for %s' % (name,))
    AttributeError: No method found for documentationViewController

    (This post is now too long for me too see what I’m typing in the viewport, even maximized to the whole iPad screen, and there’s apparently no way to scroll, so I apologize if I have typoes belowe...)

    Perhaps my error is that I shouldn’t be running the script, but in some other way install it, as you do with extensions?

    Even if this doesn’t work anymore, a different method would be welcomed—I read the earlier comment saying to tap the title to get a tree traversal, like with code view, but I can’t figure out how to do that for the documentation—unlike the code, where there’s a centered title up top you can tap the documentation has an interface without a title bar at top, the search box replaces it—and that search box searches globally through the docs. Right now I’m looking at a method and I want to see if the argument name mentioned here is discussed anywhere else, but argument names aren’t indexed so I can’t find them via the search, I need a “search in page”, but a hierarchy view might give me a clue.

    The online docs, where I could use the ⌘ F in the browser, are problematic when I’m on VPN because the HTTPS link doesn’t work as the certificate has expired.


    p.s. Ooh! “edit” works to get the viewport to the bottom though it doesn’t scroll up, so I’ll try to fix this mess now.... this is current Safari on current iPadOS 13 on an iPad Pro 10.5” using a Bluetooth keyboard, btw, since I assume this limitation isn’t universal!

    posted in Pythonista read more
Internal error.

Oops! Looks like something went wrong!