On this page:

Target audience:

Users of the extension providing Python support.


Summary: This document provides basic information about the extension providing Python support.


What's new

1.2.0 functional release

  • Support for IBM Message Queues
  • Bug correction on quality rules detecting web service calls inside loops

What's new?

Please see Python 1.2 - Release Notes for more information.

Description

This extension provides support for Python.

In what situation should you install this extension?

If your application contains Python source code and you want to view these object types and their links with other objects, then you should install this extension.

Supported Python versions

The following table displays the supported versions matrix:

VersionSupport
3.x(tick)
2.x(tick)
1.x(error)

Function Point, Quality and Sizing support

This extension provides the following support:

Function Points
(transactions)
Quality and SizingSecurity
(tick)(tick)(tick)

CAST AIP compatibility

This extension is compatible with:

CAST AIP release
Supported
8.3.x(tick)
8.2.x(tick)
8.1.x(tick)
8.0.x(tick)
7.3.4 and all higher 7.3.x releases(tick)

Supported DBMS servers

This extension is compatible with the following DBMS servers:

CAST AIP releaseCSSOracleMicrosoft
All supported releases(tick)(tick)(error)

Prerequisites

(tick)An installation of any compatible release of CAST AIP (see table above)

Dependencies with other extensions

Note that when using the CAST Extension Downloader to download the extension and the Manage Extensions interface in CAST Server Manager to install the extension, any dependent extensions are automatically downloaded and installed for you. You do not need to do anything.

Download and installation instructions

Please see:

The latest release status of this extension can be seen when downloading it from the CAST Extend server.

Packaging, delivering and analyzing your source code

Once the extension is installed, no further configuration changes are required before you can package your source code and run an analysis. The process of packaging, delivering and analyzing your source code is as follows:

Packaging and delivery

Note that the Python extension does not contain any CAST Delivery Manager Tool discoverers or extractors, therefore, no "Python" projects will be detected by the CAST Delivery Manager Tool (DMT). You therefore need to manually create an Analysis Unit in the CAST Management Studio - this is explained below.

Using the CAST Delivery Manager Tool:

Click to enlarge:

Click to enlarge:

Click to enlarge:

Analyzing

Using the CAST Management Studio:

Click to enlarge:

Automatic skipping of unit-test code

The analyzer skips files that are recognized as forming part of testing code, i.e., in principle, code not pertaining to production code. The reason to avoid inclusion of testing code is that many Quality Rule violations are overrepresented in test code, either because code tends to be of poorer quality (certainly not critical) or prevalence of particular testing patterns. Accounting for test code would negatively impact the total score of the project. The heuristics used by the analyzer are based on detecting unit-test library imports, and file and path naming conventions as summarized in the table below: 

TypeValueHeaderLinesMinimumCount
FilePath**/test_*.py  
FilePath**/*_test.py  
FilePath**/*_test_*.py  
FilePath**/test/*.py  
FilePath**/tests/*.py  
FileContentimport unittest12 
FileContentfrom unittest import12 
FileContentfrom nose.tools import12 
FileContentself.assert 2


The ** symbol represents any arbitrary path string, whereas * represents any string without directory slashes.

What results can you expect?

Once the analysis/snapshot generation has completed, you can view the results in the normal manner:

Python Class and method example

iOS Front-end connected to a Python Flask Back-end.

Objects

The following specific objects are displayed in CAST Enlighten:

IconDescription

Python Project, Python External Library
Python Module
Python Class
Python Method
Python Script

Python Get Urllib, Urllib2, Httplib, Httplib2, aiohttp Service

Python Flask, aiohttp Web Service Get Operation

Python Post Urllib, Urllib2, Httplib, Httplib2, aiohttp Service

Python Flask, aiohttp Web Service Post Operation

Python Put Urllib, Httplib, Httplib2, aiohttp Service

Python Flask, aiohttp Web Service Put Operation

Python Delete Urllib, Httplib, Httplib2, aiohttp Service

Python Flask, aiohttp Web Service Delete Operation

SQL Named Query

RabbitMQ Python QueueCall

ActiveMQ Python QueueCall

IBM MQ Python QueueCall

RabbitMQ Python QueueReceive

ActiveMQ Python QueueReceive

IBM MQ Python QueueReceive

Links

The following links are constructed :

Structural Rules

The following structural rules are provided:

1.2.0-funcrelhttps://technologies.castsoftware.com/rules?sec=srs_python&ref=||1.2.0-funcrel

You can also find a global list here:

https://technologies.castsoftware.com/rules?sec=t_1021000&ref=||

Web Service calls and operations support

The following libraries are supported for Web Service operations (left) and Web Service HTTP API calls (right):

Once the Python extension analysis is finished, the analyzer will output the final number of web service call and operation objects created.

requests

Example for GET request:

import requests
r = requests.get('https://api.github.com/events')

urllib

Example for GET request:

import urllib.request
with urllib.request.urlopen('http://python.org/') as response:
   html = response.read()

urllib2

Example for GET request:

import urllib2

req = urllib2.Request('http://python.org/')
response = urllib2.urlopen(req)
the_page = response.read()

Example for POST request.

import urllib2
import urllib

values = {'name' : 'Michael Foord',
          'location' : 'Northampton',
          'language' : 'Python' }

data = urllib.urlencode(values)

req = urllib2.Request('http://python.org/', data)
response = urllib2.urlopen(req)
the_page = response.read()


PUT and DELETE calls are not supported by the urllib2 module (Python version 2.x) by default. Workarounds to bypass this limitation are not detected by the analyzer.

httplib

Example for GET request:

from httplib import HTTPConnection
def f():
    conn = HTTPConnection("www.python.org")
    conn.request("GET", "/index.html")

Example link from method "f" to the get httplib service:

http.client

Example for GET request:

from http.client import HTTPConnection
def f():
    conn = HTTPConnection("www.python.org")
    conn.request("GET", "/index.html")

In this case a Python Get Httplib Service will be generated (the httplib module from Python 2 has been renamed to http.client in Python 3).

httplib2

The following code will issue a http get to the url 'https://api.github.com/events':

import httplib2
h = httplib2.Http(".cache")
(resp, content) = h.request("https://api.github.com/events")

aiohttp

The following code will issue a http get to the url 'https://api.github.com/events':

import aiohttp
session = aiohttp.ClientSession()
res = session.get('https://api.github.com/events'

The aiohttp module can be also used in server mode, implementing web service operations

from aiohttp import web
async def handler(request):
    return web.Response(text="Welcome in Python")
app = web.Application()
app.router.add_get('/index', handler)
web.run_app(app)

In this case a Web Service Operation object associated to the function (coroutine) handler will be generated similar to the example for flask given below.

flask

Flask route annotations for web service operations (GET, PUT, POST, DELETE) are supported. In particular, any decorator with the format @prefix.route is considered as a flask annotation where prefix can be a Flask application object or blueprint object. In the following example, a default GET operation is ascribed to the function f, and the POST and PUT operations to the upload_file function:

from flask import Flask
app = Flask(__name__)
 
@app.route('/')
def f():
    return 'hello world!'
 
@app.route('/upload', methods=['POST', 'PUT'])
def upload_file()
	if request.method == 'POST':
            pass
	# ...

The link between the GET operation named after the routing URL "/"  and the called function f is represented by an arrow pointing to the function:

The name of a saved Web Service Operation object will be generated from the routing URL by adding a final slash when not present. In this example the name of the PUT and POST operations is "/upload/" after the routing url "/upload".

URL query parameters such as @app.route('/user/<username>') are supported. In this case the generated Web Service Operation object will be named as /user/{}/, as shown in the example below.

from flask import Flask
app = Flask(__name__)
 
@app.route('/user/<username>')
def show_user_profile(username):
    return 'User %s' % username


Similarly double slashes // in flask routing URLs are transformed into /{}/. Additional backslashes inside URL query parameters of type path [ @app.route('/<path:path>') ] are not resolved (which in principle could catch any URL) so the web service will be named as a regular parameter /{}/.

The equivalent alternative to routing annotations using the Flask add_url_rule is also supported.

from flask import Flask
app = Flask(__name__)    
 
def index():
    pass
    
app.add_url_rule('/', 'index')
  

Database queries

Simple database queries consistent with the Python Database API Specification (PEP 249) are recognized. This allows to support a large number of important libraries interfacing Python and SQL databases (SQLite, MySQL, etc). The analyzer identifies execute method calls as potential database queries and searches for generic SQL statements passed in as an argument ('SELECT ...", "INSERT ...)". In the example below data from the stocks table is retrieved via a SELECT statement passed explicitly by a string to the execute method of a cursor object.

# select.py
import sqlite3

conn = sqlite3.connect('example.db')
c = conn.cursor()
c.execute('SELECT * FROM stocks') 

The analyzer creates a SQL Named Query object with name SELECT * FROM stocks (first 4 words are only used as naming convention) representing a call to a database. Provided analysis dependencies between SQL and Python are configured in CAST Management Studio, the analyzer will automatically link this object to the corresponding Table object, in this case stocks, that has been generated by a SQL analysis unit.

File system access functions

Representing end points based on file system access is important to automatically configure transactions. Towards this goal we aim at providing automatic recognition of standard library input/output functions. Currently we provide support for the built-in open function and the most common methods associated to file-like objects write, read, writelines, readline, readlines, and close,  as shown in the example below.

# file1.py
 
data = """<html>
<header><title>This is title</title></header>
<body>
Hello world
</body>
</html>
"""
 
f = open('page.html', 'w')
f.write(data)
f.close()

The objects corresponding to the code of the file1.py file are inside the Universal Directory root object. Additionally the analyzer will automatically generate a Python external library object representing the Python Standard Library. Within this, the Python built-in library is abstracted as a Python source code object named builtins.py, with its corresponding open function and file class (abstracting general file-like objects) that contains the above mentioned methods. No differences are considered between Python2 and Python3 built-in functions. Notice the external character of these objects denoted by gray-shaded icons in the left Object Browser panel.

Due to implementation constraints in CAIP versions [7.3.6, 8.1] a spurious link is generated between the Python external library object and a PY File object.

Message Queues support

Introduction

Message queues are software-engineering components used for inter-process communication, or for inter-thread communication within the same process. They use a queue for messaging. A producer posts messages to a queue. At the appointed time, the receivers are started up and process the messages in the queue. A queued message can be stored and forwarded, and the message can be redelivered until the message is processed. Message queues enable asynchronous processing, which allows messages to be queued without the need to process them immediately.

Message Queues currently handled by the Python analyzer

ActiveMQ

Apache ActiveMQ is an open source message broker written in Java together with a full Java Message Service (JMS) client. The goal of ActiveMQ is to provide standards-based, message-oriented application integration across as many languages and platforms as possible. ActiveMQ acts as the middleman allowing heterogeneous integration and interaction in an asynchronous manner.

IBM MQ

IBM MQ is a family of network message-oriented middle ware products that IBM launched. It was originally called MQSeries (for "Message Queue"), and was renamed WebSphere MQ to join the suite of WebSphere products. IBM MQ allows independent and potentially non-concurrent applications on a distributed system to securely communicate with each other. IBM MQ is available on a large number of platforms (both IBM and non-IBM), including z/OS (mainframe), OS/400 (IBM System i or AS/400), Transaction Processing FacilityUNIXLinuxand Microsoft Windows.

RabbitMQ

RabbitMQ is an open source message-queueing software called a message broker or queue manager RabbitMQ implements AMQP. It supports multiple messaging protocols. RabbitMQ can be deployed in distributed and federated configurations to meet high-scale, high-availability requirements.

Message queue applications using the below mentioned frameworks/clients are handled:

CAST Enlighten screenshots

When a message queue application is analyzed by the Python analyser, the following transactions can be found at the end of analysis:

Example of ActiveMQ Producer

import stomp

conn = stomp.Connection10()
conn.start()
conn.connect()
conn.send('SampleQueue', 'Its working!!')
conn.disconnect()

Example of ActiveMQ Consumer

import stomp

queue = 'SampleQueue'
conn = stomp.Connection10()
conn.start()
conn.connect()
conn.subscribe(queue)
conn.disconnect()

CAST Enlighten screenshot of ActiveMQ Transaction

Example of RabbitMQ Producer

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
 
channel.queue_declare(queue = "sample_queue")
channel.basic_publish(exchange = '', routing_key = "sample_queue", body = "Hello world!" )
connection.close()

Example of RabbitMQ Consumer

import pika

def callback(ch, method, properties, body):
    print("[x] Received % r" % body)
 
connectionconnection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.queue_declare(queue = "sample_queue")
channel.basic_consume(callback, queue = "sample_queue", no_ack = True)
channel.start_consuming()

CAST Enlighten screenshot of RabbitMQ Transaction

 

Example of IBM MQ Producer

import pymqi

def send_message(self):
    queue_manager = "QM01"
    channel = "SVRCONN.1"
    host = "192.168.1.135"
    port = "1434"
    queue_name = "TEST.QUEUE1"
    message = "Hello from Python!"

    qmgr = pymqi.connect(queue_manager, channel, conn_info)
    queue = pymqi.Queue(qmgr, queue_name)
    queue.put(message)
    queue.close()
    qmgr.disconnect()

Example of IBM MQ Consumer

import pymqi

def on_message(self,headers, msg):
    queue_manager = "QM01"
    channel = "SVRCONN.1"
    host = "192.168.1.135"
    port = "1434"
    queue_name = "TEST.QUEUE1"

    qmgr = pymqi.connect(queue_manager, channel, conn_info)
    queue = pymqi.Queue(qmgr, queue_name)
    message = queue.get()
    queue.close()
    qmgr.disconnect()

CAST Enlighten screenshot of IBM MQ Transaction

Limitations