analitics

Pages

Wednesday, March 4, 2020

Python 3.6.9 : My colab tutorials - part 002.

This is another notebook with the Altair python package.
The development team comes with this intro:
Altair is a declarative statistical visualization library for Python, based on Vega and Vega-Lite.

Altair offers a powerful and concise visualization grammar that enables you to build a wide range of statistical visualizations quickly. Here is an example of using the Altair API to quickly visualize a dataset with an interactive scatter plot:

See the notebook at my GitHub account.

Sunday, March 1, 2020

Python 3.6.9 : My colab tutorials - part 001.

Today I start this tutorials series for the Colab tool.
To share my working with the Colab tool I created this GitHub project.
This project has two colab files :
catafest_001.ipynb  Created using Colaboratory  
catafest_002.ipynb  Created using Colaboratory 
First colab notebook come with a simple tutorial.
The next colab notebook is a little bit more complex and shares more information about how can deal with simples tasks on colab.
This is the table of contests for this colab notebook:
  • Table of contents
  • Select GPU for this notebook
  • Check with nvidia-smi
  • Check whether you have a visible GPU
  • Check with tensoflow test
  • Read information about hardware
  • Check cpuinfo
  • Check meminfo
  • Use Linux commands
  • Use python modules torch and fastai
  • Use python modules
  • Show and get information
  • Enter credentials with Username and Password:
  • Datatime fields
  • Raw fields
  • Number fields
  • Boolean fields
  • Pandas data fields
  • Upload files
  • Upload local files
  • Use the Jupyter Widgets

Python Qt5 : Create a spectrum equalizer.

I haven't written much for a while on these issues about python and PyQt5.
Today I will show a complex example of QtMultimedia and how to create a spectrum equalizer.
First, the PyQt5 bindings come with this python module named QtMultimedia.
The main reason was the lack of time and focus of my effort on more stringent elements of my life.
Let's start with the few lines of source code that show us how can use this python module.
[mythcat@desk ~]$ python3 
Python 3.7.6 (default, Jan 30 2020, 09:44:41) 
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import PyQt5
>>> from PyQt5.QtMultimedia import *
>>> dir(PyQt5.QtMultimedia)
['QAbstractVideoBuffer', 'QAbstractVideoFilter', 'QAbstractVideoSurface', 'QAudio', 'QAudioBuffer',
 'QAudioDecoder', 'QAudioDeviceInfo', 'QAudioEncoderSettings', 'QAudioFormat', 'QAudioInput', 'QAudioOutput',
 'QAudioProbe', 'QAudioRecorder', 'QCamera', 'QCameraExposure', 'QCameraFocus', 'QCameraFocusZone',
 'QCameraImageCapture', 'QCameraImageProcessing', 'QCameraInfo', 'QCameraViewfinderSettings', 
 'QImageEncoderSettings','QMediaBindableInterface', 'QMediaContent', 'QMediaControl', 'QMediaMetaData', 
 'QMediaObject', 'QMediaPlayer', 'QMediaPlaylist', 'QMediaRecorder', 'QMediaResource', 'QMediaService', 
 'QMediaTimeInterval', 'QMediaTimeRange', 'QMultimedia', 'QRadioData', 'QRadioTuner', 'QSound', 'QSoundEffect',
 'QVideoEncoderSettings', 'QVideoFilterRunnable', 'QVideoFrame', 'QVideoProbe', 'QVideoSurfaceFormat',
 '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
The next issue is creating a random equalizer effect with bars.

This source doesn't use the QtMultimedia but can be implemented in the random area of equalizer set by update_values function:
import random
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtCore import pyqtSignal as Signal

print("load all modules!")

class Equalizer_Bars(QtWidgets.QWidget):

    def __init__(self, bars, steps, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # this fit the size to equalizer bars area
        self.setSizePolicy(
            QtWidgets.QSizePolicy.MinimumExpanding,
            QtWidgets.QSizePolicy.MinimumExpanding
        )
        # set the size of the window
        self.setMinimumHeight(480)
        self.setMinimumWidth(640)
        
        if isinstance(steps, list):
            # list of colours.
            self.n_steps = len(steps)
            self.steps = steps

        elif isinstance(steps, int):
            # int number of bars, defaults to blue.
            self.n_steps = steps
            self.steps = ['blue'] * steps
        else:
            raise TypeError('steps variable set wrong, try with a list or int')
        
        # create bars
        self.set_bars = bars
        # define settings of bars
        self.set_space_between_bars = 1
        self.set_height_of_bars = 1
        # set color of background
        self.set_background_color = QtGui.QColor('white')
        # set padding by pixel .
        self.set_padding = 10  

        # create timer 
        self.set_timer = None
        # set decay for move bars 
        self.set_decay_frequency_ms(76)
        self.set_decay_value= 10

        # set values for minim and maxim 
        self.set_min_value = 0
        self.set_max_value = 100

        # store all current values in a list.
        self.set_all_values= [0.0] * bars


    def paintEvent(self, e):
        # create a painter
        painter = QtGui.QPainter(self)
        # create a brush for drawing 
        brush = QtGui.QBrush()
        brush.setColor(self.set_background_color)
        brush.setStyle(Qt.SolidPattern)
        rect = QtCore.QRect(0, 0, painter.device().width(), painter.device().height())
        painter.fillRect(rect, brush)
        
        # set the canvas.
        d_height = painter.device().height() - (self.set_padding * 2)
        d_width = painter.device().width() - (self.set_padding * 2)

        # set the bars.
        step_y = d_height / self.n_steps
        bar_height = step_y * self.set_height_of_bars
        bar_height_space = step_y * (1 - self.set_space_between_bars) / 2

        step_x = d_width / self.set_bars
        bar_width = step_x * self.set_space_between_bars
        bar_width_space = step_x * (1 - self.set_height_of_bars) / 2

        for i in range(self.set_bars):

            # calculating the y position for this bar for stop, from the value in range.
            c = (self.set_all_values[i] - self.set_min_value) / (self.set_max_value - self.set_min_value)
            n_steps_to_draw = int(c * self.n_steps)

            for n in range(n_steps_to_draw):
                brush.setColor(QtGui.QColor(self.steps[n]))
                rect = QtCore.QRect(
                    self.set_padding + (step_x * i) + bar_width_space,
                    self.set_padding + d_height - ((1 + n) * step_y) + bar_height_space,
                    bar_width,
                    bar_height
                )
                painter.fillRect(rect, brush)

        painter.end()

    def _trigger_refresh(self):
        self.update()

    def set_decay_trick(self, f):
        self.set_decay_value= float(f)

    def set_decay_frequency_ms(self, ms):
        if self.set_timer:
            self.set_timer.stop()

        if ms:
            self.set_timer = QtCore.QTimer()
            self.set_timer.setInterval(ms)
            self.set_timer.timeout.connect(self.set_decay_beat)
            self.set_timer.start()

    def set_decay_beat(self):
        self.set_all_values= [
            max(0, v - self.set_decay_value)
            for v in self.set_all_values
        ]
        self.update()  # Redraw new position.

    def size_values(self, v):
        self.set_all_values= v
        self.update()

    def values(self):
        return self.set_all_values

    def set_range(self, vmin, vmax):
        assert float(vmin) < float(vmax)
        self.set_min_value, self.set_max_value = float(vmin), float(vmax)
    # will be used with QBrush 
    def setColor(self, color):
        self.steps = [color] * self._bar.n_steps
        self.update()

    def set_color_bars(self, colors):
        self.n_steps = len(colors)
        self.steps = colors
        self.update()

    def set_bar_padding(self, i):
        self.set_padding = int(i)
        self.update()

    def set_bar_solid_percent(self, f):
        self._bar_solid_percent = float(f)
        self.update()

    def set_background_color(self, color):
        self.set_background_color = QtGui.QColor(color)
        self.update()


class Window(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()

        self.equalizer = Equalizer_Bars(8, \
        ['#00405e', '#3350a1', '#386787','#0088ba','#3396e6', '#00b9d0','#c1f9f9', '#cce2f7'])

        self.setCentralWidget(self.equalizer)

        self.set_timer = QtCore.QTimer()
        self.set_timer.setInterval(100)
        self.set_timer.timeout.connect(self.update_values)
        self.set_timer.start()

    def update_values(self):
        self.equalizer.size_values([
            min(100, i+random.randint(0, 500) if random.randint(0, 10) > 2 else i)
            for i in self.equalizer.values()
            ])
            
# start the program 
app = QtWidgets.QApplication([])
w = Window()
w.show()
app.exec_()

Thursday, February 27, 2020

Python 3.6.9 : Google give a new tool for python users.

Today I discovered a real surprise gift made by the team from Google for the evolution of programmers.
I say this because not everyone can afford hardware resources.
This gift is a new tool called Colab and uses these versions of python and sys:
Python version
3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0]
Version info.
sys.version_info(major=3, minor=6, micro=9, releaselevel='final', serial=0)
This utility allows you to run source code that requires online hardware resources using your google account.
Colab allows you to use and share Jupyter notebooks because is an open-source project on which Colab is based.
The types of GPUs that are available in Colab varies over time.
This is necessary for Colab to be able to provide access to these resources for free.
The GPUs available in Colab often include Nvidia K80s, T4s, P4s, and P100s.
This way you can test demanding modules like the python TensorFlow module.
The utility is free but you can pay extra for more hardware resources.
Colab notebooks are stored in Google Drive, or can be loaded from GitHub.
You can see a simple intro with a notebook on my GitHub account.

Tuesday, February 25, 2020

Python 3.7.6 : The new concepts of execution in python 3 - part 001.

The main goal of these tutorials series is learning to deal with python source code using the new concepts of execution in python 3.
When two or more events are concurrent it means that they are happening at the same time.
Concurrent programming is not equivalent to parallel execution.
In computing, concurrency is the execution of pieces of work or tasks by a computer at the same time.
Concurrency is a property which more than one operation can be run simultaneously.
When multiple computations or operations are carried out at the same time or in parallel with the goal of speeding up the computation process then this process is named parallelism.
Parallelism is a property which operations are actually being run simultaneously using the multiprocessing.
Multiprocessing, on the other hand, involves utilizing two or more processor units on a computer to achieve parallelism.
Multithreading is a property that refers to the ability of a CPU to execute multiple threads concurrently.
Python’s concurrency methods including threading, multiprocessing, and asyncio.
The difference between the threading and multiprocessing is this: the threading module uses threads, the multiprocessing module uses processes.
The threading is the package that provides API to create and manage threads.
With multiprocessing, Python creates new processes using an API similar to the threading module.
The asyncio is a library to write concurrent code using the async/await syntax.
The keyword async indicates that our function is a coroutine meaning they choose when to pause and let others execute and run coroutines multitask cooperatively.
The three fundamental advantages of async and await over threads are:
  • cooperative multitasking - you can reasonably have millions of concurrent tasks;
  • using await makes visible where the schedule points;
  • if a task doesn’t yield then it can accidentally block all other tasks from running;
  • tasks can support cancellation.
The next source of code show us how can deal with the execution code in Python 3 using the threading and multiprocessing python packages.
The timeit python package is used to benchmark the code write in the code_to_test variable:
Let's test the multi-threading execution with python:
[mythcat@desk ~]$ python3 
Python 3.7.6 (default, Jan 30 2020, 09:44:41) 
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> code_to_test = """
... import threading
... 
... text = "Hello World"
... 
... def print_text(text):
...     for char in text:
...             print (char)
... 
... # multi-threading execution
... def multi_threads():
...     thread_1 = threading.Thread(target=print_text(text))
...     thread_2 = threading.Thread(target=print_text(text))
...     thread_1.start()
...     thread_2.start()
...     thread_1.join()
...     thread_2.join()
... multi_threads()
... """
>>> 
>>> elapsed_time = timeit.timeit(code_to_test, number=1)
H
e
l
l
o
 
W
o
r
l
d
H
e
l
l
o
 
W
o
r
l
d
>>> print(elapsed_time)
0.010613240000566293
Let's test the serially execution with python:
[mythcat@desk ~]$ python3 
Python 3.7.6 (default, Jan 30 2020, 09:44:41) 
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> code_to_test = """
... import threading
... 
... text = "Hello World"
... 
... def print_text(text):
...     for char in text:
...             print (char)
... # serially execution
... def serially():
...     print_text(text)
...     print_text(text)
... serially()
... """
>>> elapsed_time = timeit.timeit(code_to_test, number=1)
H
e
l
l
o
 
W
o
r
l
d
H
e
l
l
o
 
W
o
r
l
d
>>> print(elapsed_time)
0.011771811000471644
Let's test the multiprocessing execution with python:
[mythcat@desk ~]$ python3 
Python 3.7.6 (default, Jan 30 2020, 09:44:41) 
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> code_to_test = """
... import multiprocessing
... 
... text = "Hello World"
... 
... def print_text(text):
...     for char in text:
...             print (char)
... 
... # multiprocessing execution
... def multiprocessing_test():
...      process_1 = multiprocessing.Process(target=print_text(text))
...      process_2 = multiprocessing.Process(target=print_text(text))
...      process_1.start()
...      process_2.start()
...      process_1.join()
...      process_2.join()
... multiprocessing_test()
... """
>>> elapsed_time = timeit.timeit(code_to_test, number=1)
H
e
l
l
o
 
W
o
r
l
d
H
e
l
l
o
 
W
o
r
l
d
>>> print(elapsed_time)
0.3649730779998208
Since asyncio is a little complex, I will write about this in the next tutorial.

Sunday, February 23, 2020

Python 3.7.6 : The SELinux python package.

The tutorial for today is about the SELinux python package.
The official webpage is this.
First, I update my pip tool and I used the python 3.7.6 version:
[mythcat@desk ~]$ pip install --upgrade pip --user
...
Successfully installed pip-20.0.2
Let's install the python package named selinux:
[mythcat@desk ~]$ pip3 install selinux --user
...
Requirement already satisfied: selinux in /usr/lib64/python3.7/site-packages (2.9)
Let's test it:
[mythcat@desk ~]$ python3 
Python 3.7.6 (default, Jan 30 2020, 09:44:41) 
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import selinux 
>>> from selinux import * 
>>> print(dir(selinux))
Now, I can test my SELinux with this python package:
>>> selinux.is_selinux_enabled()
1
>>> selinux.selinux_getenforcemode()
[0, 0]
>>> mode = selinux.security_getenforce()
>>> mode
0
>>> selinux.selinux_getpolicytype()
[0, 'mls']
>>> selinux.is_selinux_enabled()
1
>>> selinux.is_selinux_mls_enabled()
1
>>> selinux.get_default_context('mythcat','user_u:object_r:user_home_t:s0')
[-1, None]
>>> context = selinux.matchpathcon(os.path.normpath(/), 0)[1]
>>> context
'system_u:object_r:root_t:s0'
>>> selinux.restorecon('/')
>>> context_t = selinux.getfilecon('/')[1].split(":")[2]
>>> context_t 
'root_t'
>>> context_t = selinux.getfilecon('/home/mythcat')[1].split(":")[2]
>>> context_t 
'user_home_dir_t'
>>> selinux.matchpathcon('/', mode)
[0, 'system_u:object_r:root_t:s0']
>>> selinux.matchpathcon('/home/mythcat', mode)
[0, 'user_u:object_r:user_home_dir_t:s0']
>>> file_context=selinux.lgetfilecon('/home/mythcat/sel_001.py')
>>> file_context
[31, 'user_u:object_r:user_home_t:s0']
>>> selinux.security_policyvers()
32

Saturday, February 22, 2020

Python 3.7.5 : This python package can work with ArcGIS platform.

This python package is named like the ArcGIS platform and can be used for spatial analysis, mapping, and GIS.
The ArcGIS package uses the ArcGIS platform for organizations to create, manage, share, and analyze spatial data.
This platform has a server component, mobile and desktop applications, and developer tools.
[mythcat@desk projects]$ pip3 install arcgis --user
...
You can test it on your workstation or live using the notebooks esri.com, see the next screenshot:

Let's search all maps from world with the maps of disaster using the notebook from esri website.
from arcgis.gis import GIS
from arcgis.geocoding import geocode
from IPython.display import display
from arcgis.mapping import WebMap
from arcgis.geoprocessing import import_toolbox
gis = GIS()
map1 = gis.map()

webmap_search = gis.content.search("disaster", item_type="Web Map")
webmap_search
The result will be this list:
[<Item title:"Hurricane and Cyclone Web Map" type:Web Map owner:cfernerDRP>, 
<Item title:"Severe Weather Web Map" type:Web Map owner:cfernerDRP>, 
<Item title:"NYC OEM Hurricane Evacuation Zones" type:Web Map owner:nfurness>, 
<Item title:"County of San Diego Emergency Map (Live)" type:Web Map owner:oes_services>, 
<Item title:"Zombie US" type:Web Map owner:wjones_mt>, 
<Item title:"2009 Social Vulnerability in the United States (Mature Support)" type:Web Map owner:esri>, 
<Item title:"Waldo Canyon Fire - Consolidated Public Information" type:Web Map owner:jpfeffer>, 
<Item title:"US Wildfire Activity Web Map" type:Web Map owner:cfernerDRP>, 
<Item title:"Earthquake Web Map" type:Web Map owner:cfernerDRP>, 
<Item title:"Current Weather and Wind Station Information" type:Web Map owner:esri_livefeeds>]
Now you can show each map by usinh the index:
map_one = webmap_search[1]
map_one

Wednesday, February 19, 2020

Python 3.7.5 : The PyQtChart from python Qt5.

The PyQtChart is a set of Python bindings for The Qt Company’s Qt Charts library and is implemented as a single module.
Let's install this python package with the pip3 tool:
[mythcat@desk ~]$ pip3 install PyQtChart --user
...
Installing collected packages: PyQtChart
Successfully installed PyQtChart-5.14.0
Let's test with a simple example:
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
from PyQt5.QtChart import QChart, QChartView, QPieSeries, QPieSlice
from PyQt5.QtGui import QPainter, QPen
from PyQt5.QtCore import Qt

class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("testing Pie Chart")
        self.setGeometry(100,100, 640,480)
        self.show()
        self.create_piechart()

    def create_piechart(self):

        series = QPieSeries()
        #append all values with a sum of 360 
        series.append("size 5", 5)
        series.append("size 10", 10)
        series.append("size 30", 30)
        series.append("size 45", 45)
        series.append("size 90", 90)
        series.append("size 180", 180)

        #adding slice 
        slice = QPieSlice()
        slice = series.slices()[2]
        slice.setExploded(True)
        slice.setLabelVisible(True)
        slice.setPen(QPen(Qt.darkGreen, 1))
        slice.setBrush(Qt.green)
        slice = series.slices()[4]
        slice.setExploded(False)
        slice.setLabelVisible(True)
        slice.setPen(QPen(Qt.red, 1))
        #slice.setBrush(Qt.blue)

        #create chart 
        chart = QChart()
        #chart.legend().hide()
        chart.addSeries(series)
        chart.createDefaultAxes()
        chart.setAnimationOptions(QChart.SeriesAnimations)
        chart.setTitle("The all 360 on  chart .")

        chart.legend().setVisible(True)
        chart.legend().setAlignment(Qt.AlignBottom)

        chartview = QChartView(chart)
        chartview.setRenderHint(QPainter.Antialiasing)

        self.setCentralWidget(chartview)

App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec_())
The result can be seen in the next image:

Sunday, February 16, 2020

Python 3.7.5 : The httpx python package.

Today I will present a new python packet that can help you in developing web applications.
This is the next generation HTTP client for Python and is named httpx.
This python package comes with a nice logo: a butterfly.
The official webpage can be found at this webpage.
The development team come with this intro:
HTTPX is a fully featured HTTP client for Python 3, which provides sync and async APIs, and support for both HTTP/1.1 and HTTP/2.
I install it on my Fedora 31 distro with the pip3 tool.
[mythcat@desk ~]$ pip3 install httpx --user
...
Successfully installed h11-0.9.0 h2-3.2.0 hpack-3.0.0 hstspreload-2020.2.15 httpx-0.11.1 
hyperframe-5.2.0 rfc3986-1.3.2 sniffio-1.1.0
With this python package, you can build a simple application with https API, migrate an application that uses web requests to make HTTP call.
use it as a test client for your web project, build a web spider and much more.
All HTTP methods get, post, patch, put, delete are implemented as coroutines in httpx python package and supports HTTP/2.
Let's start with few lines of source code:
[mythcat@desk ~]$ python3 
Python 3.7.6 (default, Jan 30 2020, 09:44:41) 
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import httpx
>>> out = httpx.get('https://www.google.com')
>>> out.status_code
200
>>> out.headers['content-type']
'text/html; charset=ISO-8859-1'
>>> out.text[:76]
'<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang='
>>> out.http_version
'HTTP/1.1'
>>> with httpx.Client() as client:
...     out_client = client.get('https://www.google.com')
... 
>>> out_client.http_version
'HTTP/1.1'
You can use asynchronous call to bost your python application using httpx python package.
I will make a tutorial about asyncio in the future.
For example, the website named example.com can return json data and using the next source code I can get it using the asyncio package.
import httpx
import asyncio
from typing import Dict
async def get_web() -> Dict:
    resp = await httpx.get("https://example.com/")
    if resp.status_code == httpx.codes.OK:
        return resp.json()
if __name__ == '__main__':   
    comments = asyncio.run(get_web())
Use async and await when you have to execute HTTP calls with httpx because is fully Requests compatible async HTTP Client.
The HTTPX comes with a lot of features, see the official GitHub webpage.

Saturday, February 15, 2020

Python 3.7.5 : Use Brython in web development to avoid javascript.

The tutorial for today is about how can avoid the javascript and use python script in webdevelopment using the Brython.
Brython's goal is to replace Javascript with Python, as the scripting language for web browsers. see the official webpage.
It is necessary to include brython.js and to run the brython() function upon page load using the onload attribute of the BODY tag.
You can use python language in the HTML file or you can write it in a separate file, and to load it using the src attribute of the script tag:
<html>
<head>
<script src="/brython.js"></script>
</head>
<body onload="brython()">
<script type="text/python" src="test.py"></script>
<input id="zone" autocomplete="off">
<button id="mybutton">click!</button>
</body>
</html>
Let's see one simple example with one edit and button bind
<html>
<head>
<script src="/brython.js"></script>
</head>
<body onload="brython()">
<script type="text/python">
from browser import document, alert
def echo(ev):
 alert(document["zone"].value)
document["mybutton"].bind("click", echo)
</script>
<input id="zone">
<button id="mybutton">click !</button>
</body>
</html>
When I click on the button, the onclick event calls and run the echo() function and gets the value of the INPUT element, through its id named zone and show the message.
Is fast and works great with javascripts libraries, see the example with THREE demo.
from browser import document, window

THREE = window.THREE

camera = THREE.PerspectiveCamera.new(75, 1, 1, 10000)
camera.position.z = 1000
scene = THREE.Scene.new()
geometry = THREE.CubeGeometry.new(200, 200, 200)
material = THREE.MeshBasicMaterial.new({"color": "#ff0000", "wireframe": True})
mesh = THREE.Mesh.new(geometry, material)
scene.add(mesh)

renderer = THREE.WebGLRenderer.new()
renderer.setSize(444, 444)

document <= renderer.domElement
renderer.render(scene, camera)

def animate(i):
    # note: three.js includes requestAnimationFrame shim
    window.requestAnimationFrame(animate)

    mesh.rotation.x += 0.01
    mesh.rotation.y += 0.02

    renderer.render(scene, camera)   

animate(0)

Tuesday, February 11, 2020

Python 3.7.5 : Using the hug framework - part 001.

Today I will come with another tutorial series about the hug framework.
The hug framework is on the top 3 performing web frameworks for Python and comes with the cleanest way to create HTTP REST APIs on Python 3.
The official webpage can be found hug web page with a good area for learn.
Let's install this python package.
[mythcat@desk projects]$ mkdir hug_001
[mythcat@desk projects]$ cd hug_001/
[mythcat@desk hug_001]$ pip3 install hug --user
...
Successfully installed hug-2.6.1
The Hug is a framework that allows you to expose a single code in several ways:
  • a local package;
  • as an A.P.I.;
  • as a C.L.I.;
Let's create an app.py python script to see all of these options:
import hug

# local pkg 
@hug.local()
def get_products(product:hug.types.text):
        """Get product name"""
        return {"product":product.upper()}

# API
@hug.get()

# CLI
@hug.cli()
To test it I used this source code:
import hug

# local pkg 
@hug.get()
@hug.local()
def get_products(product:hug.types.text):
        """Get product name"""
        return {"product":product.upper()}
The rerver can be run with this command:
[mythcat@desk hug_001]$ hug -f app.py

/#######################################################################\
          `.----``..-------..``.----.
         :/:::::--:---------:--::::://.
        .+::::----##/-/oo+:-##----:::://
        `//::-------/oosoo-------::://.       ##    ##  ##    ##    #####
          .-:------./++o/o-.------::-`   ```  ##    ##  ##    ##  ##
             `----.-./+o+:..----.     `.:///. ########  ##    ## ##
   ```        `----.-::::::------  `.-:::://. ##    ##  ##    ## ##   ####
  ://::--.``` -:``...-----...` `:--::::::-.`  ##    ##  ##   ##   ##    ##
  :/:::::::::-:-     `````      .:::::-.`     ##    ##    ####     ######
   ``.--:::::::.                .:::.`
         ``..::.                .::         EMBRACE THE APIs OF THE FUTURE
             ::-                .:-
             -::`               ::-                   VERSION 2.6.1
             `::-              -::`
              -::-`           -::-
\########################################################################/

 Copyright (C) 2016 Timothy Edmund Crosley
 Under the MIT License


Serving on :8000...
OPen the browser with the http://localhost:8000/ or http://localhost:8000/products:
If you want to use the CLI then you need to make these changes in the source code:
import hug
# cli 
@hug.cli()
# local pkg 
@hug.get('/products')
@hug.local()
def get_products(product:hug.types.text):
        """Get product name"""
        return {"product":product.upper()}
# the main CLI
if __name__ == '__main__':
        get_products.interface.cli() 
I can see the help area from python:
[mythcat@desk hug_001]$ hug -f app.py -c help
app

Available Commands:

 - get_products: Get product name 
The hug help show the all arguments for use:
[mythcat@desk hug_001]$ hug --help
usage: hug [-h] [-v] [-f FILE] [-m MODULE] [-ho HOST] [-p PORT] [-n] [-ma]
           [-i INTERVAL] [-c COMMAND] [-s]

Hug API Development Server

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit
  -f FILE, --file FILE  file
  -m MODULE, --module MODULE
                        module
  -ho HOST, --host HOST
                        host
  -p PORT, --port PORT  A whole number
  -n, --no_404_documentation
                        Providing any value will set this to true
  -ma, --manual_reload  Providing any value will set this to true
  -i INTERVAL, --interval INTERVAL
                        A whole number
  -c COMMAND, --command COMMAND
                        command
  -s, --silent          Providing any value will set this to true 

Wednesday, January 22, 2020

Python 3.7.5 : Django security issues - part 003.

Let's update this subject today with another new tutorial.
In the last tutorial about Django security I wrote about python package named django-axes.
First, let's fix an old issue about a URL pattern that matches anything and expects an integer that generates errors like:
...
  File "/home/mythcat/.local/lib/python3.7/site-packages/django/db/models/fields/__init__.py", line 1772, 
in get_prep_value
    ) from e
ValueError: Field 'id' expected a number but got 'favicon.ico'.
[22/Jan/2020 21:50:06] "GET /favicon.ico/ HTTP/1.1" 500 130547
Now, let's start my project:
[mythcat@desk ~]$ cd projects/
[mythcat@desk projects]$ cd django/
[mythcat@desk django]$ source env/bin/activate
Create a new folder named static in the test001 folder and add a icon file named favicon.ico.
(env) [mythcat@desk django]$ cd mysite/test001/
(env) [mythcat@desk test001]$ mkdir static 
In the settings.py file you need to have this source code:

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]
Change in the urls.py this line of source code to fix the error:
path('<int:author_id>/',views.index_next, name = 'index_next'),
Let's run the Django project server with:
(env) [mythcat@desk django]$ cd mysite/
(env) [mythcat@desk mysite]$ python3 manage.py runserver
I login into my admin area with user catalin and password adminadmin.
If you try to login with a bad password then the account is locked by django-axes python package.
Use this command to reset all lockouts and access records.
(env) [mythcat@desk mysite]$ python3 manage.py axes_reset
No attempts found.
Into admin area you can see the AXES area with Access attempts and Access logs.
Axes listens to the following signals from django.contrib.auth.signals to log access attempts.
In this case Axes lockout responses on failed user authentication attempts from login views.
The Access logs shows access log, see examples:
Jan. 22, 2020, 8:46 p.m.-127.0.0.1catalinMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36/admin/login/
Jan. 21, 2020, 6:42 p.m.Jan. 22, 2020, 8:45 p.m.127.0.0.1catalinMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36/admin/login/
You can set the axes into settings.py file , see this link.


Tuesday, January 21, 2020

Python 3.7.5 : Use Django Formsets.

Django Formsets manage the complexity of multiple copies of a form in a view.
This simplifies the task of creating a formset for a form that handles multiple instances of a model.
Let's start with my old project:
[mythcat@desk ~]$ cd projects/
[mythcat@desk projects]$ cd django/
[mythcat@desk django]$ source env/bin/activate
Into models.py I add these classes:
#create Inline Form with book and author
class Author(models.Model):
    author_book = models.CharField(max_length = 100)
    def __str__(self):
        return self.author_book

class Book(models.Model):
    book_name = models.CharField(max_length = 100)
    author_book_name = models.ForeignKey(Author,on_delete=models.CASCADE)
    def __str__(self):
        return self.book_name

(env) [mythcat@desk mysite]$ python3 manage.py makemigrations
Migrations for 'test001':
  test001/migrations/0004_author_book.py
    - Create model Author
    - Create model Book
(env) [mythcat@desk mysite]$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, axes, contenttypes, sessions, test001
Running migrations:
  Applying test001.0004_author_book... OK
Add the classes to admin.py:
from .models import Author, Book
...
admin.site.register(Author)
admin.site.register(Book)
Now you can log in into the admin area and add authors and then add books.

Add the source code to views.py:
...
# add to views.py Author and Book 
from .models import Author, Book
# Author , Book redirect 
from django.shortcuts import redirect
...
# author and book source code 
def index_next(request, author_id):
    author = Author.objects.get(pk=author_id)
    BookFormset = inlineformset_factory(Author,Book, fields=('book_name',))
    if request.method == 'POST':
        formset = BookFormset(request.POST,instance = author)
        if formset.is_valid():
            formset.save()
            return redirect('index_next',author_id = author_id)
    formset = BookFormset(instance = author)
    return render(request, 'index_next.html', {'formset': formset})
...
Let's fix the URL for the next step.
Add the source code to urls.py:
...
# add index_next to urls.py 
from test001.views import index_next
...
urlpatterns = [
    ...
    path('&lt author_id &gt',views.index_next, name = 'index_next'),
    ...
    ]
Add index_next.html file into the template folder and into this file write HTML5 with a form and one submit button.
In the form tag add this:
{{ formset.as_p }}
Run the runserver command:
(env) [mythcat@desk mysite]$ python3 manage.py runserver
Use this http://127.0.0.1:8000/1 to see the first on the database shown on the browser.
You can customize the output of inline form, see source code:
...
BookFormset = inlineformset_factory(Author,Book, fields=('book_name',), can_delete=False, extra=1)
...
See the full project on my GitHub account at django_chart project repo.