Annie  Emard

Annie Emard

1652061420

CallGraph: Generate Static Call Graphs for Multiple Languages

Generate static call graphs for multiple languages

A call graph shows how functions call each other within a program.
Each oval represents a function, and each arrow indicates a function call.
In the diagram below, the main program is represented by node MAIN. It calls 6 functions, one of which calls 9 other functions.

'callGraph' parses source code for function definitions and calls, generates a call graph image, and displays it on screen.
Supported languages are: awk, bash, basic, dart, fortran, go, lua, javascript, julia, kotlin, matlab, perl, pascal, php, python, R, raku, ruby, rust, scala, swift, and tcl.

c/c++/java are not supported, since their complex and varied syntax requires heavy machinery.
 

"Sample output"

Usage:
    callGraph  <files>  <options>

    If your script calls helper modules, and you want the call graph to display the modules' functions,
        list the modules explicitly on the command line:
    callGraph script.pl path/moduleA.pm path/moduleB.pm
    
Options:
    -language <lang>           By default, filename extensions are parsed for .pl .pm .tcl .py, etc.
                               If those are not found, the first line of the script (#! shebang) is inspected.
                               If neither of those give clues, use this option to specify 'pl', 'tcl', 'py', etc
                               This option is required if a directory is scanned

    -start <function>          Specify function(s) as starting point instead of the main code.
                               These are displayed in green.
                               This is useful when parsing a large script, as the generated graph can be huge.
                               In addition, the calls leading to this function are charted.
                               Functions which are not reachable from one of the starting points
                                 are not charted.
                               -start __MAIN__  can be very useful when multiple source files
                                 are specified on the command line
                              The filename can be included as well:
                                                -start <file>:<function>

    -ignore <regex>            Specify function(s) to ignore.
                               This is useful when pruning the output of a large graph.
                               In particular, use it to remove logging or other helper functions which are
                                 called by many functions, and only clutter up the graph.
                               To ignore multiple functions, use this regex format:
                                   -ignore '(abc|xyz)'

    -output <filename>         Specify an output filename
                               By default, the .png file is named according to the first filename.
                               If a filename ending in .dot is given,
                                 only the intermediate .dot file is created.
                               If a filename ending in .svg is given, svg format is used
                               If a filename ending in .pdf is given, pdf format is used

    -noShow                    By default, the .png file is displayed.  This option prevents that behavior.

    -fullPath                  By default, the script strips off the path name of the input file(s).
                               This option prevents that behavior.

    -writeSubsetCode <file>    Create an output source code file which includes only the functions
                                 included in the graph.
                               This can be useful when trying to comprehend a large legacy code.

    -ymlOut <file>             Create an output YAML file which describes the following for each function:
                                   * which functions call it
                                   * which functions it calls
                               This can be useful to create your own automation or custom formatting
                               
    -ymlIn <file>              Use your intermediate file instead of parsing source files

    -verbose                   Provides 2 additional functionalities:
                               
                               1) Displays the external scripts referenced within each function

                               2) For Perl/TCL, attempts to list the global variables
                                    used in each function call in the graph.
                                  Global variables are arguably not the best design paradigm,
                                    but they are found extensively in real-world legacy scripts.

                                  Perl:
                                      'my' variables will affect this determination (use strict).
                                      Does not distinguish between $var, @var and %var.

                                  TCL:
                                      Variables declared as 'global' but not used, are marked with a '*'


Usage examples:
    callGraph  example.pl example_helper_lib.pm
    callGraph  example.py
    callGraph  <directory> -language 'go'

Algorithm:
    callGraph uses a simple line-by-line algorithm, using regexes to find function definitions and calls.
    Function definitions can be detected easily, since they start with identifiers such as:
        'sub', 'def', 'proc', 'function', 'func', 'fun', or 'fn'
    Function definitions end with '}' or 'end' at the same nesting level as the definition.
    Function calls are a bit more tricky, since built-in function calls look exactly like user function calls.
        To solve this, the algorithm first assumes that anything matching 'word(...)' is a function call,
        and then discards any calls which do not have corresponding definitions.
    For example, Perl:
        sub funcA {
            ...
            if ($x) {
                print($y);
                funcB($y);
            }
            ...
        }
        sub funcB {
            ...
        }
    Since this is not a true parser, the formatting must be consistent so that nesting can be determined.
    If your Perl script does not follow this rule, consider running it through 'perltidy' first.
    Also, don't expect miracles such as parsing dynamic function calls.
    Caveats aside, it seems to work well on garden-variety scripts spanning tens of thousands of lines,
        and has helped me unravel large pieces of legacy code to implement urgent bug fixes.
    
Acknowlegements:
    This code borrows core functionality from https://github.com/cobber/perl_call_graph

Requirements:
    GraphViz and the Perl GraphViz library must be installed:
        sudo apt install graphviz
        sudo apt install make
        sudo cpan install GraphViz

Author: koknat
Source Code: https://github.com/koknat/callGraph
License: GPL-3.0 License

#graphs 

What is GEEK

Buddha Community

CallGraph: Generate Static Call Graphs for Multiple Languages

Variables Globales De Python: Cómo Definir Un Ejemplo De Variable Glob

En este artículo, aprenderá los conceptos básicos de las variables globales.

Para empezar, aprenderá cómo declarar variables en Python y qué significa realmente el término 'ámbito de variable'.

Luego, aprenderá las diferencias entre variables locales y globales y comprenderá cómo definir variables globales y cómo usar la globalpalabra clave.

¿Qué son las variables en Python y cómo se crean? Una introducción para principiantes

Puede pensar en las variables como contenedores de almacenamiento .

Son contenedores de almacenamiento para almacenar datos, información y valores que le gustaría guardar en la memoria de la computadora. Luego puede hacer referencia a ellos o incluso manipularlos en algún momento a lo largo de la vida del programa.

Una variable tiene un nombre simbólico y puede pensar en ese nombre como la etiqueta en el contenedor de almacenamiento que actúa como su identificador.

El nombre de la variable será una referencia y un puntero a los datos almacenados en su interior. Por lo tanto, no es necesario recordar los detalles de sus datos e información; solo necesita hacer referencia al nombre de la variable que contiene esos datos e información.

Al dar un nombre a una variable, asegúrese de que sea descriptivo de los datos que contiene. Los nombres de las variables deben ser claros y fácilmente comprensibles tanto para usted en el futuro como para los otros desarrolladores con los que puede estar trabajando.

Ahora, veamos cómo crear una variable en Python.

Al declarar variables en Python, no necesita especificar su tipo de datos.

Por ejemplo, en el lenguaje de programación C, debe mencionar explícitamente el tipo de datos que contendrá la variable.

Entonces, si quisiera almacenar su edad, que es un número entero, o inttipo, esto es lo que tendría que hacer en C:

#include <stdio.h>
 
int main(void)
{
  int age = 28;
  // 'int' is the data type
  // 'age' is the name 
  // 'age' is capable of holding integer values
  // positive/negative whole numbers or 0
  // '=' is the assignment operator
  // '28' is the value
}

Sin embargo, así es como escribirías lo anterior en Python:

age = 28

#'age' is the variable name, or identifier
# '=' is the assignment operator
#'28' is the value assigned to the variable, so '28' is the value of 'age'

El nombre de la variable siempre está en el lado izquierdo y el valor que desea asignar va en el lado derecho después del operador de asignación.

Tenga en cuenta que puede cambiar los valores de las variables a lo largo de la vida de un programa:

my_age = 28

print(f"My age in 2022 is {my_age}.")

my_age = 29

print(f"My age in 2023 will be {my_age}.")

#output

#My age in 2022 is 28.
#My age in 2023 will be 29.

Mantienes el mismo nombre de variable my_age, pero solo cambias el valor de 28a 29.

¿Qué significa el alcance variable en Python?

El alcance de la variable se refiere a las partes y los límites de un programa de Python donde una variable está disponible, accesible y visible.

Hay cuatro tipos de alcance para las variables de Python, que también se conocen como la regla LEGB :

  • local ,
  • Encerrando ,
  • globales ,
  • Incorporado .

En el resto de este artículo, se centrará en aprender a crear variables con alcance global y comprenderá la diferencia entre los alcances de variables locales y globales.

Cómo crear variables con alcance local en Python

Las variables definidas dentro del cuerpo de una función tienen alcance local , lo que significa que solo se puede acceder a ellas dentro de esa función en particular. En otras palabras, son 'locales' para esa función.

Solo puede acceder a una variable local llamando a la función.

def learn_to_code():
    #create local variable
    coding_website = "freeCodeCamp"
    print(f"The best place to learn to code is with {coding_website}!")

#call function
learn_to_code()


#output

#The best place to learn to code is with freeCodeCamp!

Mire lo que sucede cuando trato de acceder a esa variable con un alcance local desde fuera del cuerpo de la función:

def learn_to_code():
    #create local variable
    coding_website = "freeCodeCamp"
    print(f"The best place to learn to code is with {coding_website}!")

#try to print local variable 'coding_website' from outside the function
print(coding_website)

#output

#NameError: name 'coding_website' is not defined

Plantea un NameErrorporque no es 'visible' en el resto del programa. Solo es 'visible' dentro de la función donde se definió.

Cómo crear variables con alcance global en Python

Cuando define una variable fuera de una función, como en la parte superior del archivo, tiene un alcance global y se conoce como variable global.

Se accede a una variable global desde cualquier parte del programa.

Puede usarlo dentro del cuerpo de una función, así como acceder desde fuera de una función:

#create a global variable
coding_website = "freeCodeCamp"

def learn_to_code():
    #access the variable 'coding_website' inside the function
    print(f"The best place to learn to code is with {coding_website}!")

#call the function
learn_to_code()

#access the variable 'coding_website' from outside the function
print(coding_website)

#output

#The best place to learn to code is with freeCodeCamp!
#freeCodeCamp

¿Qué sucede cuando hay una variable global y local, y ambas tienen el mismo nombre?

#global variable
city = "Athens"

def travel_plans():
    #local variable with the same name as the global variable
    city = "London"
    print(f"I want to visit {city} next year!")

#call function - this will output the value of local variable
travel_plans()

#reference global variable - this will output the value of global variable
print(f"I want to visit {city} next year!")

#output

#I want to visit London next year!
#I want to visit Athens next year!

En el ejemplo anterior, tal vez no esperaba ese resultado específico.

Tal vez pensaste que el valor de citycambiaría cuando le asignara un valor diferente dentro de la función.

Tal vez esperabas que cuando hice referencia a la variable global con la línea print(f" I want to visit {city} next year!"), la salida sería en #I want to visit London next year!lugar de #I want to visit Athens next year!.

Sin embargo, cuando se llamó a la función, imprimió el valor de la variable local.

Luego, cuando hice referencia a la variable global fuera de la función, se imprimió el valor asignado a la variable global.

No interfirieron entre sí.

Dicho esto, usar el mismo nombre de variable para variables globales y locales no se considera una buena práctica. Asegúrese de que sus variables no tengan el mismo nombre, ya que puede obtener algunos resultados confusos cuando ejecute su programa.

Cómo usar la globalpalabra clave en Python

¿Qué sucede si tiene una variable global pero desea cambiar su valor dentro de una función?

Mira lo que sucede cuando trato de hacer eso:

#global variable
city = "Athens"

def travel_plans():
    #First, this is like when I tried to access the global variable defined outside the function. 
    # This works fine on its own, as you saw earlier on.
    print(f"I want to visit {city} next year!")

    #However, when I then try to re-assign a different value to the global variable 'city' from inside the function,
    #after trying to print it,
    #it will throw an error
    city = "London"
    print(f"I want to visit {city} next year!")

#call function
travel_plans()

#output

#UnboundLocalError: local variable 'city' referenced before assignment

Por defecto, Python piensa que quieres usar una variable local dentro de una función.

Entonces, cuando intento imprimir el valor de la variable por primera vez y luego reasignar un valor a la variable a la que intento acceder, Python se confunde.

La forma de cambiar el valor de una variable global dentro de una función es usando la globalpalabra clave:

#global variable
city = "Athens"

#print value of global variable
print(f"I want to visit {city} next year!")

def travel_plans():
    global city
    #print initial value of global variable
    print(f"I want to visit {city} next year!")
    #assign a different value to global variable from within function
    city = "London"
    #print new value
    print(f"I want to visit {city} next year!")

#call function
travel_plans()

#print value of global variable
print(f"I want to visit {city} next year!")

Utilice la globalpalabra clave antes de hacer referencia a ella en la función, ya que obtendrá el siguiente error: SyntaxError: name 'city' is used prior to global declaration.

Anteriormente, vio que no podía acceder a las variables creadas dentro de las funciones ya que tienen un alcance local.

La globalpalabra clave cambia la visibilidad de las variables declaradas dentro de las funciones.

def learn_to_code():
   global coding_website
   coding_website = "freeCodeCamp"
   print(f"The best place to learn to code is with {coding_website}!")

#call function
learn_to_code()

#access variable from within the function
print(coding_website)

#output

#The best place to learn to code is with freeCodeCamp!
#freeCodeCamp

Conclusión

¡Y ahí lo tienes! Ahora conoce los conceptos básicos de las variables globales en Python y puede distinguir las diferencias entre las variables locales y globales.

Espero que hayas encontrado útil este artículo.

Comenzará desde lo básico y aprenderá de una manera interactiva y amigable para principiantes. También construirá cinco proyectos al final para poner en práctica y ayudar a reforzar lo que ha aprendido.

¡Gracias por leer y feliz codificación!

Fuente: https://www.freecodecamp.org/news/python-global-variables-examples/

#python 

坂本  篤司

坂本 篤司

1652450700

Pythonグローバル変数–グローバル変数の例を定義する方法

この記事では、グローバル変数の基本を学びます。

まず、Pythonで変数を宣言する方法と、「変数スコープ」という用語が実際に何を意味するかを学習します。

次に、ローカル変数とグローバル変数の違いを学び、グローバル変数の定義方法とglobalキーワードの使用方法を理解します。

Pythonの変数とは何ですか?どのように作成しますか?初心者のための紹介

変数はストレージコンテナと考えることができます。

これらは、コンピュータのメモリに保存したいデータ、情報、および値を保持するためのストレージコンテナです。その後、プログラムの存続期間中のある時点でそれらを参照したり、操作したりすることもできます。

変数にはシンボリックがあり、その名前は、その識別子として機能するストレージコンテナのラベルと考えることができます。

変数名は、その中に格納されているデータへの参照とポインターになります。したがって、データと情報の詳細を覚えておく必要はありません。そのデータと情報を保持する変数名を参照するだけで済みます。

変数に名前を付けるときは、変数が保持するデータを説明していることを確認してください。変数名は、将来の自分自身と一緒に作業する可能性のある他の開発者の両方にとって、明確で簡単に理解できる必要があります。

それでは、Pythonで実際に変数を作成する方法を見てみましょう。

Pythonで変数を宣言するときは、データ型を指定する必要はありません。

たとえば、Cプログラミング言語では、変数が保持するデータの型を明示的に指定する必要があります。

したがって、整数またはint型である年齢を格納したい場合、これはCで行う必要があることです。

#include <stdio.h>
 
int main(void)
{
  int age = 28;
  // 'int' is the data type
  // 'age' is the name 
  // 'age' is capable of holding integer values
  // positive/negative whole numbers or 0
  // '=' is the assignment operator
  // '28' is the value
}

ただし、これはPythonで上記を記述する方法です。

age = 28

#'age' is the variable name, or identifier
# '=' is the assignment operator
#'28' is the value assigned to the variable, so '28' is the value of 'age'

変数名は常に左側にあり、代入する値は代入演算子の後に右側に配置されます。

プログラムの存続期間中、変数の値を変更できることに注意してください。

my_age = 28

print(f"My age in 2022 is {my_age}.")

my_age = 29

print(f"My age in 2023 will be {my_age}.")

#output

#My age in 2022 is 28.
#My age in 2023 will be 29.

同じ変数名を保持しますが、値をからにmy_age変更するだけです。2829

Pythonの可変スコープとはどういう意味ですか?

変数スコープとは、変数が利用可能で、アクセス可能で、表示可能なPythonプログラムの部分と境界を指します。

Python変数のスコープには4つのタイプがあり、 LEGBルールとも呼ばれます。

  • 局所
  • 囲み
  • グローバル
  • ビルトイン

この記事の残りの部分では、グローバルスコープを使用した変数の作成について学習することに焦点を当て、ローカル変数スコープとグローバル変数スコープの違いを理解します。

Pythonでローカルスコープを使用して変数を作成する方法

関数の本体内で定義された変数にはローカルスコープがあります。つまり、その特定の関数内でのみアクセスできます。言い換えれば、それらはその関数に対して「ローカル」です。

ローカル変数にアクセスするには、関数を呼び出す必要があります。

def learn_to_code():
    #create local variable
    coding_website = "freeCodeCamp"
    print(f"The best place to learn to code is with {coding_website}!")

#call function
learn_to_code()


#output

#The best place to learn to code is with freeCodeCamp!

関数の本体の外部からローカルスコープを使用してその変数にアクセスしようとするとどうなるかを見てください。

def learn_to_code():
    #create local variable
    coding_website = "freeCodeCamp"
    print(f"The best place to learn to code is with {coding_website}!")

#try to print local variable 'coding_website' from outside the function
print(coding_website)

#output

#NameError: name 'coding_website' is not defined

NameErrorプログラムの残りの部分では「表示」されないため、aが発生します。定義された関数内でのみ「表示」されます。

Pythonでグローバルスコープを使用して変数を作成する方法

ファイルの先頭など、関数の外部で変数を定義すると、その変数はグローバルスコープを持ち、グローバル変数と呼ばれます。

グローバル変数は、プログラムのどこからでもアクセスできます。

関数の本体内で使用することも、関数の外部からアクセスすることもできます。

#create a global variable
coding_website = "freeCodeCamp"

def learn_to_code():
    #access the variable 'coding_website' inside the function
    print(f"The best place to learn to code is with {coding_website}!")

#call the function
learn_to_code()

#access the variable 'coding_website' from outside the function
print(coding_website)

#output

#The best place to learn to code is with freeCodeCamp!
#freeCodeCamp

グローバル変数とローカル変数があり、両方が同じ名前の場合はどうなりますか?

#global variable
city = "Athens"

def travel_plans():
    #local variable with the same name as the global variable
    city = "London"
    print(f"I want to visit {city} next year!")

#call function - this will output the value of local variable
travel_plans()

#reference global variable - this will output the value of global variable
print(f"I want to visit {city} next year!")

#output

#I want to visit London next year!
#I want to visit Athens next year!

上記の例では、その特定の出力を期待していなかった可能性があります。

city関数内で別の値を割り当てたときに、の値が変わると思ったかもしれません。

たぶん、私が行でグローバル変数を参照したときprint(f" I want to visit {city} next year!")、出力は#I want to visit London next year!の代わりになると予想しました#I want to visit Athens next year!

ただし、関数が呼び出されると、ローカル変数の値が出力されます。

次に、関数の外部でグローバル変数を参照すると、グローバル変数に割り当てられた値が出力されました。

彼らはお互いに干渉しませんでした。

ただし、グローバル変数とローカル変数に同じ変数名を使用することは、ベストプラクティスとは見なされません。プログラムを実行すると混乱する結果が生じる可能性があるため、変数の名前が同じでないことを確認してください。

Pythonでキーワードを使用する方法global

グローバル変数があり、関数内でその値を変更したい場合はどうなりますか?

私がそれをしようとすると何が起こるか見てください:

#global variable
city = "Athens"

def travel_plans():
    #First, this is like when I tried to access the global variable defined outside the function. 
    # This works fine on its own, as you saw earlier on.
    print(f"I want to visit {city} next year!")

    #However, when I then try to re-assign a different value to the global variable 'city' from inside the function,
    #after trying to print it,
    #it will throw an error
    city = "London"
    print(f"I want to visit {city} next year!")

#call function
travel_plans()

#output

#UnboundLocalError: local variable 'city' referenced before assignment

デフォルトでは、Pythonは関数内でローカル変数を使用したいと考えています。

そのため、最初に変数の値を出力してから、アクセスしようとしている変数に値再割り当てしようとすると、Pythonが混乱します。

関数内のグローバル変数の値を変更する方法は、次のglobalキーワードを使用することです。

#global variable
city = "Athens"

#print value of global variable
print(f"I want to visit {city} next year!")

def travel_plans():
    global city
    #print initial value of global variable
    print(f"I want to visit {city} next year!")
    #assign a different value to global variable from within function
    city = "London"
    #print new value
    print(f"I want to visit {city} next year!")

#call function
travel_plans()

#print value of global variable
print(f"I want to visit {city} next year!")

global次のエラーが発生するため、関数でキーワードを参照する前にキーワードを使用してくださいSyntaxError: name 'city' is used prior to global declaration

以前、関数内で作成された変数はローカルスコープを持っているため、それらにアクセスできないことを確認しました。

globalキーワードは、関数内で宣言された変数の可視性を変更します。

def learn_to_code():
   global coding_website
   coding_website = "freeCodeCamp"
   print(f"The best place to learn to code is with {coding_website}!")

#call function
learn_to_code()

#access variable from within the function
print(coding_website)

#output

#The best place to learn to code is with freeCodeCamp!
#freeCodeCamp

結論

そして、あなたはそれを持っています!これで、Pythonのグローバル変数の基本を理解し、ローカル変数とグローバル変数の違いを理解できます。

この記事がお役に立てば幸いです。

基本から始めて、インタラクティブで初心者に優しい方法で学びます。また、最後に5つのプロジェクトを構築して実践し、学んだことを強化するのに役立てます。

読んでくれてありがとう、そして幸せなコーディング!

ソース:https ://www.freecodecamp.org/news/python-global-variables-examples/

#python 

Python Global Variables – How to Define a Global Variable Example

In this article, you will learn the basics of global variables.

To begin with, you will learn how to declare variables in Python and what the term 'variable scope' actually means.

Then, you will learn the differences between local and global variables and understand how to define global variables and how to use the global keyword.

What Are Variables in Python and How Do You Create Them? An Introduction for Beginners

You can think of variables as storage containers.

They are storage containers for holding data, information, and values that you would like to save in the computer's memory. You can then reference or even manipulate them at some point throughout the life of the program.

A variable has a symbolic name, and you can think of that name as the label on the storage container that acts as its identifier.

The variable name will be a reference and pointer to the data stored inside it. So, there is no need to remember the details of your data and information – you only need to reference the variable name that holds that data and information.

When giving a variable a name, make sure that it is descriptive of the data it holds. Variable names need to be clear and easily understandable both for your future self and the other developers you may be working with.

Now, let's see how to actually create a variable in Python.

When declaring variables in Python, you don't need to specify their data type.

For example, in the C programming language, you have to mention explicitly the type of data the variable will hold.

So, if you wanted to store your age which is an integer, or int type, this is what you would have to do in C:

#include <stdio.h>
 
int main(void)
{
  int age = 28;
  // 'int' is the data type
  // 'age' is the name 
  // 'age' is capable of holding integer values
  // positive/negative whole numbers or 0
  // '=' is the assignment operator
  // '28' is the value
}

However, this is how you would write the above in Python:

age = 28

#'age' is the variable name, or identifier
# '=' is the assignment operator
#'28' is the value assigned to the variable, so '28' is the value of 'age'

The variable name is always on the left-hand side, and the value you want to assign goes on the right-hand side after the assignment operator.

Keep in mind that you can change the values of variables throughout the life of a program:

my_age = 28

print(f"My age in 2022 is {my_age}.")

my_age = 29

print(f"My age in 2023 will be {my_age}.")

#output

#My age in 2022 is 28.
#My age in 2023 will be 29.

You keep the same variable name, my_age, but only change the value from 28 to 29.

What Does Variable Scope in Python Mean?

Variable scope refers to the parts and boundaries of a Python program where a variable is available, accessible, and visible.

There are four types of scope for Python variables, which are also known as the LEGB rule:

  • Local,
  • Enclosing,
  • Global,
  • Built-in.

For the rest of this article, you will focus on learning about creating variables with global scope, and you will understand the difference between the local and global variable scopes.

How to Create Variables With Local Scope in Python

Variables defined inside a function's body have local scope, which means they are accessible only within that particular function. In other words, they are 'local' to that function.

You can only access a local variable by calling the function.

def learn_to_code():
    #create local variable
    coding_website = "freeCodeCamp"
    print(f"The best place to learn to code is with {coding_website}!")

#call function
learn_to_code()


#output

#The best place to learn to code is with freeCodeCamp!

Look at what happens when I try to access that variable with a local scope from outside the function's body:

def learn_to_code():
    #create local variable
    coding_website = "freeCodeCamp"
    print(f"The best place to learn to code is with {coding_website}!")

#try to print local variable 'coding_website' from outside the function
print(coding_website)

#output

#NameError: name 'coding_website' is not defined

It raises a NameError because it is not 'visible' in the rest of the program. It is only 'visible' within the function where it was defined.

How to Create Variables With Global Scope in Python

When you define a variable outside a function, like at the top of the file, it has a global scope and it is known as a global variable.

A global variable is accessed from anywhere in the program.

You can use it inside a function's body, as well as access it from outside a function:

#create a global variable
coding_website = "freeCodeCamp"

def learn_to_code():
    #access the variable 'coding_website' inside the function
    print(f"The best place to learn to code is with {coding_website}!")

#call the function
learn_to_code()

#access the variable 'coding_website' from outside the function
print(coding_website)

#output

#The best place to learn to code is with freeCodeCamp!
#freeCodeCamp

What happens when there is a global and local variable, and they both have the same name?

#global variable
city = "Athens"

def travel_plans():
    #local variable with the same name as the global variable
    city = "London"
    print(f"I want to visit {city} next year!")

#call function - this will output the value of local variable
travel_plans()

#reference global variable - this will output the value of global variable
print(f"I want to visit {city} next year!")

#output

#I want to visit London next year!
#I want to visit Athens next year!

In the example above, maybe you were not expecting that specific output.

Maybe you thought that the value of city would change when I assigned it a different value inside the function.

Maybe you expected that when I referenced the global variable with the line print(f" I want to visit {city} next year!"), the output would be #I want to visit London next year! instead of #I want to visit Athens next year!.

However, when the function was called, it printed the value of the local variable.

Then, when I referenced the global variable outside the function, the value assigned to the global variable was printed.

They didn't interfere with one another.

That said, using the same variable name for global and local variables is not considered a best practice. Make sure that your variables don't have the same name, as you may get some confusing results when you run your program.

How to Use the global Keyword in Python

What if you have a global variable but want to change its value inside a function?

Look at what happens when I try to do that:

#global variable
city = "Athens"

def travel_plans():
    #First, this is like when I tried to access the global variable defined outside the function. 
    # This works fine on its own, as you saw earlier on.
    print(f"I want to visit {city} next year!")

    #However, when I then try to re-assign a different value to the global variable 'city' from inside the function,
    #after trying to print it,
    #it will throw an error
    city = "London"
    print(f"I want to visit {city} next year!")

#call function
travel_plans()

#output

#UnboundLocalError: local variable 'city' referenced before assignment

By default Python thinks you want to use a local variable inside a function.

So, when I first try to print the value of the variable and then re-assign a value to the variable I am trying to access, Python gets confused.

The way to change the value of a global variable inside a function is by using the global keyword:

#global variable
city = "Athens"

#print value of global variable
print(f"I want to visit {city} next year!")

def travel_plans():
    global city
    #print initial value of global variable
    print(f"I want to visit {city} next year!")
    #assign a different value to global variable from within function
    city = "London"
    #print new value
    print(f"I want to visit {city} next year!")

#call function
travel_plans()

#print value of global variable
print(f"I want to visit {city} next year!")

Use the global keyword before referencing it in the function, as you will get the following error: SyntaxError: name 'city' is used prior to global declaration.

Earlier, you saw that you couldn't access variables created inside functions since they have local scope.

The global keyword changes the visibility of variables declared inside functions.

def learn_to_code():
   global coding_website
   coding_website = "freeCodeCamp"
   print(f"The best place to learn to code is with {coding_website}!")

#call function
learn_to_code()

#access variable from within the function
print(coding_website)

#output

#The best place to learn to code is with freeCodeCamp!
#freeCodeCamp

Conclusion

And there you have it! You now know the basics of global variables in Python and can tell the differences between local and global variables.

I hope you found this article useful.

You'll start from the basics and learn in an interactive and beginner-friendly way. You'll also build five projects at the end to put into practice and help reinforce what you've learned.

Thanks for reading and happy coding!

Source: https://www.freecodecamp.org/news/python-global-variables-examples/

#python 

Hermann  Frami

Hermann Frami

1656080760

Serverless Plugin: AWS API Gateway integration Helper

Serverless Plugin: AWS Api Gateway integration helper

Overview

The plugin provides the functionality to merge OpenApiSpecification files (formerly known as swagger) with one or multiple YML files containing the the x-amazon-apigateway extensions. There are several use-cases to keep both information separated, e.g. it is needed to deploy different api gateway integrations depending on a stage environment.

When dealing with functional tests you do not want to test the production environment, but only a mocking response.

The plugin supports YML based OpenApi3 specification files only

Features

  • deploy stage dependent x-amazon-apigateway integrations
  • separate infrastructure (aws) from openapi specification
  • use mock integrations for functional testing
  • auto-generating CORS methods, headers and api gateway mocking response
  • hook into package & deploy lifeCycle and generate combined openApi files on the fly during deployment
  • auto-inject generated openApi file into the Body property of specified API Gateway
  • generate mocking responses without specifying x-amazon-apigateway-integration objects
  • generate request-validation blocks
  • generate all required x-amazon-apigateway-integration objects automatically
  • full proxy generation support with [NEW]: feature: PROXY Manager

See the examples folder for a full working example

Installation & Setup

Run npm install in your Serverless project.

$ npm install --save-dev serverless-openapi-integration-helper

Add the plugin to your serverless.yml file

plugins:
  - serverless-openapi-integration-helper

Plugin configuration

You can configure the plugin under the key openApiIntegration. See See Configuration Reference for a list of available options

The mapping array must be used to configure where the files containing the x-amazon-apigateway-integration blocks are located.

openApiIntegration:
    package: true #New feature! Hook into the package & deploy process
    inputFile: schema.yml
    mapping:
       - stage: [dev, prod] #multiple stages
         path: integrations
       - stage: test #single stage
         path: mocks

In the above example all YML files inside the integrations directory will be processed and merged with the schema.yml file when deploying the dev stage

serverless deploy --stage=dev

To use a different x-amazon-apigateway to perform functional tests (with mocking responses e.g) the directory mock is processed and merged with the schema.yml file when deploying the test stage

serverless deploy --stage=test

Usage

You can setup a fully working API GATEWAY with any openApi 3.0 specification file First create the input file containing the OpenApiSpecification

# ./schema.yml
openapi: 3.0.0
info:
  description: User Registration
  version: 1.0.0
  title: UserRegistration
paths:
  /api/v1/user:
    post:
      summary: adds a user
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Customer'
      responses:
        '201':
          description: user created
components:
  schemas:
    Customer:
      type: object
      required:
        - email_address
        - password
      properties:
        email_address:
          type: string
          example: test@example.com
        password:
          type: string
          format: password
          example: someStrongPassword#

The plugin will generate the x-amazon-apigateway integrations objects for all methods that do not have an integration.

#generate a file containing a gateway mock integration in the directory /mocks
serverless integration create --output mocks --type mock --stage=test

#generate a file containing the production integration in the directory integrations/
serverless integration create --output integrations --type http --stage=prod

Supported types are

  • http_proxy
  • http
  • aws
  • aws_proxy
  • mock

The plugin now generates a merged file during deployment that is automatically injected in your serverless resources

#Create OpenApi File containing mocking responses (usable in functional tests) and deploy to ApiGateway
serverless deploy --stage==test
#Create OpenApi File containing the production integration and deploy to ApiGateway
serverless deploy --stage=prod

The generated output is automatically injected in the resources.Resources.YOUR_API_GATEWAY.Properties.Body property

resources:
  Resources:
    ApiGatewayRestApi:
      Type: AWS::ApiGateway::RestApi
      Properties:
        ApiKeySourceType: HEADER
        Body: ~ #autogenerated by plugin
        Description: "Some Description"
        FailOnWarnings: false
        Name: ${opt:stage, self:provider.stage}-some-name
        EndpointConfiguration:
          Types:
            - REGIONAL
    ApiGatewayDeployment:
      Type: AWS::ApiGateway::Deployment
      Properties:
        RestApiId:
          Ref: ApiGatewayRestApi
        StageName: ${opt:stage, self:provider.stage}

Commands

Manual merge

The generate command can be used independently with

serverless integration merge --stage=dev

Of course then the API Gateway Body property has to be specified manually

resources:
  Resources:
    ApiGatewayRestApi:
      Type: AWS::ApiGateway::RestApi
      Properties:
        ApiKeySourceType: HEADER
        Body: ${file(openapi-integration/api.yml)}

CORS generator

The plugin can generate full CORS support out of the box.

openApiIntegration:
  cors: true
  ...

If enabled, the plugin generates all required OPTIONS methods as well as the required header informations and adds a mocking response to API Gateway. You can customize the CORS templates by placing your own files inside a directory openapi-integration (in your project root). The following files can be overwritten:

FilenameDescription
headers.ymlAll headers required for CORS support
integration.ymlContains the x-amazon-apigateway-integration block
path.ymlOpenApi specification for the OPTIONS method
response-parameters.ymlThe response Parameters of the x-amazon-apigateway-integration responses

See the EXAMPLES directory for detailed instructions.

Auto Mock Generator

If enabled, the plugin generates mocking responses for all methods that do not have an x-amazon-apigateway-integration block defined. It takes the first 2xx response defined in the openApi specification and generates a simple mocking response on the fly

openApiIntegration:
  autoMock: true
  ...

When using the autoMock feature, you do not need to specify inputPath mappings, since all endpoints are mocked automatically

openApiIntegration:
    package: true
    inputFile: schema.yml
    mapping: ~

VALIDATION generator

The plugin supports full request validation out of the box

openApiIntegration:
  validation: true
  ...

If enabled, the plugin generates the x-amazon-apigateway-request-validators blocks and adds a basic request validation to all methods. You can customize the VALIDATION template by placing your own files inside a directory openapi-integration (in your project root). The following files can be overwritten:

FilenameDescription
request-validator.ymlThe x-amazon-apigateway-request-validators block

See the EXAMPLES directory for detailed instructions.

Proxy Manager

The proxymanager feature automates the complete generation of an HTTP proxy integration. You only have to define the target URL and all necessary AWS integration blocks are generated on-the-fly during deployment.

openApiIntegration:
   cors: true
   validation: true
   mapping:
      - stage: [dev, prod]
        proxyManager:
           type: http_proxy
           baseUrl: https://www.example.com
           pattern: "(?<=api\/v1)\/.+"
  ...

With this setting, no separate integration files need to be created

A combination of your own and auto-generated files is still possible without any problems

Proxy Manager configuration

type

at the moment only http_proxy supported

baseUrl

The base url is required to map the path variable from the openapi specification to the URI from the aws integration.

Example:

#original openapi specification
paths:
   /api/v1/user:
    post:
      ... 

will be translated to

#generated openapi specification output
paths:
   /api/v1/user:
      post:
         ...
         x-amazon-apigateway-integration:
            type: http_proxy
            passthroughBehavior: when_no_match
            httpMethod: POST
            uri: https://www.example.com/api/v1/user

pattern

The pattern can be used to adapt the mapping of the base url using regexp, to remove a prefix, or a version string

Example:

baseUrl: https://www.example.com
pattern: "(?<=api\/v1)\/.+"

will translate the route /api/v1/user to https://www.example.com/user

Configuration Reference

configure the plugin under the key openApiIntegration

openApiIntegration:
  inputFile: schema.yml #required
  package: true #optional, defaults to false 
  inputDirectory: ./ #optional, defaults to ./
  cors: true #optional, defaults to false
  autoMock: true #optional, defaults to false
  validation: true #optional, defaults to false
  mapping: #optional, can be completely blank if autoMock option is enabled
    - stage: [dev, prod] #multiple stages
      path: integrations
      proxyManager: #optional
         type: http_proxy
         baseUrl: https://example.com
         pattern: "(?<=v1)\/.+"
    - stage: test #single stage
      path: mocks/customer.yml
  outputFile: api.yml #optional, defaults to api.yml
  outputDirectory: openapi-integration #optional, defaults to ./openapi-integration

Known Issues

Stage deployment

When using serverless framework only to deploy your aws resources without having any lambda functions or triggers, the AWS Gateway deploymemt does not behave as expected. Any deployment to an existing stage will be ignored, since CloudFormation does not redeploy a stage if the DeploymentIdentifier has not changed.

The plugin serverless-random-gateway-deployment-id solves this problem by adding a random id to the deployment-name and all references to it on every deploy

See the examples folder for a full working example

Variable Resolving

Serverless variables inside the openapi integration files are not resolved correctly when using the package & deploy hooks. This problem can be solved by using the api gateway STAGE VARIABLES.

See the examples folder for a full working example

Example

service:
  name: user-registration

provider:
  name: aws
  stage: dev
  region: eu-central-1

plugins:
  - serverless-openapi-integration-helper
  
openApiIntegration:
  inputFile: schema.yml
  package: true
  mapping:
    - path: integrations
      stage: [dev, prod]
    - path: mocks/customer.yml
      stage: test

functions:

resources:
  Resources:
    ApiGatewayRestApi:
      Type: AWS::ApiGateway::RestApi
      Properties:
        ApiKeySourceType: HEADER
        Body: ~
        Description: "Some Description"
        FailOnWarnings: false
        Name: ${opt:stage, self:provider.stage}-some-name
        EndpointConfiguration:
          Types:
            - REGIONAL
    ApiGatewayDeployment:
      Type: AWS::ApiGateway::Deployment
      Properties:
        RestApiId:
          Ref: ApiGatewayRestApi
        StageName: ${opt:stage, self:provider.stage}
serverless deploy --stage=test
serverless deploy --stage=prod

Approach to a functional test of schema validation

The plugin works well in combination with the serverless-plugin-test-helper to automate tests against the deployed api gateway

Install The plugin test helper package

npm install --save-dev serverless-plugin-test-helper

add the plugin as a plugin dependency in your serverless configuration file and configure the plugin according to the Readme

#./serveless.yml
plugins:
  - serverless-plugin-test-helper
  - serverless-openapi-integration-helper

[...]

resources:
   Outputs:
      GatewayUrl: # This is the key that will be used in the generated outputs file
         Description: This is a helper for functional tests
         Value: !Join
            - ''
            - - 'https://'
              - !Ref ApiGatewayRestApi
              - '.execute-api.'
              - ${opt:region, self:provider.region}
              - '.amazonaws.com/'
              - ${opt:stage, self:provider.stage}

   Resources:
    ApiGatewayRestApi:
      Type: AWS::ApiGateway::RestApi
      Properties:
        ApiKeySourceType: HEADER
        Body: ~
        Description: User Registration (${opt:stage, self:provider.stage})
        FailOnWarnings: false
        Name: ${opt:stage, self:provider.stage}-gateway
        EndpointConfiguration:
          Types:
            - REGIONAL
    ApiGatewayDeployment:
      Type: AWS::ApiGateway::Deployment
      Properties:
        RestApiId:
          Ref: ApiGatewayRestApi
        StageName: ${opt:stage, self:provider.stage}

Testing the schema validation

Add a functional test (e.g. with jest)

//tests/registration.js
import {getOutput} from 'serverless-plugin-test-helper';
import axios from 'axios';

axios.defaults.adapter = require('axios/lib/adapters/http'); //Todo

const URL = getOutput('GatewayUrl');
test('request validation on registration', async () => {
    expect.assertions(1);
    const {status} = await axios.post(URL + '/api/v1/user',
        {
            "email_address": "test@example.com",
            "password": "someStrongPassword#"
        },
        {
            headers: {
                'Content-Type': 'application/json',
            }
        });
    expect(status).toEqual(201);
});

test('request validation on registration (invalid request)', async () => {
    expect.assertions(1);
    try {
        await axios.post(URL + '/api/v1/user',
            {
                "email": "test@example.com"
            },
            {
                headers: {
                    'Content-Type': 'application/json',
                }
            });
    } catch (e) {
        expect(e.response).toMatchObject({
            statusText: 'Bad Request',
            status: 400
        });
    }
});

Then perform the functional test

serverless deploy --stage=test
npm test
serverless remove --stage=test

The command will

  • merge the openapi specification file with the MOCK integration configured before
  • deploy to API Gateway in an isolated TEST infrastructure environment (your other environments will not be affected since we are deploying to a separated gateway)
  • perform the test and verify that schema validation is correct
  • remove all TEST resources if test succeeded

See the examples folder for a full working example

Feedback is appreciated! If you have an idea for how this plugin/library can be improved (or even just a complaint/criticism) then please open an issue.

Author: yndlingsfar
Source Code: https://github.com/yndlingsfar/serverless-openapi-integration-helper 
License: MIT license

#serverless #openapi #aws 

Annie  Emard

Annie Emard

1652061420

CallGraph: Generate Static Call Graphs for Multiple Languages

Generate static call graphs for multiple languages

A call graph shows how functions call each other within a program.
Each oval represents a function, and each arrow indicates a function call.
In the diagram below, the main program is represented by node MAIN. It calls 6 functions, one of which calls 9 other functions.

'callGraph' parses source code for function definitions and calls, generates a call graph image, and displays it on screen.
Supported languages are: awk, bash, basic, dart, fortran, go, lua, javascript, julia, kotlin, matlab, perl, pascal, php, python, R, raku, ruby, rust, scala, swift, and tcl.

c/c++/java are not supported, since their complex and varied syntax requires heavy machinery.
 

"Sample output"

Usage:
    callGraph  <files>  <options>

    If your script calls helper modules, and you want the call graph to display the modules' functions,
        list the modules explicitly on the command line:
    callGraph script.pl path/moduleA.pm path/moduleB.pm
    
Options:
    -language <lang>           By default, filename extensions are parsed for .pl .pm .tcl .py, etc.
                               If those are not found, the first line of the script (#! shebang) is inspected.
                               If neither of those give clues, use this option to specify 'pl', 'tcl', 'py', etc
                               This option is required if a directory is scanned

    -start <function>          Specify function(s) as starting point instead of the main code.
                               These are displayed in green.
                               This is useful when parsing a large script, as the generated graph can be huge.
                               In addition, the calls leading to this function are charted.
                               Functions which are not reachable from one of the starting points
                                 are not charted.
                               -start __MAIN__  can be very useful when multiple source files
                                 are specified on the command line
                              The filename can be included as well:
                                                -start <file>:<function>

    -ignore <regex>            Specify function(s) to ignore.
                               This is useful when pruning the output of a large graph.
                               In particular, use it to remove logging or other helper functions which are
                                 called by many functions, and only clutter up the graph.
                               To ignore multiple functions, use this regex format:
                                   -ignore '(abc|xyz)'

    -output <filename>         Specify an output filename
                               By default, the .png file is named according to the first filename.
                               If a filename ending in .dot is given,
                                 only the intermediate .dot file is created.
                               If a filename ending in .svg is given, svg format is used
                               If a filename ending in .pdf is given, pdf format is used

    -noShow                    By default, the .png file is displayed.  This option prevents that behavior.

    -fullPath                  By default, the script strips off the path name of the input file(s).
                               This option prevents that behavior.

    -writeSubsetCode <file>    Create an output source code file which includes only the functions
                                 included in the graph.
                               This can be useful when trying to comprehend a large legacy code.

    -ymlOut <file>             Create an output YAML file which describes the following for each function:
                                   * which functions call it
                                   * which functions it calls
                               This can be useful to create your own automation or custom formatting
                               
    -ymlIn <file>              Use your intermediate file instead of parsing source files

    -verbose                   Provides 2 additional functionalities:
                               
                               1) Displays the external scripts referenced within each function

                               2) For Perl/TCL, attempts to list the global variables
                                    used in each function call in the graph.
                                  Global variables are arguably not the best design paradigm,
                                    but they are found extensively in real-world legacy scripts.

                                  Perl:
                                      'my' variables will affect this determination (use strict).
                                      Does not distinguish between $var, @var and %var.

                                  TCL:
                                      Variables declared as 'global' but not used, are marked with a '*'


Usage examples:
    callGraph  example.pl example_helper_lib.pm
    callGraph  example.py
    callGraph  <directory> -language 'go'

Algorithm:
    callGraph uses a simple line-by-line algorithm, using regexes to find function definitions and calls.
    Function definitions can be detected easily, since they start with identifiers such as:
        'sub', 'def', 'proc', 'function', 'func', 'fun', or 'fn'
    Function definitions end with '}' or 'end' at the same nesting level as the definition.
    Function calls are a bit more tricky, since built-in function calls look exactly like user function calls.
        To solve this, the algorithm first assumes that anything matching 'word(...)' is a function call,
        and then discards any calls which do not have corresponding definitions.
    For example, Perl:
        sub funcA {
            ...
            if ($x) {
                print($y);
                funcB($y);
            }
            ...
        }
        sub funcB {
            ...
        }
    Since this is not a true parser, the formatting must be consistent so that nesting can be determined.
    If your Perl script does not follow this rule, consider running it through 'perltidy' first.
    Also, don't expect miracles such as parsing dynamic function calls.
    Caveats aside, it seems to work well on garden-variety scripts spanning tens of thousands of lines,
        and has helped me unravel large pieces of legacy code to implement urgent bug fixes.
    
Acknowlegements:
    This code borrows core functionality from https://github.com/cobber/perl_call_graph

Requirements:
    GraphViz and the Perl GraphViz library must be installed:
        sudo apt install graphviz
        sudo apt install make
        sudo cpan install GraphViz

Author: koknat
Source Code: https://github.com/koknat/callGraph
License: GPL-3.0 License

#graphs