A Great Seed for Angular Material – Cordova Apps

A Great App Seed from Mario Aleo

Mario Aleo has published a GREAT App Seed for Cordova – Angular Material Apps on his GitHub Repository cordova-angular-angularMaterial-seed.

When i first encountered a reference to the seed here on stackOverflow, I said “This looks like EXACTLY what i need. It [the Repository Documentation] is VERY WELL EXPLAINED”.

Since then, in the space of just a few hours, I have used Mario’s seed to produce a running app on my tablet. Not only is the GitHub Repository documentation GREAT, but the code in the Mario’s seed is SUPERBLY READABLE. I will learn a lot from using your code, Mario. Thanks.

Also, Mario says that his work is based on AngularJS Best Practices: Directory Structure by Adnan Kukic (@kukicadnan).

Thanks to BOTH of you.

Love and peace,

Joe

Execute Shell Commands from a Python GUI App

GUI Execute Commands

Here’s my Python – TKinter App that takes a set of Shell Commands from a .json file and displays them for individual execution when a button is clicked. Write these frequently used commands once and let the GUI program remember their syntax.

Keep 3 files in the same directory:

  • guiExecuteCommands.py The TKInter Program
  • config.json The Configuration Data
  • cmds.json The Initial Command Set

Contents

  • The TKInter Program File – guiExecuteCommands.py
  • The Configuration Data File – config.json
  • The Initial Command Set – cmds.json
  • A Screenshot of the TKInter Program
  • A run log of the program

The TKInter Program File – guiExecuteCommands.py

Here is the guiExecuteCommands.py file.

#!/usr/bin/python
# -*- coding: utf-8 -*-
# guiExecuteCommands.py
import sys, os, time, subprocess, json, atexit

# if not('.' in sys.path): sys.path.append('.')
# from MyCommands import cmds

import Tkinter, tkFileDialog

class Theapp(Tkinter.Tk):
    def __init__(self,parent):

        # joe's init
        with open('config.json') as data_file:
            cfg_data = json.load(data_file)
        self.cfg_data = cfg_data 

        with open(cfg_data[0]['commandsf']) as data_file:
            cmds = json.load(data_file)
        self.cmds = cmds 


        atexit.register(self.on_exit) # http://stackoverflow.com/a/28664350/601770


        # /joe's init




        Tkinter.Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()

    def on_exit(self):
        ''' http://stackoverflow.com/a/28664350/601770  
            save the state that has been changed
        '''

        self.cfg_data[0]['workingd'] = self.cwd.get()


        print "self.cwd.get(): %s"%(self.cwd.get())
        print "self.cfg_data: %s"%(self.cfg_data)

        with open('config.json', 'w') as f:
            json.dump(self.cfg_data, f)

    def execute_cmd(self, rnum):
        ''' C:\1d\PythonPjs\subprocessPjs\executeCommandsPj\executeCommands\executeCommands.py

        '''
        commandstring = self.cmd_entries[rnum].get()
        cwdpath = self.cwd.get()
        outstr = subprocess.check_call(commandstring, cwd=cwdpath, shell=True)  #  Convenience Function
        print outstr


    ## http://stackoverflow.com/a/16777523/601770   
    def bclick(self, rnum):
        def click():            
            self.execute_cmd(rnum)
        return click



    def browse2cwd(self):   
        """
        http://stackoverflow.com/questions/11295917/how-to-select-a-directory-and-store-the-location-using-tkinter-in-python
        http://tkinter.unpythonic.net/wiki/tkFileDialog
            find "def askdirectory(self):"
        """   
        tkFileDiaOpt4Dir = {}
        tkFileDiaOpt4Dir['initialdir'] = self.cwd.get()
        tkFileDiaOpt4Dir['mustexist'] = False
        tkFileDiaOpt4Dir['parent'] = self
        tkFileDiaOpt4Dir['title'] = 'Browse to set CWD.'

        self.cwd.set( tkFileDialog.askdirectory(**tkFileDiaOpt4Dir) )

        print "browse2cwd:  self.cwd.get(): %s"%(self.cwd.get())

    def initialize(self):
        self.cwd = Tkinter.StringVar()
        self.cwd.set(self.cfg_data[0]['workingd'])

        self.grid()  # make this be a grid

        ### add the gui elements in here

        ## browse to working directory
        label = Tkinter.Label(self, text="Working Directory", fg="white",bg="blue")
        label.grid(column=0,row=0,columnspan=3,sticky='W')

        self.cwd_entry = Tkinter.Entry(self, width=80, textvariable=self.cwd)
        self.cwd_entry.grid(column=0,row=1,columnspan=2, sticky='W') # http://effbot.org/tkinterbook/entry.htm

        b = Tkinter.Button(self,text=u"Browse", command=self.browse2cwd)
        b.grid(column=2,row=1) 

        toprowscount = 2


        ## command row elements len == len(MyCommands.cmds)
        self.buttons = []
        self.cmd_entries = []
        for rnum, cmd in enumerate(self.cmds):


            label = Tkinter.Label(self, anchor="w",text=cmd['label'], fg="white",bg="blue")
            label.grid(column=0,row=rnum+toprowscount,sticky='EW')

            self.cmd_entries.append( Tkinter.Entry(self, width=60) )
            self.cmd_entries[-1].grid(column=1,row=rnum+toprowscount,sticky='EW'); self.cmd_entries[-1].insert(0, (cmd['cmd']+' '+ cmd['args']))


            b = Tkinter.Button(self,text=u"Ex%s"%(rnum), command=self.bclick(rnum))
            b.grid(column=2,row=rnum+toprowscount) 

            self.buttons.append(b)


        ## Finish up
        self.grid_columnconfigure(0,weight=1) # make resizable
        self.resizable(True,False)            # make resizable ONLY HORIZONTALLY




if __name__ == "__main__":
    app = Theapp(None)
    app.title('Gui Execute Comands')
    app.mainloop()

The Configuration Data File – config.json

Here is the config.json file.

[{
   "programd": "C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand", 
   "commandsf": "C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand\\cmds.json",  
   "configd": "C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand", 
   "workingd": "C:/1d/CrossPlatformPjs/CordovaPjs/cordovaAngular00Pj/cordovaAngular00"
}]

The Initial Command Set – cmds.json

Here is the (INITIAL) cmds.json file

[
  {"cmd": "cordova", "args": "run android", "label": "android build 4 device"}, 
  {"cmd": "cordova", "args": "emulate android", "label": "android build 4 emulation"}, 
  {"cmd": "dir", "args": "*", "label": "dir of working dir"}
]  

A Screenshot of the TKInter Program

Here is a screenshot of the program.

guiExecuteShot

A run log of the program

Here is a run log.

Note: if the user changed the working directory, on exit the new working directory will be saved in the config.json file.

C:\1bat\guiExecuteCommands>guiExecuteCommands.py
browse2cwd:  self.cwd.get(): C:/1d/CrossPlatformPjs/Building Single Page Web Apps with AngularJS PJ
 Volume in drive C is Windows
 Volume Serial Number is F2FB-4810

 Directory of C:\1d\CrossPlatformPjs\Building Single Page Web Apps with AngularJS PJ

12/23/2015  09:58 AM    <DIR>          .
12/23/2015  09:58 AM    <DIR>          ..
12/23/2015  11:11 AM    <DIR>          zetc
               0 File(s)              0 bytes
               3 Dir(s)  900,352,217,088 bytes free
0
self.cwd.get(): C:/1d/CrossPlatformPjs/Building Single Page Web Apps with AngularJS PJ
self.cfg_data: [{u'programd': u'C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand', u'commandsf': u'C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand\\cmds.json', u'configd': u'C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand', u'workingd': u'C:/1d/CrossPlatformPjs/Building Single Page Web Apps with AngularJS PJ'}]

C:\1bat\guiExecuteCommands>

Show jQuery Client info in web2py View

This web2py View shows jQuery Client Side Info

{{left_sidebar_enabled,right_sidebar_enabled=False,('message' in globals())}}
{{extend 'layout.html'}}

{{block head}}

        $(document).ready(function(){
            $("#width").html($(window).width());
            $("#height").html($(window).height());

        });

{{end}}

{{if 'message' in globals():}}
<h3>{{=message + "hello 3"}}</h3>
<h3>width: <span id="width"></span>    height: <span id="height"></span></h3>
{{pass}}


Get web2py Debugging Info

Get Debugging Info

Here’s a quick way to get debugging info (Mobile or NOT).

from gluon.contrib.user_agent_parser import mobilize
import datetime
@mobilize
def index():
""" Here's an easy web2py debugging action [mobile or NOT] """
response.flash = T("Welcome to web2py!")
m = str(datetime.datetime.now()) +"\n"
m += str(request.user_agent()) +"\n"
m += "\n"
m += "Hi. We have skipped a line."
return dict(message=PRE(T(m)))

Output:
2015-12-03 19:47:23.762934
<Storage {'os': <Storage {'version': 'NT 10.0', 'name': 'Windows'}>, 'is_tablet': False, 'is_mobile': False, 'browser': <Storage {'version': '46.0.2490.86', 'name': 'Chrome'}>}>

Hi. Is next line.

Headless Selenium on Ubuntu 14.04 with PhantomJS 2.0

Headless Selenium on Ubuntu 14.04 with PhantomJS 2.0

N.B. This is STILL incomplete.

More work later :)

We’re following the excellent Headless Selenium Testing With Python and PhantomJS

Install Selenium

Let’s use pip to install Selenium

$ pip install selenium

Install PhantomJS

To make PhantomJS installation easy we will use the GitHub Repository, PhantomJS 2.0 built on Ubuntu 14.04 x64.

  1. Let’s login as root, cd to the root home.
    $ # However you login as root - I use WinSCP & Putty.
    $ cd ~
    
  2. According to the notes on the GitHub, to avoid the noticed dependency error, first let’s install “libicu52”.
    $ sudo apt-get install libicu52
    
  3. Now let’s just follow the original instructions on the GitHub Repository.
    $ # Since the file the GitHub Repository is 
    $ #    **actually** the phantomjs **executable**, 
    $ # And we want system wide access,
    $ cd /usr/bin
    
    # Now do our GitHub Repository wget into /usr/bin
    $ $ wget https://github.com/Pyppe/phantomjs2.0-ubuntu14.04x64/raw/master/bin/phantomjs
    
    # Now change the permissions
    $ chmod 0755 phantomjs
    
    $ # -rwxr-xr-x 1 root root 56596085 Aug 26 09:22 phantomjs
    

    That does it.

Love and peace,
Joe