Python https://www.python.org/ is a high level interpreter language, supporting object oriented programming, and having a lot high level libraries for all kind of applications. It is highly portable to all kinds of hardware devices and operating systems. Python scripts are converted to byte code that runs on a virtual machine. Additionally there is IronPython that runs on top of .NET (or Mono) or Microsofts python for .NET and Jython that runs on Java virtual machine. There are ten-thousands of python packages available at https://pypi.python.org/pypi
Extending python is connecting C routines to python. The other way around is also possible, embedding python is integrating the python interpreter in a c program. And have this run the python script.
Python scripts have usually the extension py but can also have no extension at all, since under Linux the magic first line
#!/usr/bin/python
tells exactly what to do when this file has to be executed, start the interpreter found under /usr/bin/python
The first thing to know when dealing with python scripts is that to group commands no {} brackets are used, everything is done with indention.
Be consequent and do not use tab characters but use space characters for the indent, so when using different editors no mess gets created.
Avoid long sequences of nested code segments, use functions and objects to encapsulate.
As general advice, if the code is getting large and nested, then its is time to learn a bit more about python since using the right methods (including, dictionaries, sets, classes, libraries) surprisingly compact code can be written.
The file /usr/bin/python
is probably a link to a command as /usr/bin/python2
or /usr/bin/python3
because different version of python might be installed on the computer. It selects therefore the default python to be used. To be more specific the magic line could be
#!/usr/bin/python3
To select python3
Today still many python scripts are written for python2 that has incompatibilities with python3. So a python3 script will not run with a python2 interpreter and vice a versa.
Since python2 is no more actively developed, this book concentrates on python3.
If the computer is setup for python3 it fails when starting a python2 script. Therefore /usr/bin/python2 <script name>
will force to use python2
A script 2to3 is installed that can automatically convert python2 scripts to python3
see: https://docs.python.org/2/library/2to3.html. Running 2to3<myscript>
.py it will analyze the script and prints the changes to the screen. To rename the python2 script to <myscript>
.py.bak and create a converted python3 script run it as 2to3 -w<myscript>
.py. If python 2 is set as the active python interpreter run it as python3<myscript>
.py. Note that python3 is a link to something as python3.1
Or set the magic line first line to choose the right version:
#!/usr/bin/python3
2to3 makes use of fixers that can be listed with 2to3 -l. Not all are active per default and need to be enabled with 2to3 -f<name of fixer>
if desired.
The 2to3 works well on simple scripts, where the keyword print gets converted to the function call print(), but the troubles come with the libraries and file access.
To test python open a console and type python. Now you can type in commands and see what is going on.
On Getnoo Linux eselect python list will show what python version is the default and what are installed
Different python versions are probably installed on the same computer so the question arises what packages are available and taken. A way to see it is starting
python
Python 3.4.3 (default, Oct 30 2016, 21:08:25) [GCC 4.9.3] on linux Type "help", "copyright", "credits" or "license" for more information.
>>>
from distutils.sysconfig import get_python_lib
>>>
print(get_python_lib())
/usr/lib/python3.4/site-packages
User installed packages end up as ~/.local/lib64/python3.5/site-packages
Python documentation is available under
https://docs.python.org/ or
/usr/share/doc/python-docs-<xxx>/html/index.html
http://www.onlamp.com/python/
There is a python doc server (pydoc server) for OpenRC add it to the start
/etc/init.d/pydoc-<version>
start
The port is PYDOC_PORT=7464 and can be viewed:
The stuff comes from
/usr/share/doc/python-docs-2.5.1/html/index.htm
On trouble run it from a console /usr/bin/pydoc3.6 -b
The following IDE's are available:
The standard IDE (Integrated Development Environment) that comes with Python is idle:
It requires tcl and tk support to run.
For Gentoo set the tcl and tk useflags and then re-emerge it emerge -pv python
idle is pretty basic but it might be the only IDE available (or working). To pass command line parameters idle -r<name of python script>
<command line parameter>
For a specific python version start idle3.3
Debugging is possible using its debug window, where the source can be viewed and all the variables. In the source, breakpoints can be set to lines.
With the debug window open it debugs when run, with the debug window closed run runs.
Click the Source checkbox to see single step and where the program is. For the default setting single step is a dark gray line and brake point is yellow. Not both colors can be seen at the same time so the dark gray line disappears when jumping to a yellow line. So if there is no expected dark gray line press step or out.
It has individual windows, but when arranging them it looks like a real (but un-bloated) IDE
eric6 is a nice complete IDE for python.
Python can make you crazy about the formatting, here eric draws vertical lines to help you horizontally positioning the text.
To complete the python help insert in Settings > Preferences > Help Documentation >
Python Documentation the link to the directory as
/usr/share/doc/python-docs-<x>/html
that holds the index.html file.
It produces ~/.config/Eric6
and ~/.eric6
pycharm with its community edition gets installed under gentoo in /opt/pycharm-community/bin/pycharm.sh
pudb is a console based debugger
winpdb is a stand alone debugger with a GUI for python2 only (except some hacks are done). It is a highly featured python debugger especially when it comes to multi threading support. So use an context sensitive editor in one window and winpdb in a other window. The application uses os.fork() to create a child process. The function os.fork() returns two values, the value 0 to the child process and the PID of the child process to the parent process. Since the program forking is just one file (one program, one source), the two threads running the same source code, have to check the return value of os.fork() to know whether they run as child or as parent thread. The python debugger winpdb allows to debug either the parent process or whats probably more desirable to continue with the child process. To select what you desire the gui of winpdb has a console window where you can type in either fork child or fork parent.
Eclipse has a plugin, add the link http://www.pydev.org/updates/to get the pydev plugin. Then go to window -> preferences and set the python interpreter as /usr/bin/python3
Often python script are called by a external process, this might be a gui, and other python script or every thing else. The python script will then be started in a environment with additional environmental variable set, other command line parameters passed and maybe other processes or threads started in parallel. This environment is different from the one that would exist when the python script would have been started simply in a console.
Therefore you need a debugger with embedded debugging support as winpdb. Add the following line into the file that you would like to debug
import rpdb2; rpdb2.start_embedded_debugger_interactive_password()
Then start the program using the python script as usual, however this time the python script will prompt for a password and wait for an external debugger. Start winpdb and go to file => password and then file => attach where the python script pop's up and can be selected. If you have problems with the interactive password you can use fix password as:
import rpdb2; rpdb2.start_embedded_debugger('hello')
Hint for winpdb: It shows at the current line capital letters that have the following meaning
C |
CALL |
A function is called (or some other code block entered) |
L |
LINE |
The interpreter is about to execute a new line of code (sometimes multiple line events on one line exist) |
R |
RETURN |
A function (or other code block) is about to return |
E |
EXCEPTION |
An exception has occurred |
* |
RUNNING |
The thread is still running (probably blocked in C code) |
Inside a python module there are global and local variables. However a child module has its own global name space and can not access global variables of the parent module. The parent module however can access the global variables of the child module by simply adding the child's module name as prefix (if imported this way)
Variables and almost everything in python are objects. Objects are instances of classes. Objects have an identifier, a name (that is optional) and a value.
Some objects as integers have immutable values and result in a not obvious behavior. This is best explained by the following:
>>> a=1 >>> b=1 >>> id(a) 134578352 >>> id(b) 134578352 >>> id(1) 134578352
To the object with the value 1 the name a gets assigned. After that the object with the name a and the value gets an additional name b. This can be verified by checking the id of the object using the names. The identifier can also be observed by passing the value to the id() command. Assigning the name b to an other value (=object) deletes the name b of the previous object.
To see that a is an object you can call the class add method of a:
>>> a.__add__(2) 3
This the same as a +2 that results in 3. In fact python converts the + sign to the class method __add__ , but luckily hides this to human.
Luckily there are objects with mutable values as lists, they behave as expected:
>>> a=[1] >>> id(a) 3075342668L >>> b=[1] >>> id(b) 3074937644L
For mutable objects, each value assigned to a name creates a new object. To get the value of the first (and here only) value of the list you can either use the nice looking command using brackets or the class __getitem__ method:
>>> a[0] 1 >>> a.__getitem__(0) 1
However the following shows a common pitfall. The simple command b=a behaves differently, the list just gets a second name. To make a copy, a slice out of the list a needs to be done. The syntax for it is [<start index>
:<end index>
]. If the indexes are omitted as in [:] then a slice from the very beginning to the very end is done.
>>> a=[1] >>> b=a >>> id(a) 3074516172L >>> id(b) 3074516172L >>> c=a[:] >>> id(c) 3074916588L
Python data types or more precisely data classes can be grouped in mutable and immutable. Additionally there are sequences. Some sequences are mutable (as lists) and some immutable (as strings, tuples).
To use the wording of object oriented programming, if a data class gets used, it becomes an data object as instance of the data class.
Explaining in simple words, it is sometimes not obvious that the data is immutable:
>>> a="hello" >>> id(a) 3073624256L >>> a=a[1:3] >>> a 'el' >>> id(a) 3073538048L
It seems that the immutable string a has been changed (even being immutable). However as the id() shows a new variable with the name a has been created.
With mutable data types the behavior is different:
>>> list=['h','e','l','l','o'] >>> id(list) 3074023660L >>> del list[2] >>> id(list) 3074023660L >>> print list ['h', 'e', 'l', 'o']
Using the python data types is a bit confusing since some commands are consistent among the different data types others not. To understand the logic behind, the different and many data types need to be understand in very detail.
There is a reason way different data types exist!
Strings have a lot of functions (or in term of object oriented programming) methods.
Table 15.2. String methods
s.strip() | Removes blank (or character passed) characters from the beginning and end |
s.split("/") | Using the character passed, splits the string in substring and returns list of substrings |
s.endwithsuffix("/") | Returns true if the string ends with the character passed |
List and tuples can have different type of variables inside. C has arrays and structures for that.To add a new element to a list do a+=[i].
One big change between python2 and Python3 are the way strings are handled.
There are strings using unicode utf-8 and bytes (byte arrays).
To convert strings to bytes character encoding and decoding is required. Bytes can be declared with b'<here are bytes>
' whereas a string is '<this is my unicode string>
'.
Create bytes from strings is encoding strings and is done <stringofbytes>=<utf8string>
.encode()
Creating strings from bytes is decoding bytes and is done <utf8string>=<stringofbytes>
.decode()
Bytes arrays can contain any byte value or uft8 sequence. they can appear as follows:
x = b'El ni\xc3\xb1o' s = x.decode() print(s)
To convert a number into bytes
b=chr(128).encode()
This has also impact how files are handled. Files can be read as text (strings) or binary data (bytes).
You can also get elements in a sequence counting from the back a[-1] gives the last element in a. Mathematically speaking the length len(a) is added to negative numbers.
>>> a="hello" >>> a[0] 'h' >>> a[-1] 'o'
The .count(<listelement>
) method returns how many times the list element is in the list, so don't loop lists for that.
2**8 is power 8 of 2 and so 256. In C, after including the math library, it would be pow(2,8)
>>> 2**8 256
Python can deal with complex numbers:
>>> a=2j >>> a+(1+1j) (1+3j)
Range checking gets more readable instead of C like (a>min)&&(a<max) it gets
>>> max=5 >>> min=2 >>> a=3 >>> min<a<max True
Every different from 0 is considered as True. this explains the following:
if a: pass if len(a): pass
Instead of if: else: if: else: if: else: use if: elif: elif: else:, since no switch case as in C exists.
A count variable is not required in the for loop to access elements in a sequence (notice the indention):
>>> s=[0,2,4,6] >>> for p in s: ... p ... 0 2 4 6
Inside the for loop do not modify s. If you want to do it use a while loop. As example:
>>> s=[0,2,4,6] >>> while len(s)>0: ... print s ... s.pop(0) ... [0, 2, 4, 6] 0 [2, 4, 6] 2 [4, 6] 4 [6] 6
Without argument pop defaults to -1 and takes the last list member.element.
If you still want to use a count variable, you could use a while loop, but python stile uses the range command that creates a sequence that is passed to the for loop:
>>> for p in range(3): ... p ... 0 1 2
The range command can also do more as counting back and create more complex sequences.
Functions can return also more complex data as lists.
Functions can alternatively be called with <parametername>
=<value>
instead of just the values in correct sequence separated by commas. This looks like more writing but is safer and nicer code since it is independent of the sequence and also makes sure the parameter are passed in a consistent manner. To have good documented code it is also recommend to put every parameter to a new line and add a comment using the # character on every line.
*<parameter>
means that the <parameter>
can occur multiple times. It can be accessed using <parameter>
[].
<parameter>
=5 assigns a default value, this allows to call the function without passing any parameters.
Modules are usually single py files. Packages contain one or many modules. Packages are py files inside a subdirectory and have an __init__.py file.
To use a module that is in the same directory. Note don't use - character in py file names.
import <module name>
To import all modules from a package (This can create tons of unnecessary global variables and naming conflict)
from os import *
So better
import os
And putting os in front of the module name to make it clear to where it belongs.
Python modules are usually put under /usr/lib/python<pythonversion>/site-packages
but when developing a more flexible way is desired than creating and installing packages. The modules can be anywhere as long python finds it.
With the command export PYTHONPATH=/<here is my direcory>
/ ; $PYTHONPATH the search paths for python can be expanded.
To not have the hassle with the PYTHONPATH
import sys
print(sys.path)
shows where python is looking for modules, so links as
ln -s /home/<path>
/<module name>
.py /usr/lib/python3.2/<module name>
.py
Modules in the sys.path will be found modules elsewhere not and cause an import error. The first path in sys.path is usually ' ' this means the current working dir (os.getcwd()). Depending how the python script is started the cwd might be different and the python script fails (as when debugging in IDLE) to not have such effects add the missing path to sys.path using sys.path.append(<missing path >
)
__file__ that holds the started script.
When writing a module, it is desired to run the module on its own, reasons are to debug the module or to have even a standalone utility program. Adding the following, makes starting the code just when calling the module directly with python on the command line. In this case the hidden variable __name__ contains __main__.
if __name__ == '__main__':
<here comes my test code calling the stuff above>
Instead of writing everything yourself look at https://pypi.python.org/pypi. There is also a tutorial about submitting and installing packages: https://wiki.python.org/moin/CheeseShopTutorial
A good python program should not crash. However sometimes it is not known in advance if a crash might happen. Examples are input from the user for a number, or parsing an xml file.
An other approach is to catch the exception and act afterwards. To initiate this add the python key word try: then the critical code. After that there is the choice for one of the two key words:
except: This key word initiates the commands that are executed when the commands after try fail. Optionally the error can be added to except as except TypeError: to act just on type errors. This way multiple except's can follow a try:
finally: This key word works as except:, except that this code is executed also when try: worked trouble free.
In python 2 print was a keyword but in python 3 it is a build in function, therefore it has print() brackets.
There are different ways how to format what print is doing. If nothing print prints out the variables and adds a space in between. The variables can also be converted to a string using str() or repr(). Finally there are two format string methods (see https://pyformat.info/). An old style (C like) using the % character and a new style using the .format method.
print(a, b) print(str(a)+" "+str(b)) print(repr(a).rjust(6), repr(b).rjust(6)) print('{0:6d} {1:6.2f}'.format(a, b))
The modern way is using {}
{} place holder for a string
{:d} decimal number
{:x} hex number
{:03x} hex number with 3 nibbles and printed preceding zeros
To not end with new line characters tell print to no insert them
print("No new line after here", end='')
Threads are as processes and allow to run in parallel, with the exception that threads use the same memory space. As example it thread1 writes to a global variable thread2 can read it. A python script not creating threads is a single thread script.
In the simples case threads are started as follows
import threading
t =threading.Thread(target=<function name>
)
t.start()
More advanced threads are started by defining a new subclass of the Thread class, then override the __init__(self [,args]) method to add additional arguments. Then, override the run(self [,args]) method to implement what the thread should do when started.
The word pass is a python keyword and does not do anything. It is used to not cause a syntax error in the above code. Since a breakpoint can be set to pass it is quite helpful during program development. pass can be put as place holder for code that needs to be written.
Since it is an interpreter language you can execute what is written in a string variable using the exec command.
>>> exec "pi=3.1415" >>> pi 3.1415
To read from the console raw_input() can be used that returns always a string. However input() could also be used that returns an object based on the input a string, and integer, ... . This looks like more coding work, but using the command type() can be used to check if the input was correct or try: can be used to just be optimistic and do and if it fails except TypeError: can be used to react.
Interrupting a running program can be done with a keyboard interrupt
while True: time.sleep(0.05) # be nice try: pass # some code here except KeyboardInterrupt: pass # crtl+C brings you here
Almost every program must deal with command line parameters. Therefore python offers modules for that. The module argparse should be used now. It replaced optparse that replaced the getopt module. Some python statements are required to let the program known with what command line parameter it has to deal. Those parameters will then be easily available in the options structure. Left overs that will not be parsed are called positional arguments and are arguments that usually are absolute necessary to run (as a filename).
Instead of printing out information to track what the program is doing python offers a logger, see https://docs.python.org/3/howto/logging.html. After
import logging
a logging call looks similar as a print:
logging.info("This variable will be logged: "+i)
The logger can be configured. Levels can be set to control how much is printed. The levels are: DEBUG, INFO, WARNING, ERROR and CRITICAL and the outputs can be written in a file instead of the console:
logging.basicConfig(level=logging.INFO, filename='log.log')
Python programs with Graphical User Interfaces (GUI) make use of the following graphical libraries that give the applications different look:
pyQT based on QT
http://wxpython.org/ toolkit based on http://wxWidgets.org/ There is Boaconstructor a RAD (rapid development) GUI tool for it.
http://pygtk.org/ that is the gtk=gimp tool kit. Glade is a tool to draw the GUI as xml file that can then be used by GtkBuilder to interface to different programming languages as python.
anjuta is the standard ide for gnome and gnome is based on gtk. In anjuta a new project can be created for python pyGtk. It has dependencies to rope and glade to have support for it working. This creates a working hello world gui application using python. The gui itself is an xml file with the extension ui that is in the data subdirectory. The glade support in anjuta is responsible to edit this xml file using a gui and not a text editor and integrate it to the anjuta file. Glade itself would run as standalone program to edit this ui xml file, however a consistency mess with anjuta would then be probable.
Tkinter is an interface to tk (tool kit).
Tkinter comes with python and needs no installation, but looks a bit basic. Using ttk (Tk themed widgets) to look can be improved. An advantage is that it is stable, has not many dependencies and is portable.
Links to documentation: https://tkdocs.com/tutorial/index.html https://documentation.help/Python-3.6.3/tkinter.ttk.html
Nowadays tinker gets used together with ttk (Tk themed widgets).
ttk comes with a set of widgets allowing to set themes with the style= attribute.
Matplotlib for plotting and numpy for numerical calculation bring functionality as known from Matlab into python. Matplotlib uses a frontend/backend approach to output the plots. This allows to use different backends to put the results into files having different formats or embed in various GUI canvasses as tkinter, gtk, qt, qt4.
Matplotlib commonly uses numpy arrays but for simple things without a lot of computing as reading results from an instrument, python lists instead of numpy arrays can be used.
For python3 matplotlib >=1.2 must be installed
The standard way of installing python package is pip and using https://pypi.org/ and https://pip.pypa.io/en/stable/user_guide/ However installing packages without the Linux package manager being involved is not advised. pip needs to be first installed. For Gentoo emerge dev-python/pip
pip is also aware on what it did and what it can do. Commands as:
pip list and pip list --outdated
pip search <name>
pip uninstall <name>
pip install --upgrade <name>
pip install --trusted-host files.pythonhosted.org <name>
when getting error
Avoid using pip as root since it could impact python scripts that are used by the system (especially gentoo since all system program as emerge are written in python). Use it as user and install the python package under the users home directory. pip install --user bincopy==14.0.0 The package goes in something as ~/.local/lib64/python3.5/site-packages
and the python interpreter will find it.
In Linux such packages should be installed as usual using the package manager (for Gentoo the emerge command) to no create a mess with the installed package database. The python files will be installed to /usr/lib64/python
<m>
.<n>
/site-packages/<package name>
Additionally specially for Gentoo Linux there might be different python versions installed (see <m>
.<n>
) so it is good the package manager takes care about this. Otherwise python might be unable to find the package for the simple reason: Mismatch between python and package version numbers.
Python looks in the sys.path that can be seen by
python
Python 3.5.4 (default, Jan 7 2018, 19:27:36) [GCC 6.4.0] on linux
import sys
Type "help", "copyright", "credits" or "license" for more information. >>>
>>>
sys.path
['', '/usr/lib64/python35.zip', '/usr/lib64/python3.5', '/usr/lib64/python3.5/plat-linux', '/usr/lib64/python3.5/lib-dynload', '/usr/lib64/python3.5/site-packages'] >>>
Distutils creates further a
file (or directory) that contains information about the package. There is also a <name>
-<version>
-<python version>
.egg-info__pycache__
directory that holds the compiled and optimized bytecode files for the py file.
To use an installed python package it must be imported. To know how and what to import it must be known how it got installed.
Files as /usr/lib64/python
can be imported as <m>
.<n>
/site-packages/<name>
.py
import <name>
It is common, that a package is installed into a directory under /usr/lib64/python
and this directory holds different python files. Such a file <m>
.<n>
/site-packages//usr/lib64/python
can be imported as <m>
.<n>
/site-packages/<package name>/<name>
.py
from <package-name> import <name>
Doxygen supports python as well. The docstrings are considered directly by doxygen without the need to specially mark them.
Python has also a feature to attach a docstring to functions. After the function header a line starting by """ will open the docstring that can contain multiple lines and needs no special characters at the beginning of each line. The docstring is terminated by a second line starting with """. Such docstrings can be visible in the python interacting mode by the help() function.
The python module (file, main program) can hold a doxygen command as follows:
"""@package docstring
<Documentation>
"""
Alternatively for doxygen the # character used for comments can be takes as well.
With unittest a program (test.py
) can be made that calls the python program in various ways and compares the results against what is expected.
#!/usr/bin/python3 import unittest class MyTest(unittest.TestCase): def test_default(self):<code>
self.assertEqual(a,b) def test_other(self):<code>
self.assertEqual(a,b) if __name__ == '__main__': unittest.main()
Different test_<name>
functions can be added that contain an assert<what>
method.
The program test.py can then be called as
python -m unittest -v test.py
python test.py -v
test.py -v since it contains #!/usr/bin/python3
test.py MyTest -v to call the MyTest test cases
test.py MyTest.test_default_bin -v to just call a specific test case (for example the one causing troubles)
A good sign of code quality is if test run all the code. The program coverage can be used instead of the program python.
coverage run <program>
.py
coverage report to get a text report
coverage html then open htmlcov/index.html
to see a html report
coverage -h to get help
coverage does not check what get started and run in other processes
More than one python version is probably installed on your computer. In Gentoo Linux the command eselect python list shows what is installed and what is taken as default, first you must emerge eselect-python.
To switch to a particular version do eselect python set<n>
Which python version is active is set by links in /usr/bin
Since Gentoo allows to have more than one python version installed and usable at the same time (like version 2.7 and its new incompatible version 3.4), there needs to be some setup that this works. When installing the Gentoo-way a python scripts they end up under /usr/bin
however a closer look shows there is just a link to a wrapper script ../lib/python-exec/python-exec2
inside ../lib/python-exec/
there are other directories as python3.3
that contains all scripts.
The wrapper python-exec hat its configuration file /etc/python-exec/python-exec.conf
where global preferences are set. Obviously the preferred python version must be installed, otherwise gentoo tools as emerge will pop up errors.
The libraries are under /usr/lib/python
where additional installed packages are in
<pythonversion>
/usr/lib/python
. When updating and removing an old python version, it can happen that the old directory
<pythonversion>
/site-packages/usr/lib/python
remains, due to unknown garbage inside, so take a look and delete it. <pythonversion>
/site-packages
Python is portable to many different CPU architectures and operating systems, however it runs only if a python interpreter is installed. On a Linux machines as Gentoo, python can be assumed to be installed but on a Windows machine not.
On Windows the python scripts the extension can be renamed from py
to pyw
to hide the black console window when graphical python scripts are executed. The interpreter pythonw.exe
is then used instead of python.exe
As alternative there is Jython (the successor of JPython) http://www.jython.org/, this is python 2.x running on top of a Java virtual machine as java byte code. To use jython type jython. Jython with all its libraries can be installed as java -jar jython_installer-<version>
.jar --console or if you like to risk a gui headache java -jar jython_installer-<version>
.jar
After installation, python can be started with
IDLE console => python my.py
console => my.py
double click in file manager (but console applications disappear when done)
The best way to start is using Windows menu start and start IDLE. Then open a python script
and run it as module F5
<name>
.py
It might be installed in a user directory and therefore just available for a single user as
c:\Users\
<username>
\AppData\Local\Programs\Python\Python35\python.exe
Python is not added to the windows path environmental variable so it will not be found in console window it need to be started with the complete path.
This can be fixed by adding this path to the windows environmental variables:
The shell might probably report that some modules (libraries) are not installed
The next problem is how to install those libraries, the standard way is using pip. Newer python version come with pip, on older versions pip needs to be installed first.
update pip (-m makes python know that pip is a module and python therefore knows where to look for it) is done with python -m pip install -U pip
python -m pip install --user bincopy==14.0.0 installs the missing module (bincopy) with a desired version (14.0.0)
A warning might comes that c:\Users\
should be set to the path
this is recommended otherwise programs as pyinstaller are not found<username>
\AppData\Roaming\Phyton\Phython35\Scripts
If the installation fails due to certification errors install the certificates python -m pip install certifi
When debugging with IDLE then it can happen that imports of local modules fail. The reason is that sys.path does not contain the path of the script and the current working path is not the path where the script is. This can be fixed in the shell window of IDLE by sys.path.append('Z:\\<path of current script>
'). In this example it is shown that Windows need to get two \\ characters since the first is a string escape character.
To know where the code is running use :
>>> import platform >>> platform.system() 'Windows'
To get portable code avoid using commands as os.system("cd /home") that execute Linux commands. Use os.chdir(<path>
) instead.
os.linesep instead of '\n' for Linux or '\r\n' for windows used in text files. However within python code it is recommended to use all the time '\n' on all platforms and have pythin deal with it.
However the next problem arises the path syntax is not consistent between Windows and Linux.
Pyhon internally the '/' is used also for windows. Printing this out would cause confusion and or passing it to a windows program would cause an error.
The pathlib can be used to convert paths from String to an object. Then different methods are possible.
import pathlib
# is an object maybe required to convert to string
s=pathlib.PureWindowsPath(<path>
)
t=str(s) # converts object to string
u=s.as_posix() # returns a string
Alternatively it can be dealt on string level using functions/constants/variables as
os.sep instead of the '\' for Windows and '/' for Linux characters. Don't be afraid seeing '\\' for Windows. '\' is used in Strings as escape character allowing to insert none printable characters. So a second '\' character needs to be inserted to indicate that it is a '\' character.
os.path
os.path.split() and os.path.join()
The os module (there are different implementations for the different os) puts an abstraction layer to it that can normalize path names, so it converts Windows forward slashes to backward slashes and have the drive name as directory name. Be aware that not all file systems understand utf-8 encoded file names.
Under Linux ~
is expanded to the users home directory /home/
on Windows this works as well but will be expanded to <username>
C:\Users\
<username>
Directories under C:\Users\
that start with a '.' character are an indication that they got ported from a non Windows system to Windows (as from Linux to Windows)<username>
lxml might be problematic so it is wise to include it as
# call lxml as ET so it is compatible with the python # built-in library xml but the library lxml has more # features as pretty-print and xml declaration support lxml=False try: from lxml import etree as ET lxml=True except: import xml.etree.ElementTree as ET <some code> if lxml==True: tree.write(self.sessionPath+os.sep+self.sessionFile, encoding="utf-8", pretty_print=True, xml_declaration=True) else: tree.write(self.sessionPath+os.sep+self.sessionFile, encoding="utf-8") <some code>
pyinstaller from https://pyinstaller.readthedocs.io/en/stable/ offers a nice way to create a Windows exe. To run pyinstaller Python needs to be installed under Windows.
Take the time to check what python version (as 3.5.2) runs well with pyinstaller and avoid using not supported versions
pyinstaller allows converting python scripts into windows exe files not requiring to fiddle around with installing and setting up python on a windows computer. Those windows exe do not require to administrator privilege to install them, since they contain usually all required code. Two ways are possible
Everything packed in a single exe file, that when started extracts itself to a os temp directory as C:\Users\
\, then it runs from that and finally the directory gets removed. Since there is just one file it is easy to distribute it. Drawback is that it is slower to start and no files as <username>
\AppData\Local\Temp\<some name>
readme.txt
can be observed.
Directory structure that contains a small windows exe to be started and all other files (as dll or text files as readme.txt
.
Having a directory structure is also better during testing and developing, since it can be easy observed what files are around and where. Regarding paths pyinstaller is a bit tricky since a boot loader starts the windows exe.
Certain paths are different depending how python code is started.
pyinstaller <name>
.spec creates the
. <name>
.exe
The
can be created automatically the first time by calling pyinstaller <name>
.spec<name>
.py
Do not call pyinstaller <name>
.py since it overwrites
with a default one unless a new default <name>
.spec
is required. Create a backup copy of <name>
.spec
with a useful name as <name>
.spec
and call it pyinstaller <name>
-onefile.spec<name>
-onefile.spec
Files can be added in <name>
.spec
a = Analysis( datas=[('*.gif','.')], ...
The python tuple means copy it from source to destination.
There are also command line options when creating or overwriting a <name>
.spec file.
--add-data '*.gif:.' copies *.gif to the bundle
--onefile creates single
file <name>
.exe<name>
.exe
--windowed hides the console window and shows just the gui window. Drawback no error messages appear.
--onefile puts everything in a
file that when run gets first unzipped in temp folder of OS
<name>
.exe
--icon file.ico attaches a windows icon to replace the standard python icon seen in the windows file manager. it is not the icon in the window decoration of the application.
The pyinstaller can also be run under Linux as well, since it is pure python. The same commands as above can be used. However the result will be different, it will a Linux binary.
pyinstaller can also be installed on Linux (and Mac OS X, FreeBSD, Solaris and AIX) and can create single file executables as on Windows using pyinstaller <name>
.spec or if pyinstaller is installed locally ~/.local/bin/pyinstaller <name>
.spec.
This is a nice option to freeze all its dependencies to the python script and have it therefore archived and executable.
Under Windows, Python can also run from a memory stick without requiring an installation, as usual under Linux there are different ways to do this:
http://portablepython.com/ comes with an exe that is an installer. There are 2.6 but also 3.2 versions available. The versions have different IDE and libraries included. The pyscripter is a full featured IDE with everything desired and more. SPE is an other ide that makes use of winpdb as debugger. py2exe and the necessary DLL's are also present. Once installed the portable python directory can be copied and moved anywhere.
http://www.voidspace.org.uk/python/movpy/, unzip and go to the movpy directory and double click on movpyw to get the gui launcher. In the gui launcher the python script can be selected. There are also options to be clicked, on useful option is b that stops the console window after the script has run, this way it will be seen what the script has written to the console. IDLE is also available where the script can be debugged. Python version 2.5.1 comes with it.
Convert the python script into a windows exe file using pyinstaller
Python comes with distutils to have a standard way to distribute python code and therefore create a standard way to install it.
See: https://docs.python.org/3.5/distutils/
To create distutils package a setup.py
file has to be created that holds the information distutils requires.
For single py files this setup.py
file can placed beside the py files and can look as follows:
from distutils.core import setup setup(name='<name of the module>
', version='<version>
', scripts=['<name of the module, without py extension>
'], )
For more complex program it is wise to create a package, a collection of files. So put them in a subdirectory and place a setup.py
file above that directory that could look as:
from distutils.core import setup setup( name="girttools", packages = ["girttools"], version="0", description='Tools for Gnu Infra Red Transceiver', author='Urs Lindegger', author_email='urs@linurs.org', url='http://www.linurs.org/girt.html', download_url = "http://www.linurs.org/girt/download/girttools-0.tgz", keywords = ["Infrared transceiver"], classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Development Status :: 4 - Beta", "Intended Audience :: End Users/Desktop", "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", "Operating System :: POSIX :: Linux", "Topic :: Multimedia", ], long_description = """\ Gnu Infra Red Transceiver Tools ------------------------------- Tools to setup and work with the Gnu Infra Red Transceiver that can replace all you IR remote controllers. """
The setup function can be called with either packages this is a list of subdirectories containing the py files or py_modules a list of python files without adding the .py extension.
The long_description (or since it is python everything) can also be read out of a file:
long_description=open('README.md').read()
Valid classifiers can be found at https://pypi.org/pypi?%3Aaction=list_classifiers or https://pypi.org/classifiers/
Instead of py_modules that can list various py files packages is used containing the subdirectory that must contain a __init__.py
file.
Finally when done packages can be register so other will find them https://pypi.python.org/pypi?:action=register_form. Python Package Index (“PyPI”) allows to classify your package so it can be found, therefore don't invent your own classifiers select them out of https://pypi.python.org/pypi?:action=list_classifiers
To include attentional files create a MANIFEST.in
file as defined in https://docs.python.org/3.1/distutils/sourcedist.html. The MANIFEST.in
file can also contain wild-carts and distutils specific commands as recursive directory functions.
Adding files is not the same as having them installed. To install them to the same location as the package goes, use package_data in the setup.py
file and not MANIFEST.in
.
Finally MANIFET.in
is read among other things defined in setup.py to create the MANIFEST
file that contains all files
setup.py
can also contain data_files that can be used to install files in any directory. Due to specifying the path the *.tar.gz
package will no more be portable to different systems. An example would be installing a Linux init script to /etc/init.d
, however on a Linux system using systemd instead of init or even on a Windows machine this makes not much sense to install it. It is better to do this on the system specific package as for Gentoo Linux in the ebuild. However you simply add them to the *.tar.gz
using the MANIFEST.in
file.
python setup.py check will check your setup.py
To get the *.tar.gz
package in the subdirectory dist
run python setup.py sdist (source distribution)
For windows an graphical windows installer can be created: python setup.py bdist_wininst
setuptools is an enhanced alternative to distutils. Nice is that also setup tools uses a setup.py file. So Building the package is also done with python setup.py sdist
After having the tar.gz you could but should not install it as : python setup.py install Instead of that you should create a package that fits you Linux distribution and then use the package manager to have it installed. Under Linux python modules (py files) are copied to the directory /usr/local/lib/python
and packages (directories containing __init__.py) are copied into a subdirectory under <X>
.<Y>
/site-packages/usr/local/lib/python
. <X>
.<Y>
/site-packages
__init__.py indicates that all files in the same directory belong to a package and the directory is the name of the package.
/usr/local/lib/python
is a location that allows to import those modules and packages into other python modules but it is not a location where the command line finds them. Python files to be started on the command line must be declared in the <X>
.<Y>
/site-packagessetup.py
script as scripts. Under Linux those scripts will end up in the /bin
directory where the command line finds them.
Alternatively distutils allows to install the package to an other directory as your home directory with python setup.py install --home=~ any other directory with python setup.py install --home=<dir>
where no system conflicts should occur.
https://docs.python.org/3.1/distutils/builtdist.html helps you to move your package to distributions as creating a RPM red hat package.
For Gentoo Linux an ebuild needs to be developed that first installs the package in a sandbox and then copied (merged) to your system getting track what files will be added and check collisions.
Ebuilds can make usage of eclasses and there is a distutils eclass (https://wiki.gentoo.org/wiki/Project:Python/distutils-r1), so the ebuild for a python module can be very simple as:
EAPI=6 PYTHON_COMPAT=( python{3_4,3_5,3_6} pypy ) inherit distutils-r1 DESCRIPTION="Library for all sort of python code" HOMEPAGE="https://www.linurs.org" SRC_URI="http://www.linurs.org/download/${P}.tar.gz" LICENSE="Unlicense" SLOT="0" KEYWORDS="~arm64 ~x86 ~amd64" IUSE="" DOCS=( README.txt )
${P} is the filename of the ebuild including version number.
The inherit function loads distutils and this overwrites the standard install routines. So the ebuild contains no code just meta data about the python package and where to find it on the Internet remains.
The README.txt
file gets zipped under /usr/share/doc/${P}/
There is SWIG http://www.swig.org/ that creates wrapper code around the C or C++ code. This wrapper code can then be accessed by Python.
Or using cython: http://cython.org/
When a python code is started, then the source is converted into bytecode https://docs.python.org/release/2.5.2/lib/bytecodes.html and a virtual machine then executes this bytecode. When the same program is started again then the bytecode is started (except when the source has changed, then a new byte code is created). The files containing byte code have the extension pyc (or when optimized pyo). Be aware that the bytecode might be incompatible between different releases of python. Python has support for disassembling byte code:
>>> import dis >>> def myfunc(alist): >>> return len(alist) >>> dis.dis(myfunc) 2 0 LOAD_GLOBAL 0 (len) 3 LOAD_FAST 0 (alist) 6 CALL_FUNCTION 1 9 RETURN_VALUE