Пример модуля с doctest
1 """Several functions of numbers theory.
2 """
3
4 import doctest
5 # import that
6
7 def fact1(n):
8 """Return n! (factorial of n) calculated recursively.
9
10 Examples:
11
12 >>> fact1(5)
13 120
14 >>> fact1(0)
15 1
16 """
17 if n == 0:
18 return 1
19 else:
20 return n * fact1(n - 1)
21
22 # def fact2
23 # ...
24
25 if __name__ == "__main__":
26 doctest.testmod()
Пример скрипта с doctest
1 """List files in the current directory.
2 """
3 import doctest
4 import optparse
5 # import ...
6 # more module imports here
7
8 def main(options, args):
9 """Choose action based on given parameters. List the required files"""
10 for file in glob.glob("*"):
11 print(file)
12
13 # def ...
14 # more functions here
15
16 if __name__ == "__main__":
17 parser = optparse.OptionParser(description=__doc__)
18 # ... -- more options here
19 parser.add_option("-v", "--verbose", action="store_true",
20 help="Be more verbose")
21 parser.add_option("-t", "--test", action="store_true",
22 help="Run self-tests. Print diagnostics on errors")
23 options, args = parser.parse_args()
24
25 if options.test:
26 doctest.testmod(verbose=options.verbose)
27 exit()
28
29 main(options, args)
Задачи
Прочитайте условиях всех задач. Выполните любые три из них (кроме последней) и последнюю задачу.
tr
Создайте (в репозиториии, ессно) скрипт tr.py, который заменяет в файле каждый пробел на табуляцию.
Скрипт принимает необязательный позиционный параметр: имя входного файла. Если параметр не указан, скрипт читает стандартный поток ввода.
Скрипт принимает один именованный параметр: -o / --outfile. Если параметр указан, скрипт записывает изменения в файл с таким именем. Если параметр не указан, скрипт возвращает изменения на стандартный вывод.
tr -- продолжение
Дополните скрипт tr.py так, чтобы он теперь принимал параметры:
- -f / --from-chars=CHARS
- -t / --to-chars=CHARS
- -d / --delete=CHARS
Если в значениях этих параметров встречаются обозначения вроде \n или \t, эти обозначения должны заменяться на соответствующие символы (перенос строки, табуляция). (Подсказка: посмотрите на "a\\nb".decode("string_escape") и "a\nb".encode("string_escape")).
Если один из парамтеров -f или -t указан, то значения этих параметров должны иметь одинаковую длину.
Если указаны параметры -f и -t, то скрипт во входном файле заменяет каждый из символов в строке from_chars на соответствующий символ из строки to_chars.
Если указан параметр -d, то скрипт удаляет из входного файла все символы, перечисленные его значении.
Например, tr -d '\r' -o new_ls.py ls.py распечатает файл ls.py на стандартный выв убрав из него все символы '\r', тем самым переведёт его из файла с DOS-овскими переносами строк в файл с UNIX-овскими переносами строк.
Или: tr -f '123456789' -t 'abcdefghij' получает текст со стандартного ввода (e.g, с клавиатуры), и пишет на стандартный вывод (e.g., на экран) то же текст, в котором цифра заменена на букву с соответсвующим номером.
Подсказка: решение этой задачи скорее всего будет либо простым длинным и понятным (нуу, гыгы), либо будет использовать string.maketrans.
cut-pdb.py
Создайте скрипт cut-pdb.py, который оставляет в PDB-файле только интересную нам часть.
Скрипт получает параметры:
- -a / --after: номер остатка, начиная с которого находится интересная нам часть
- -b / --before: номер остатка, начиная до котого длится интересная нам часть
- -c / --chain: имя цепи, которая нам интересна
Скрипт получает два позиционных параметра: имена входного и выходного PDB-файлов.
Скрипт пишет в выходной PDB-файл строки типа ATOM или HETATM из входного файла, которые удовлетворяют тем из условий, которые заданы.
Например, ./cut-pdb.py -c A in.pdb out.pdb оставит в out.pdb только цепочку A из in.pdb. Или: ./cut-pdb.py -a 20 -b 30 in.pdb out.pdb оставит в out.pdb только остатки с 20 по 30 в каждой из цепочек.
cut-pdb.py -- продолжение
Добавьте к скрипту cut-pdb.py параметр:
- -s / --selection.
Этот параметр описывает множество интересных частей в PDB-файле.
Пример: ./cut-pdb.py -s A:20-30,B:220-230 in.pdb out.pdb оставляет в out.pdb остатки с 20 по 30 в цепочке A и с 220 по 230 в цепочке B.
Описание формата параметра:
- параметр состоит из нескольких частей через запятую
- каждая часть состит из трёх частей, каждая из которых необязательная:
- имя цепочки + двоеточие
- начало диапазона (если оно указано, после него должен быть минус)
- конец диапазона (если он указан, перед ним должен быть минус)
Если вам кажется, что такой формат совершенно невозможно трудно разобрать, подсказка: научитесь пользоваться str.partition (например "123".partition("2")). Если Вы всё равно не можете понять, как это делать, вот готовое решение: /SelectionParser (предупреждение: на самом деле, оно очень простое! Второе предупреждение: даже если вы его утащите, написание к нему docstring и тестов лежит на ваших плечах)
grep
Напишите скрипт grep.py.
Скрипт получает обязательный параметр -e / --expression.
Скрипт получает в качестве позиционных параметров имена файлов, которые он будет читать. Если позиционных параметров не задано, скрипт будет читать стандартный поток ввода.
Скрипт читает входные файлы и выводит на стандартный поток вывода только те строки, в которых есть строка, заданная в --expression.
sort -- 1
Напишите скрипт sort.py.
Скрипт читает станратный поток ввода, и печатает на стандартный поток вывода его содержимое, упорядоченное построчно.
Пример:
...$ echo -e "2\n3\n1" | ./sort.py 1 2 3
(Команда ` echo -e "строка" ' выводит на стандартный поток вывода строку, заменяя \n на перенос строки. Таким образом, echo -e "2\n3\n1" печатает на стандартный вывод строку с текстом "2", строку "3" и строку "1")
sort -- 2
Дополните скрипт sort.py
Скрипт получает в качестве позиционных параметров имена входных файлов. Если позиционные параметры даны, скрипт читает все файлы, объединяет их содержимое и сортирует. Если не даны, скрипт ведёт себя так же, как в предыдущем задании.
Скрипт получает параметры:
-o / --outfile=FILE – имя выходного файла. Если этот параметр указан, отсортированное содержимое направляется в этот файл (вместо стандартного потока вывода).
-r / --reverse – если этот флаг указан, выдача сортируется в обратном порядке
uniq
Создайте скрипт uniq.py.
Скрипт получает один позиционный параметр: имя входного файла. Если он не указан, скрипт использует стандартный ввод. (Если указано больше одного параметра, это ошибка).
Скрипт читает входной файл, и если встречает несколько одинаковых строк подряд, печатает только одну копию такой строки.
uniq -- продолжение
Дополните скрипт uniq.py.
Теперь скрипт (кроме всего, что и раньше) получает флаги:
- -c / --count. Если этот флаг указан, то перед каждой строкой выдачи скрипт пишет, сколько раз подряд она была повторена.
- -i / --ignore-case. Если этот флаг указан, то строки сравниваются без различия заглавных и строчных букв.
docstring & doctest
Просмотрите все файлы у Вас в репозитории. Припишите к каждой функции docstring и, если это возможно, doctest.
Дабы упростить вам задачу, в моём репозитории с ответами лежат файлы test-*.txt, тесты из которых можно к себе скопировать. Лучше копировать только те тесты, которые вы понимате, как работают и что проверяют. Лучше тесты упростить (выбросить из них строку import и всякое упоминание имени модуля). Для queens.display лучше сделать свои тесты (я не мог использовать конкретный формат выдачи поля в моих тестах, поэтому выпендривался; вам же наоборот нужно, чтобы подсказке к функции приводился пример, как именно оно выглядит).
Формат PDB-файлов
Это только краткая выдержка из официального описания формата.
- файл состоит из записей
- каждая запись расположена на отдельной строке
- каждая запись имеет ширину не более 80 символов (что для нас не существенно)
- первые шесть символов записи определяют её тип
- ...
нас интересуют только записи типа ATOM и HETATM, эти записи состоят из полей ([позиции в строке1] описание):
- [1-6] тип записи - ATOM или HETATM
- [7-11] номер атома (int)
- [13-16] имя атома
- [17] индикатор альтернативного положения атома
- [18-20] название остатка
[22] идентификатор цепочки – chain_id
[23-26] номер остатка (int) – res_num
[27] insertion code2
- [31-38] координата по оси X (float), в ангстремах
- [39-46] координата по оси Y (float), в ангстремах
- [47-54] координата по оси Z (float), в ангстремах
- [55-60] коэффициент заполнения
- [61-66] температурный фактор
- [77-78] элемент
- [79-80] заряд атома