• blmacbeth

    I was playing around with the location module the other day and was wondering about how it deals with scripts closing without manually turning off location tracking. So I made a context Manager for the location module

    import location
    
    
    class LocationManager (object):
        def __enter__(self):
            location.start_updates()
    
        def __exit__(self):
            location.stop_updates()
    

    You can use it like so:

    with LocationManager():
        # Do stuff that requires `location` here...
        ...
    

    Now, this may be completely unnecessary, but I have found it useful for applications where constant location updates are not needed (e.g. get my location every 15 minutes or set my initial location for some one off script).

    @omz also think this may be a good feature for the built-in location module to adopt (if possible). So we can have both location.start(stop)_updates() or with location: ....

    Let me know what y'all think (criticism is welcome).

    B.

    EDIT
    A bit less verbose code with the help of @ccc on contexlib

    import contexlib
    import location
    
    @contexlib.contexmanager
    def location_enabled():
        location.start_updates()
        yield
        location.stop_updates()
    

    the use case is still the same.

    with location_enabled():
        # Do location stuff here...
        ...
    

    posted in Pythonista read more
  • blmacbeth

    @bistrot Add the #! python2 she-bang at the top of the script to tell it to use the (possibly) nom-default python 2.7 interpreter.

    posted in Pythonista read more
  • blmacbeth

    @omz and @Cethric thanks for the help. It seems to work.

    posted in Pythonista read more
  • blmacbeth

    I have a script where I'm trying to get the system attributes; eventually this will gather memory information. I have isolated the crash to this line of code:

    from ctypes import POINTER
    from objc_util import ObjCClass, ObjCInstance, c, c_void_p
    
    
    NSHomeDirectory = c.NSHomeDirectory
    NSHomeDirectory.restype = c_void_p
    NSHomeDirectory.argtype = []
    
    NSFileManager = ObjCClass('NSFileManager')
    
    LP_c_void_p = POINTER(c_void_p)
    
    def get_system_attributes():
        file_manager = NSFileManager.defaultManager()
        error = LP_c_void_p()
        attributes = file_manager.attributesOfFileSystemForPath_error_(
            ObjCInstance(
                NSHomeDirectory()
            ).cString(),
            error
        )
        return attributes
    
    get_system_attributes()
    

    attributesOfFileSystemForPath_error_ takes a string and an error pointer. It crashes when it gets to the error inside that function. I think it crashes due to an NSError object being created. Any ideas on how to stop the crash?

    posted in Pythonista read more
  • blmacbeth

    @Phuket2 quoted from the Apple developer forums:

    Retina Flash
    iPhone 6s and 6s Plus contain a custom display chip that allows the retina display to briefly flash 3 times brighter than its usual maximum illuminance. No new API was added to support this feature. Since iOS 4, AVCaptureDevice has supported the -hasFlash, -isFlashModeSupported: and -flashMode properties. The iPhone 6s and 6s Plus front-facing cameras are the first front-facing iOS cameras to respond YES to the -hasFlash property. By setting the front-facing camera's flashMode to AVCaptureFlashModeOn or AVCaptureFlashModeAuto, the retina flash fires when a still image is captured (see AVCaptureStillImageOutput’s captureStillImageAsynchronouslyFromConnection:completionHandler:), just as the True Tone flash fires for rear-facing camera stills.

    Hope this. Only works on 6s, 6s+, and SE.
    B.

    posted in Pythonista read more
  • blmacbeth

    @Tizzy sorry for not explaining myself better. @dgelessus is correct about the ? being the important part.

    I checked MySQL and it has its own syntax for variable arguments that just so happens to be %s. Shame on them…

    posted in Pythonista read more
  • blmacbeth

    @Tizzy it is good practice to not do statement = 'SELECT * FROM ' + table_name' or even statement = 'SELECT * FROM ' + %s' % table_name as this can cause security issues with SQL injection. Most database packages (read: modules) will have something along the lines of

    statement = '''
    SELECT *
    FROM ?
    '''
    with db.connect as conn:
        result = conn.execute(statement, (table_name,))
    

    This is a more secure way of accessing batabases. The other way is good enough for person projects, but keep that in mind or little Bobby Tables will make your life awful as a DBA.

    B.

    posted in Pythonista read more
  • blmacbeth

    @omz said:

    Btw, you can just pass a prefix to ObjCClass.get_names() instead of doing the filtering yourself (in the current beta, it would have to be a byte string though).

    Did not know that…

    posted in Pythonista read more
  • blmacbeth

    Hey @omz, I got back in to playing around with objc_util and found this:

    >>> dir(OMJavaScriptSyntaxHighlighter)
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/var/mobile/Containers/Bundle/Application/61407674-7331-47C2-B308-BDB7BBE52166/Pythonista3.app/Frameworks/PythonistaKit3.framework/pylib/site-packages/objc_util.py", line 380, in __dir__
        py_method_name = sel_name.replace(':', '_')
    TypeError: a bytes-like object is required, not 'str'
    

    This error come from the way Python3.* encodes ASCII vs Unicode strings. When you run the following:

    om_classes = [cls for cls in ObjCClass.get_names() if cls.startswith(b'OM')]
    for cls in om_classes:
        print(cls)
    

    You get the following (truncated for brevity):

    b'OMAutoresizingMaskView'
    b'OMBarButton'
    b'OMBarButtonItem'
    b'OMBaseSyntaxHighlighter'
    b'OMBasicPythonCompletionProvider'
    b'OMBasicPythonCompletionProviderTokenizedLine'
    b'OMButtonFieldSpecifier'
    b'OMCSSSyntaxHighlighter'
    b'OMCaretView'
    b'OMCheckCell'
    b'OMCheckFieldSpecifier'
    …
    b'OMUIWidgetViewScrollView'
    b'OMUIWidgetViewSegmentedControl'
    b'OMUIWidgetViewSlider'
    b'OMUIWidgetViewStickyNote'
    b'OMUIWidgetViewSwitch'
    b'OMUIWidgetViewTableView'
    b'OMUIWidgetViewTextField'
    b'OMUIWidgetViewTextView'
    b'OMUIWidgetViewWebView'
    

    Notice the b before the string. So, when you want to run string operations, which are now encoded as UTF-8, it throws a TypeError because ASCII is (for whatever reason) a byte-like object, not a string.

    To fix this you can have .get_names() return strings, or add the b prefix to the strings in replace() method in objc_util.

    posted in Pythonista read more
  • blmacbeth

    Noticed some bugs in the above code, so here are my fixes to make it work (in Pythonista3, at least).

    # coding: utf-8
    
    import ui
    from objc_util import *
    
    class BlurView (ui.View):
        def __init__(self, style=1, *args, **kwargs):
            ui.View.__init__(self, **kwargs)
            self._style = style
            self.effect_view = None
            self.setup_effect_view()
        
        @on_main_thread
        def setup_effect_view(self):
            if self.effect_view is not None:
                self.effect_view.removeFromSuperview()
            UIVisualEffectView = ObjCClass('UIVisualEffectView')
            UIVibrancyEffect = ObjCClass('UIVibrancyEffect')
            UIBlurEffect = ObjCClass('UIBlurEffect')
            UILabel = ObjCClass('UILabel')
            # Brooks patch for Rect not having a 'slice' 
            bounds = self.bounds.as_tuple()
            frame = (bounds[:2], bounds[2:])
            self.effect_view = UIVisualEffectView.alloc().initWithFrame_(frame).autorelease()
            effect = UIBlurEffect.effectWithStyle_(self._style)
            self.effect_view.effect = effect
            self.effect_view.setAutoresizingMask_(18)
            ObjCInstance(self).addSubview_(self.effect_view)
            vibrancy_effect = UIVibrancyEffect.effectForBlurEffect_(effect)
            self.vibrancy_view = UIVisualEffectView.alloc().initWithFrame_(frame).autorelease()
            self.vibrancy_view.effect = vibrancy_effect
            self.effect_view.contentView().addSubview_(self.vibrancy_view)
            
        @property
        def style(self):
            return self._style
        
        @style.setter
        def style(self, value):
            if value != self._style:
                self._style = value
                self.setup_effect_view()
        
        # Brooks fix @on_mains_thread to @on_main_thread
        @on_main_thread
        def add_vibrant_label(self, label):
            self.vibrancy_view.contentView().addSubview_(ObjCInstance(label))
    
    def main():
        image_view = ui.ImageView(frame=(0, 0, 320, 320))
        image_view.image = ui.Image.named('test:Mandrill')
        blur_view = BlurView(style=2, frame=image_view.bounds.inset(40, 40))
        image_view.add_subview(blur_view)
        label = ui.Label(frame=blur_view.bounds)
        label.text = 'Hello World'
        label.font = ('HelveticaNeue', 40)
        label.alignment = ui.ALIGN_CENTER
        blur_view.add_vibrant_label(label)
        image_view.present('sheet')
    
    main()
    

    The biggest problem was that the ui.Rect() object does not have the ability to use slices. This was fixed with the ui.Rect().as_tuple() function. The second problem was just a typo.

    B

    posted in Pythonista read more

Internal error.

Oops! Looks like something went wrong!