Skip to content

Commit 9144fb8

Browse files
authored
Merge pull request #1 from gjbex/development
Development
2 parents 1d3cb31 + 3ce7318 commit 9144fb8

File tree

20 files changed

+234
-30
lines changed

20 files changed

+234
-30
lines changed

docs/README.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
The Python programming language is increasingly popular. It is a
2-
versatile language for general purpose programming and accessible
3-
for novice programmers. For more than a decade, Python has been
4-
used for a large number of systems-related programming tasks.
1+
Python is a very versatile programming language that has a wide range of
2+
applications. This training concentrates on interaction with the
3+
operating system, the file system, other applications and the network.
4+
This is useful for systems programming, but also when you want to use
5+
Python as a coordination language for your workflows.
56
This training introduces modules that are useful in that context.
67

7-
88
## Learning outcomes
99

1010
When you complete this training you will
@@ -20,7 +20,7 @@ When you complete this training you will
2020

2121
## Schedule
2222

23-
Total duration: 3.5 hours.
23+
Total duration: 4 hours.
2424

2525
| Subject | Duration |
2626
|---------------------------------------------|----------|
@@ -29,6 +29,7 @@ Total duration: 3.5 hours.
2929
| logging | 10 min. |
3030
| interacting with the file system | 40 min. |
3131
| coffee break | 10 min. |
32+
| data formats | 30 min. |
3233
| templates | 10 min. |
3334
| interacting with processes | 45 min. |
3435
| interacting with remote systems using SSH | 30 min. |

environment.yml

+2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ name: python_for_systems_programming
22
channels:
33
- defaults
44
dependencies:
5+
- fabric
56
- jinja2
7+
- jupyter
68
- matplotlib
79
- numpy
810
- paramiko

python_for_systems_programming_linux64_conda_specs.txt

+46
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/libstdcxx-ng-9.1.0-hdf63c60_0.conda
1111
https://repo.anaconda.com/pkgs/main/linux-64/libgcc-ng-9.1.0-hdf63c60_0.conda
1212
https://repo.anaconda.com/pkgs/main/linux-64/mkl-2019.4-243.conda
1313
https://repo.anaconda.com/pkgs/main/linux-64/expat-2.2.6-he6710b0_0.conda
14+
https://repo.anaconda.com/pkgs/main/linux-64/gmp-6.1.2-h6c8ec71_1.conda
1415
https://repo.anaconda.com/pkgs/main/linux-64/icu-58.2-h9c2bf20_1.conda
1516
https://repo.anaconda.com/pkgs/main/linux-64/jpeg-9b-h024ee3a_2.conda
1617
https://repo.continuum.io/pkgs/main/linux-64/libffi-3.2.1-hd88cf55_4.tar.bz2
@@ -26,8 +27,10 @@ https://repo.anaconda.com/pkgs/main/linux-64/glib-2.63.1-h5a9c865_0.tar.bz2
2627
https://repo.anaconda.com/pkgs/main/linux-64/libedit-3.1.20181209-hc058e9b_0.conda
2728
https://repo.anaconda.com/pkgs/main/linux-64/libpng-1.6.37-hbc83047_0.conda
2829
https://repo.anaconda.com/pkgs/main/linux-64/libxml2-2.9.9-hea5a465_1.conda
30+
https://repo.anaconda.com/pkgs/main/linux-64/pandoc-2.2.3.2-0.conda
2931
https://repo.anaconda.com/pkgs/main/linux-64/readline-7.0-h7b6447c_5.conda
3032
https://repo.anaconda.com/pkgs/main/linux-64/tk-8.6.8-hbc83047_0.conda
33+
https://repo.anaconda.com/pkgs/main/linux-64/zeromq-4.3.1-he6710b0_3.conda
3134
https://repo.anaconda.com/pkgs/main/linux-64/dbus-1.13.12-h746ee38_0.tar.bz2
3235
https://repo.anaconda.com/pkgs/main/linux-64/freetype-2.9.1-h8a8886c_1.conda
3336
https://repo.anaconda.com/pkgs/main/linux-64/gstreamer-1.14.0-hb453b48_1.conda
@@ -36,33 +39,76 @@ https://repo.anaconda.com/pkgs/main/linux-64/fontconfig-2.13.0-h9420a91_0.conda
3639
https://repo.anaconda.com/pkgs/main/linux-64/gst-plugins-base-1.14.0-hbbd80ab_1.conda
3740
https://repo.anaconda.com/pkgs/main/linux-64/python-3.7.5-h0371630_0.conda
3841
https://repo.anaconda.com/pkgs/main/linux-64/asn1crypto-1.2.0-py37_0.tar.bz2
42+
https://repo.anaconda.com/pkgs/main/noarch/attrs-19.3.0-py_0.tar.bz2
43+
https://repo.anaconda.com/pkgs/main/linux-64/backcall-0.1.0-py37_0.conda
3944
https://repo.anaconda.com/pkgs/main/linux-64/certifi-2019.9.11-py37_0.tar.bz2
45+
https://repo.anaconda.com/pkgs/main/noarch/decorator-4.4.1-py_0.tar.bz2
46+
https://repo.anaconda.com/pkgs/main/noarch/defusedxml-0.6.0-py_0.tar.bz2
47+
https://repo.anaconda.com/pkgs/main/linux-64/entrypoints-0.3-py37_0.conda
4048
https://repo.anaconda.com/pkgs/main/linux-64/idna-2.8-py37_0.conda
49+
https://repo.anaconda.com/pkgs/main/linux-64/invoke-1.3.0-py37_0.tar.bz2
50+
https://repo.anaconda.com/pkgs/main/linux-64/ipython_genutils-0.2.0-py37_0.conda
4151
https://repo.anaconda.com/pkgs/main/linux-64/kiwisolver-1.1.0-py37he6710b0_0.conda
4252
https://repo.anaconda.com/pkgs/main/linux-64/markupsafe-1.1.1-py37h7b6447c_0.conda
53+
https://repo.anaconda.com/pkgs/main/linux-64/mistune-0.8.4-py37h7b6447c_0.conda
54+
https://repo.anaconda.com/pkgs/main/linux-64/more-itertools-7.2.0-py37_0.conda
55+
https://repo.anaconda.com/pkgs/main/linux-64/pandocfilters-1.4.2-py37_1.conda
56+
https://repo.anaconda.com/pkgs/main/noarch/parso-0.5.1-py_0.tar.bz2
57+
https://repo.anaconda.com/pkgs/main/linux-64/pickleshare-0.7.5-py37_0.conda
58+
https://repo.anaconda.com/pkgs/main/noarch/prometheus_client-0.7.1-py_0.tar.bz2
4359
https://repo.anaconda.com/pkgs/main/linux-64/psutil-5.6.5-py37h7b6447c_0.tar.bz2
60+
https://repo.anaconda.com/pkgs/main/linux-64/ptyprocess-0.6.0-py37_0.conda
4461
https://repo.anaconda.com/pkgs/main/linux-64/pycparser-2.19-py37_0.conda
4562
https://repo.anaconda.com/pkgs/main/noarch/pyparsing-2.4.4-py_0.tar.bz2
4663
https://repo.anaconda.com/pkgs/main/noarch/pytz-2019.3-py_0.tar.bz2
64+
https://repo.anaconda.com/pkgs/main/linux-64/pyzmq-18.1.0-py37he6710b0_0.conda
4765
https://repo.anaconda.com/pkgs/main/linux-64/qt-5.9.7-h5867ecd_1.conda
66+
https://repo.anaconda.com/pkgs/main/linux-64/send2trash-1.5.0-py37_0.conda
4867
https://repo.anaconda.com/pkgs/main/linux-64/sh-1.12.14-py37_0.tar.bz2
4968
https://repo.anaconda.com/pkgs/main/linux-64/sip-4.19.8-py37hf484d3e_0.conda
5069
https://repo.anaconda.com/pkgs/main/linux-64/six-1.13.0-py37_0.tar.bz2
70+
https://repo.anaconda.com/pkgs/main/noarch/testpath-0.4.4-py_0.tar.bz2
5171
https://repo.anaconda.com/pkgs/main/linux-64/tornado-6.0.3-py37h7b6447c_0.conda
72+
https://repo.anaconda.com/pkgs/main/linux-64/wcwidth-0.1.7-py37_0.conda
73+
https://repo.anaconda.com/pkgs/main/linux-64/webencodings-0.5.1-py37_1.conda
5274
https://repo.anaconda.com/pkgs/main/linux-64/cffi-1.13.2-py37h2e261b9_0.tar.bz2
5375
https://repo.anaconda.com/pkgs/main/linux-64/cycler-0.10.0-py37_0.conda
76+
https://repo.anaconda.com/pkgs/main/linux-64/jedi-0.15.1-py37_0.conda
5477
https://repo.anaconda.com/pkgs/main/linux-64/mkl-service-2.3.0-py37he904b0f_0.conda
78+
https://repo.anaconda.com/pkgs/main/linux-64/pexpect-4.7.0-py37_0.conda
5579
https://repo.anaconda.com/pkgs/main/linux-64/pyqt-5.9.2-py37h05f1152_2.conda
80+
https://repo.anaconda.com/pkgs/main/linux-64/pyrsistent-0.15.5-py37h7b6447c_0.tar.bz2
5681
https://repo.anaconda.com/pkgs/main/noarch/python-dateutil-2.8.1-py_0.tar.bz2
5782
https://repo.anaconda.com/pkgs/main/linux-64/setuptools-41.6.0-py37_0.tar.bz2
83+
https://repo.anaconda.com/pkgs/main/linux-64/terminado-0.8.3-py37_0.tar.bz2
84+
https://repo.anaconda.com/pkgs/main/linux-64/traitlets-4.3.3-py37_0.tar.bz2
85+
https://repo.anaconda.com/pkgs/main/noarch/zipp-0.6.0-py_0.tar.bz2
5886
https://repo.anaconda.com/pkgs/main/linux-64/bcrypt-3.1.7-py37h7b6447c_0.tar.bz2
87+
https://repo.anaconda.com/pkgs/main/linux-64/bleach-3.1.0-py37_0.conda
5988
https://repo.anaconda.com/pkgs/main/linux-64/cryptography-2.8-py37h1ba5d50_0.tar.bz2
89+
https://repo.anaconda.com/pkgs/main/linux-64/importlib_metadata-0.23-py37_0.tar.bz2
6090
https://repo.anaconda.com/pkgs/main/noarch/jinja2-2.10.3-py_0.tar.bz2
91+
https://repo.anaconda.com/pkgs/main/linux-64/jupyter_core-4.6.1-py37_0.tar.bz2
6192
https://repo.anaconda.com/pkgs/main/linux-64/numpy-base-1.17.3-py37hde5b4d6_0.tar.bz2
93+
https://repo.anaconda.com/pkgs/main/noarch/pygments-2.4.2-py_0.tar.bz2
6294
https://repo.anaconda.com/pkgs/main/linux-64/pynacl-1.3.0-py37h7b6447c_0.conda
6395
https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.33.6-py37_0.tar.bz2
96+
https://repo.anaconda.com/pkgs/main/linux-64/jsonschema-3.2.0-py37_0.tar.bz2
97+
https://repo.anaconda.com/pkgs/main/linux-64/jupyter_client-5.3.4-py37_0.tar.bz2
6498
https://repo.anaconda.com/pkgs/main/linux-64/paramiko-2.6.0-py37_0.tar.bz2
6599
https://repo.anaconda.com/pkgs/main/linux-64/pip-19.3.1-py37_0.tar.bz2
100+
https://repo.anaconda.com/pkgs/main/noarch/prompt_toolkit-2.0.10-py_0.tar.bz2
101+
https://repo.anaconda.com/pkgs/main/linux-64/fabric-2.5.0-py37_0.tar.bz2
102+
https://repo.anaconda.com/pkgs/main/linux-64/ipython-7.9.0-py37h39e3cac_0.tar.bz2
103+
https://repo.anaconda.com/pkgs/main/linux-64/nbformat-4.4.0-py37_0.conda
104+
https://repo.anaconda.com/pkgs/main/linux-64/ipykernel-5.1.3-py37h39e3cac_0.tar.bz2
105+
https://repo.anaconda.com/pkgs/main/linux-64/nbconvert-5.6.1-py37_0.tar.bz2
106+
https://repo.anaconda.com/pkgs/main/linux-64/jupyter_console-6.0.0-py37_0.conda
107+
https://repo.anaconda.com/pkgs/main/linux-64/notebook-6.0.2-py37_0.tar.bz2
108+
https://repo.anaconda.com/pkgs/main/noarch/qtconsole-4.6.0-py_0.tar.bz2
109+
https://repo.anaconda.com/pkgs/main/linux-64/widgetsnbextension-3.5.1-py37_0.conda
110+
https://repo.anaconda.com/pkgs/main/noarch/ipywidgets-7.5.1-py_0.tar.bz2
111+
https://repo.anaconda.com/pkgs/main/linux-64/jupyter-1.0.0-py37_7.conda
66112
https://repo.anaconda.com/pkgs/main/linux-64/matplotlib-3.1.1-py37h5429711_0.conda
67113
https://repo.anaconda.com/pkgs/main/linux-64/mkl_fft-1.0.15-py37ha843d7b_0.tar.bz2
68114
https://repo.anaconda.com/pkgs/main/linux-64/mkl_random-1.1.0-py37hd6b4f25_0.conda

source-code/README.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Source code
2+
3+
This is source code that is either used in the presentation, or was developed
4+
to create it. There is some material not covered in the presentation as well.
5+
6+
## Requirements
7+
8+
* Python version: at least 3.6
9+
* Packages (names listed that can be used with `pip` or `conda` to install):
10+
* jinja2
11+
* jupyter
12+
* matplotlib
13+
* numpy
14+
* paramiko
15+
* psutil
16+
* python=3.7.5
17+
* sh
18+
19+
## What is it?
20+
21+
1. `application`: illustration of how to combine `configparser` and `argparse`.
22+
1. `cmd`: illustration of how to create a repl application.
23+
1. `code-evaluation`: illustrates how to evaluate a string containing
24+
Python code at runtime.
25+
1. `command-Line-args`: illustration of how to use the argparse and the
26+
click module to handle command line arguments.
27+
1. `config-parser`: illustrates how to use the ConfigParser module to handle
28+
configuration files.
29+
1. `data-formats`: illustrates how to deal with data formats such as CSV
30+
files, binary data and XML.
31+
1. `hydra`: Facebook Hydra application framework illustration.
32+
1. `logging`: illustration of Python's logging facilities.
33+
1. `file-system`: illustrations of interacting with the operating system
34+
and the file system.
35+
1. `paramiko`: a few examples of using the Paramiko library for SSH
36+
to remote hosts.
37+
1. `Sched`: scheduled execution of funcitons in Python.
38+
1. `Subprocess`: illustrates executing a shell command from a Python script
39+
using the `subprocess` module.
40+
1. `xml-generator`: code to generate a random XML documents.

source-code/application/README.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Application
2+
3+
Example of a very simple application that prints random integers between
4+
two given values. It uses argparse and configparser to handle configuration
5+
files and command line arguments.
6+
7+
The parameters are
8+
* `n`: the number of random values to generate,
9+
* `a`: the smallest value to generate, and
10+
* `b`: the largest value to generate.
11+
12+
The point is to illustrate specifying the parameters via
13+
1. defaults in the application, `n = 1`, `a = 0`, `b = 6`,
14+
1. a "system" configuration file, `etc/my_app.conf`, `n = 2`, `a = 1`, `b = 6`,
15+
1. optionally, a configurtion file specified as a command line option, i.e.,
16+
`--conf my_app.conf`, `n = 3`, `a = 2`,
17+
1. command line options.
18+
19+
## What is it?
20+
1. `my_apps.py`: Python script to print random integer values.
21+
1. `etc/my_app.conf`: "system" level configuration file.
22+
1. `my_app.conf`: optional "user" level configuration file.
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[defaults]
2+
n = 2
3+
a = 1
4+
b = 6

source-code/application/my_app.conf

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[defaults]
2+
n = 3
3+
a = 2

source-code/application/my_app.py

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env python
2+
3+
from argparse import ArgumentParser
4+
from configparser import ConfigParser
5+
from pathlib import Path
6+
import random
7+
import sys
8+
9+
10+
def generate_data(n, a=0, b=1):
11+
return [random.randint(a, b) for _ in range(n)]
12+
13+
def main():
14+
arg_parser = ArgumentParser(description='test application')
15+
arg_parser.add_argument('--conf',
16+
help='configuration file to use')
17+
arg_parser.add_argument('--verbose', action='store_true',
18+
help='verbose output')
19+
options, remaining_options = arg_parser.parse_known_args()
20+
system_conf = Path.cwd() / 'etc' / 'my_app.conf'
21+
cfg = ConfigParser()
22+
cfg['defaults'] = {'n': '1', 'a': '0', 'b': '6'}
23+
if options.verbose:
24+
print('application default values:', file=sys.stderr)
25+
cfg.write(sys.stderr)
26+
if system_conf.exists():
27+
cfg.read('etc/my_app.conf')
28+
if options.verbose:
29+
print('system configuration file values:', file=sys.stderr)
30+
cfg.write(sys.stderr)
31+
else:
32+
print(f'missing configuration file {system_conf}', file=sys.stderr)
33+
if options.conf:
34+
cfg.read(options.conf)
35+
if options.verbose:
36+
print('user configuration file values:', file=sys.stderr)
37+
cfg.write(sys.stderr)
38+
cfg_opts = dict(cfg['defaults'])
39+
arg_parser.set_defaults(**cfg_opts)
40+
arg_parser.add_argument('n', type=int, nargs='?',
41+
help='number of random values to generate')
42+
arg_parser.add_argument('--a', type=int, help='smallest value')
43+
arg_parser.add_argument('--b', type=int, help='largest value')
44+
arg_parser.parse_args(remaining_options, options)
45+
if options.verbose:
46+
print('final options:', file=sys.stderr)
47+
print(f'n = {options.n}\na = {options.a}\nb = {options.b}', end='\n\n',
48+
file=sys.stderr)
49+
values = generate_data(options.n, a=options.a, b=options.b)
50+
print('\n'.join(str(value) for value in values))
51+
return 0
52+
53+
if __name__ == '__main__':
54+
status = main()
55+
sys.exit(status)

source-code/cmd/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Cmd
2+
23
Standard Python library framework to facilitate writing command line
34
driven interpreters.
45

56
## What is it?
7+
68
1. `simple.py`: a very simmple example that keeps track of a list of
79
friends. A friend is added by saying `hi` to her, and is removed by
810
saying `bye` to her. You can't say `hi` to someone who is your friend

source-code/code-evaluation/README.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
EvaluateCode
2-
============
1+
# Code evaluation
32

43
Python allows executino of Python source code at runtime. Although this
54
is a powerful feature, it should be used with extreme care, since it can
65
give rise to serious security issues.
76

8-
What is it?
9-
-----------
7+
## What is it?
8+
109
1. `evaluate.py`: short example that reads a code fragment, evaluates it,
1110
and prints all values of variables defined in that code fragment.
1211
Only variables of type `int`, '`float`, `str`, `bool` and `list` will

source-code/command-line-arguments/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# CommandLineArgs
1+
# Command line arguments
22

33
How to handle command line arguments in Python scripts.
44

source-code/config-parser/README.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
ConfigParser
2-
============
1+
# ConfigParser
32

43
ConfigParser is a module in Python's standard library to handle
54
configuration files easily.
65

7-
What is it?
8-
-----------
6+
## What is it?
7+
98
1. `config_reader.py`: reads a configuration file provided on the command
109
line, or `default.conf`. It prints the sections of the configuration
1110
files, and the key/value pairs defined therein.

source-code/file-system/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# OsFileSystem
1+
# File system
2+
23
Examples of code interacting with the operating system or performing
34
file system operations.
45

source-code/hydra/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ It support configuration file handling, command line arguments, logging,
77
multiruns and so on.
88

99
## What is it?
10+
1011
1. `gen_rand.py`: Python script to write random numbers to standard
1112
output.
1213
1. `conf/`: directory containing the configuration files.

source-code/logging/README.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
Logging
2-
=======
1+
# Logging
32

43
Using logging facilities rather than print or sys.stderr.write calls
54
adds a lot of flexibility to more complex programs. These facilities
65
are provided through Python's standard library.
76

8-
What is it?
9-
-----------
7+
## What is it?
8+
109
`log_it_all.py`: illustration of how to use the default logging mechanisms,
1110
how to set the log level the destination, and the log format
12-

source-code/paramiko/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# Paramiko
2+
23
Paramiko is a non-standard Python library for working with SSH. It can
34
be used to execute command on a remote host, or perform file transfers
45
using the SFTP protocol.
56

67
## What is it?
8+
79
1. `ssh.py`: module with some SSH connection utitlity functions, imported
810
in the scripts.
911
1. `ls.py`: performs an `ls` command for the specified directory on a

source-code/sched/README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Sched
2+
3+
Sometimes it can be useful to run functions at certain moments in time,
4+
similar to what cron does on Linux operatring systems.
5+
6+
## What is it?
7+
8+
* `cron.py`: example script using `schedule` that runs two tasks, one
9+
printing the time, and a computed value, the other updating the
10+
value to be printed. The first is scheduled every 2 seconds, the
11+
other every second.

source-code/sched/cron.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env python
2+
3+
import schedule
4+
import time
5+
6+
7+
def print_event(event):
8+
time_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
9+
print('{0}: {1}'.format(time_str, event['counter']))
10+
11+
12+
def set_event(event):
13+
event['counter'] += 1
14+
15+
if __name__ == '__main__':
16+
event = {'counter': 0}
17+
schedule.every(2).seconds.do(print_event, event)
18+
schedule.every().seconds.do(set_event, event)
19+
while True:
20+
schedule.run_pending()
21+
time.sleep(0.5)

0 commit comments

Comments
 (0)