├── .gitignore ├── .readthedocs.yaml ├── .tx └── config ├── Makefile ├── README.rst ├── code ├── alltypes.py ├── argvtest.py ├── averagen.py ├── bars.py ├── continue.py ├── copyfile.py ├── countwords.py ├── design1.py ├── design2.py ├── design3.py ├── download_file.py ├── evaluateequ.py ├── evaluationexp.py ├── fibonacci1.py ├── fibonacci2.py ├── global.py ├── integer.py ├── integer2.py ├── investment.py ├── ircnicks.txt ├── lenexample.py ├── local.py ├── matrixmul.py ├── multiplication.py ├── mymodule │ ├── __init__.py │ └── bars.py ├── number100.py ├── palindrome.py ├── palindromefunc.py ├── powerseries.py ├── pymfactorial │ ├── LICENSE │ ├── README.md │ ├── pymfactorial │ │ ├── __init__.py │ │ └── fact.py │ └── pyproject.toml ├── quadraticequation.py ├── salesmansalary.py ├── sample.txt ├── sample2.txt ├── shorthand.py ├── showfile.py ├── sticks.py ├── student_teacher.py ├── students.py ├── students2.py ├── temperature.py ├── tempfile ├── testhundred.py └── theidemo.py ├── docs ├── Makefile ├── _static │ └── pym.png ├── _templates │ ├── sidebarintro.html │ └── sidebarlogo.html ├── _themes │ ├── LICENSE │ ├── README.rst │ ├── flask_theme_support.py │ ├── flask_theme_support.pyc │ └── kr │ │ ├── layout.html │ │ ├── relations.html │ │ ├── static │ │ ├── flasky.css_t │ │ └── small_flask.css │ │ └── theme.conf ├── classes.rst ├── click.rst ├── collections.rst ├── conf.py ├── datastructure.rst ├── editors.rst ├── exceptions.rst ├── file.rst ├── flask.rst ├── functions.rst ├── hardwaresimulation.rst ├── ifelse.rst ├── igd.rst ├── img │ ├── averagen.png │ ├── checkname_pyper.gif │ ├── code_disable_telemetry.png │ ├── code_install_python.png │ ├── code_welcome.png │ ├── cpx.gif │ ├── greater_notyping.gif │ ├── greater_withtyping.gif │ ├── hello_flask_Index.png │ ├── hello_flask_hello.png │ ├── helloworld.png │ ├── helloworld_pyper.png │ ├── how_to_get_device_simulator.gif │ ├── installing_devicesimulator.gif │ ├── investment.png │ ├── list_first.png │ ├── mu_running_code.gif │ ├── mu_starting.gif │ ├── oneneoatatime.gif │ ├── onoff.gif │ ├── red_light.gif │ ├── redthenblue.gif │ ├── rgb.gif │ ├── temperature.png │ ├── testhundred.png │ ├── textinput_pyper.gif │ ├── theidemo.gif │ ├── twocard_pyper.gif │ └── yellow_light.png ├── index.rst ├── installation.rst ├── looping.rst ├── loopingonhardware.rst ├── modules.rst ├── mu.rst ├── operatorsexpressions.rst ├── pep8.rst ├── projectstructure.rst ├── pypercard.rst ├── strings.rst ├── testing.rst ├── thebeginning.rst ├── typehinting.rst ├── variablesanddatatypes.rst └── virtualenv.rst ├── publican.cfg ├── requirements.txt └── scripts └── build_resources.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | .vscode 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # SageMath parsed files 85 | *.sage.py 86 | 87 | # Environments 88 | .env 89 | .venv 90 | env/ 91 | venv/ 92 | ENV/ 93 | env.bak/ 94 | venv.bak/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | .spyproject 99 | 100 | # Rope project settings 101 | .ropeproject 102 | 103 | # mkdocs documentation 104 | /site 105 | 106 | # mypy 107 | .mypy_cache/ 108 | 109 | # Vim 110 | *.swp 111 | 112 | *.gpg 113 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # File: .readthedocs.yaml 2 | 3 | version: 2 4 | 5 | # Set the OS, Python version and other tools you might need 6 | 7 | build: 8 | os: ubuntu-22.04 9 | tools: 10 | python: "3.12" 11 | # Build from the docs/ directory with Sphinx 12 | sphinx: 13 | configuration: docs/conf.py 14 | 15 | # Explicitly set the version of Python and its requirements 16 | python: 17 | install: 18 | - requirements: requirements.txt 19 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | lang_map = aln:aln-AL, ar:ar-SA, as:as-IN, bal:bal-PK, bg:bg-BG, bn:bn-BD, bn_IN:bn-IN, bs:bs-BA, ca:ca-ES, cs:cs-CZ, da:da-DK, de_CH:de-CH, de:de-DE, el:el-GR, en_GB:en-GB, es:es-ES, et:et-EE, fa:fa-IR, fi:fi-FI, fr:fr-FR, gu:gu-IN, he:he-IL, hi:hi-IN, hr:hr-HR, hu:hu-HU, id:id-ID, is:is-IS, it:it-IT, ja:ja-JP, kn:kn-IN, ko:ko-KR, lt:lt-LT, lv:lv-LV, mai:mai-IN, ml:ml-IN, mr:mr-IN, ms:ms-MY, nb:nb-NO, nds:nds-DE, nl:nl-NL, nn:nn-NO, or:or-IN, pa:pa-IN, pl:pl-PL, pt_BR:pt-BR, pt:pt-PT, ro:ro-RO, ru:ru-RU, si:si-LK, sk:sk-SK, sl:sl-SI, sq:sq-AL, sr:sr-RS, sr@latin:sr-Latn-RS, sv:sv-SE, ta:ta-IN, te:te-IN, tr:tr-TR, uk:uk-UA, ur:ur-PK, vi:vi-VN, zh_CN:zh-CN, zh_HK:zh-HK, zh_TW:zh-TW 4 | type = PO 5 | 6 | [pym.acknowledgment] 7 | file_filter = /acknowledgment.po 8 | source_file = pot/acknowledgment.pot 9 | source_lang = en 10 | [pym.Appendix] 11 | file_filter = /Appendix.po 12 | source_file = pot/Appendix.pot 13 | source_lang = en 14 | [pym.Author_Group] 15 | file_filter = /Author_Group.po 16 | source_file = pot/Author_Group.pot 17 | source_lang = en 18 | [pym.Book_Info] 19 | file_filter = /Book_Info.po 20 | source_file = pot/Book_Info.pot 21 | source_lang = en 22 | [pym.Chapter] 23 | file_filter = /Chapter.po 24 | source_file = pot/Chapter.pot 25 | source_lang = en 26 | [pym.classes] 27 | file_filter = /classes.po 28 | source_file = pot/classes.pot 29 | source_lang = en 30 | [pym.datastructure] 31 | file_filter = /datastructure.po 32 | source_file = pot/datastructure.pot 33 | source_lang = en 34 | [pym.file] 35 | file_filter = /file.po 36 | source_file = pot/file.pot 37 | source_lang = en 38 | [pym.functions] 39 | file_filter = /functions.po 40 | source_file = pot/functions.pot 41 | source_lang = en 42 | [pym.ifelse] 43 | file_filter = /ifelse.po 44 | source_file = pot/ifelse.pot 45 | source_lang = en 46 | [pym.installation] 47 | file_filter = /installation.po 48 | source_file = pot/installation.pot 49 | source_lang = en 50 | [pym.LegalNotice] 51 | file_filter = /LegalNotice.po 52 | source_file = pot/LegalNotice.pot 53 | source_lang = en 54 | [pym.looping] 55 | file_filter = /looping.po 56 | source_file = pot/looping.pot 57 | source_lang = en 58 | [pym.modules] 59 | file_filter = /modules.po 60 | source_file = pot/modules.pot 61 | source_lang = en 62 | [pym.operatorsexpressions] 63 | file_filter = /operatorsexpressions.po 64 | source_file = pot/operatorsexpressions.pot 65 | source_lang = en 66 | [pym.Preface] 67 | file_filter = /Preface.po 68 | source_file = pot/Preface.pot 69 | source_lang = en 70 | [pym.Python_for_you_and_me] 71 | file_filter = /Python_for_you_and_me.po 72 | source_file = pot/Python_for_you_and_me.pot 73 | source_lang = en 74 | [pym.Revision_History] 75 | file_filter = /Revision_History.po 76 | source_file = pot/Revision_History.pot 77 | source_lang = en 78 | [pym.strings] 79 | file_filter = /strings.po 80 | source_file = pot/strings.pot 81 | source_lang = en 82 | [pym.thebeginning] 83 | file_filter = /thebeginning.po 84 | source_file = pot/thebeginning.pot 85 | source_lang = en 86 | [pym.variablesanddatatypes] 87 | file_filter = /variablesanddatatypes.po 88 | source_file = pot/variablesanddatatypes.pot 89 | source_lang = en 90 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #Makefile for pythonforyouandme 2 | 3 | XML_LANG = en-US 4 | DOCNAME = pythonforyouandme 5 | PRODUCT = Documentation 6 | #BRAND = FIX_ME! 7 | 8 | #OTHER_LANGS = as-IN bn-IN de-DE es-ES fr-FR gu-IN hi-IN it-IT ja-JP kn-IN ko-KR ml-IN mr-IN or-IN pa-IN pt-BR ru-RU si-LK ta-IN te-IN zh-CN zh-TW 9 | OTHER_LANGS = ml-IN zh-CN 10 | TRANSLATIONS = $(XML_LANG) $(OTHER_LANGS) 11 | 12 | COMMON_CONFIG = /usr/share/publican 13 | include $(COMMON_CONFIG)/make/Makefile.common 14 | 15 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Python for you and me 2 | ===================== 3 | A fast paced Python book for students. 4 | 5 | Read it `here `_. 6 | -------------------------------------------------------------------------------- /code/alltypes.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple, Sequence, Optional 2 | 3 | values: List[int] = [] 4 | city: int = 350 # The city code, not a name 5 | 6 | 7 | # This function returns a Tuple of two values, a str and an int 8 | def get_details() -> Tuple[str, int]: 9 | return "Python", 5 10 | 11 | # The following is an example of Tuple unpacking 12 | name: str 13 | marks: int 14 | name, marks = get_details() 15 | 16 | 17 | def print_all(values: Sequence) -> None: 18 | for v in values: 19 | print(v) 20 | 21 | 22 | print_all([1,2,3]) 23 | print_all({"name": "kushal", "class": 5}) 24 | # alltypes.py:23: error: Argument 1 to "print_all" has incompatible type Dict[str, object]; expected Sequence[Any] 25 | # But running the code will give us no error with wrong output 26 | 27 | def add_ten(number: Optional[int] = None) -> int: 28 | if number: 29 | return number + 10 30 | else: 31 | return 42 32 | 33 | print(add_ten()) 34 | print(add_ten(12)) -------------------------------------------------------------------------------- /code/argvtest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | print "First value", sys.argv[0] 4 | print "All values" 5 | for i, x in enumerate(sys.argv): 6 | print i, x 7 | -------------------------------------------------------------------------------- /code/averagen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | N = 10 4 | sum = 0 5 | count = 0 6 | while count < N: 7 | number = float(input("")) 8 | sum = sum + number 9 | count = count + 1 10 | average = float(sum) / N 11 | print("N = %d , Sum = %f" % (N, sum)) 12 | print("Average = %f" % average) 13 | -------------------------------------------------------------------------------- /code/bars.py: -------------------------------------------------------------------------------- 1 | """ 2 | Bars Module 3 | ============ 4 | 5 | This is an example module which provides different ways to print bars. 6 | 7 | """ 8 | 9 | ANSWER = 42 10 | 11 | 12 | def starbar(num): 13 | """ 14 | Prints a bar with * 15 | 16 | :arg num: Length of the bar 17 | 18 | """ 19 | print("*" * num) 20 | 21 | 22 | def hashbar(num): 23 | """ 24 | Prints a bar with # 25 | 26 | :arg num: Length of the bar 27 | 28 | """ 29 | print("#" * num) 30 | 31 | 32 | def simplebar(num): 33 | """ 34 | Prints a bar with - 35 | 36 | :arg num: Length of the bar 37 | 38 | """ 39 | print("-" * num) 40 | 41 | 42 | print(ANSWER) 43 | -------------------------------------------------------------------------------- /code/continue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | while True: 4 | n = int(raw_input("Please enter an Integer: ")) 5 | if n < 0: 6 | continue #this will take the execution back to the starting of the loop 7 | elif n == 0: 8 | break 9 | print "Square is ", n ** 2 10 | print "Goodbye" 11 | -------------------------------------------------------------------------------- /code/copyfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | if len(sys.argv) < 3: 4 | print "Wrong parameter" 5 | print "./copyfile.py file1 file2" 6 | sys.exit(1) 7 | f1 = open(sys.argv[1]) 8 | s = f1.read() 9 | f1.close() 10 | f2 = open(sys.argv[2], 'w') 11 | f2.write(s) 12 | f2.close() 13 | 14 | -------------------------------------------------------------------------------- /code/countwords.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | s = raw_input("Enter a line: ") 3 | print "The number of words in the line are %d" % (len(s.split(" "))) 4 | -------------------------------------------------------------------------------- /code/design1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | row = int(raw_input("Enter the number of rows: ")) 3 | n = row 4 | while n >= 0: 5 | x = "*" * n 6 | print x 7 | n -= 1 8 | -------------------------------------------------------------------------------- /code/design2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | n = int(raw_input("Enter the number of rows: ")) 3 | i = 1 4 | while i <= n: 5 | print "*" * i 6 | i += 1 7 | -------------------------------------------------------------------------------- /code/design3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | row = int(raw_input("Enter the number of rows: ")) 3 | n = row 4 | while n >= 0: 5 | x = "*" * n 6 | y = " " * (row - n) 7 | print y + x 8 | n -= 1 9 | -------------------------------------------------------------------------------- /code/download_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import os.path 4 | import requests 5 | 6 | def download(url): 7 | '''Download the given url and saves it to the current directory. 8 | 9 | :arg url: URL of the file to be downloaded. 10 | ''' 11 | req = requests.get(url) 12 | # First let us check non existing files. 13 | if req.status_code == 404: 14 | print('No such file found at %s' % url) 15 | return 16 | filename = url.split('/')[-1] 17 | with open(filename, 'wb') as fobj: 18 | fobj.write(req.content) 19 | print("Download over.") 20 | 21 | if __name__ == '__main__': 22 | url = input('Enter a URL:') 23 | download(url) 24 | -------------------------------------------------------------------------------- /code/evaluateequ.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | sum = 0.0 3 | for i in range(1, 11): 4 | sum += 1.0 / i 5 | print "%2d %10.4f" % (i , sum) 6 | -------------------------------------------------------------------------------- /code/evaluationexp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | a = 9 3 | b = 12 4 | c = 3 5 | x = a -b / 3 + c * 2 -1 6 | y = a -b / (3 + c) * (2 -1) 7 | z = a - (b / (3 +c) * 2) -1 8 | 9 | print "X = ", x 10 | print "Y = ", y 11 | print "Z = ", z 12 | -------------------------------------------------------------------------------- /code/fibonacci1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | a, b = 0, 1 3 | while b < 100: 4 | print b 5 | a, b = b, a + b 6 | -------------------------------------------------------------------------------- /code/fibonacci2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | a, b = 0, 1 3 | while b < 100: 4 | print b, 5 | a, b = b, a + b 6 | -------------------------------------------------------------------------------- /code/global.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | def change(b): 3 | global a 4 | a = 90 5 | print a 6 | 7 | a = 9 8 | print "Before the function call ", a 9 | print "inside change function", 10 | change(a) 11 | print "After the function call ", a 12 | -------------------------------------------------------------------------------- /code/integer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | days = int(raw_input("Enter days: ")) 3 | months = days / 30 4 | days = days % 30 5 | print "Months = %d Days = %d" % (months, days) 6 | -------------------------------------------------------------------------------- /code/integer2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | days = int(raw_input("Enter days: ")) 3 | print "Months = %d Days = %d" % (divmod(days, 30)) 4 | -------------------------------------------------------------------------------- /code/investment.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | amount = float(input("Enter amount: ")) 4 | inrate = float(input("Enter Interest rate: ")) 5 | period = int(input("Enter period: ")) 6 | value = 0 7 | year = 1 8 | while year <= period: 9 | value = amount + (inrate * amount) 10 | print("Year %d Rs. %.2f" % (year, value)) 11 | amount = value 12 | year = year + 1 13 | -------------------------------------------------------------------------------- /code/ircnicks.txt: -------------------------------------------------------------------------------- 1 | powerpork 2 | indradg 3 | mishti 4 | sm|CPU 5 | -------------------------------------------------------------------------------- /code/lenexample.py: -------------------------------------------------------------------------------- 1 | class Foo: 2 | 3 | def __init__(self, length=5): 4 | self.length = 5 5 | 6 | def __len__(self): 7 | return self.length 8 | 9 | 10 | f = Foo() 11 | length = len(f) 12 | print(f"Length of the f object is {length}") -------------------------------------------------------------------------------- /code/local.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | def change(a): 5 | a = 90 6 | print(f"Inside of the change function {a}") 7 | 8 | 9 | a = 9 10 | print(f"Before the function call {a}") 11 | change(a) 12 | print(f"After the function call {a}") 13 | -------------------------------------------------------------------------------- /code/matrixmul.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | n = int(raw_input("Enter the value of n: ")) 3 | print "Enter values for the Matrix A" 4 | a = [] 5 | for i in range(0, n): 6 | a.append([int(x) for x in raw_input("").split(" ")]) 7 | 8 | print "Enter values for the Matrix B" 9 | b = [] 10 | for i in range(0, n): 11 | b.append([int(x) for x in raw_input("").split(" ")]) 12 | c = [] 13 | for i in range(0, n): 14 | c.append([sum([a[i][k] * b[k][j] for k in range(0,n)]) for j in range (0,n)]) 15 | print "After matrix multiplication" 16 | print "-" * 10 * n 17 | for x in c: 18 | for y in x: 19 | print "%5d" % y, 20 | print "" 21 | print "-" * 10 * n 22 | -------------------------------------------------------------------------------- /code/multiplication.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | i = 1 3 | print "-" * 50 4 | while i < 11: 5 | n = 1 6 | while n <= 10: 7 | print "%4d" % (i * n), 8 | n += 1 9 | print "" 10 | i += 1 11 | print "-" * 50 12 | -------------------------------------------------------------------------------- /code/mymodule/__init__.py: -------------------------------------------------------------------------------- 1 | import mymodule.bars as bars 2 | from mymodule.bars import simplebar 3 | __all__ = [bars, simplebar] 4 | 5 | -------------------------------------------------------------------------------- /code/mymodule/bars.py: -------------------------------------------------------------------------------- 1 | """ 2 | Bars Module 3 | ============ 4 | 5 | This is an example module which provides different ways to print bars. 6 | 7 | """ 8 | 9 | ANSWER = 42 10 | 11 | 12 | def starbar(num): 13 | """ 14 | Prints a bar with * 15 | 16 | :arg num: Length of the bar 17 | 18 | """ 19 | print("*" * num) 20 | 21 | 22 | def hashbar(num): 23 | """ 24 | Prints a bar with # 25 | 26 | :arg num: Length of the bar 27 | 28 | """ 29 | print("#" * num) 30 | 31 | 32 | def simplebar(num): 33 | """ 34 | Prints a bar with - 35 | 36 | :arg num: Length of the bar 37 | 38 | """ 39 | print("-" * num) 40 | 41 | 42 | print(ANSWER) 43 | -------------------------------------------------------------------------------- /code/number100.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | number = int(raw_input("Enter a number: ")) 3 | if number < 100: 4 | print "The number is less than 100" 5 | else: 6 | print "The number is greater than 100" 7 | -------------------------------------------------------------------------------- /code/palindrome.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | s = raw_input("Please eneter a string: ") 3 | z = [x for x in s] 4 | z.reverse() 5 | if s == "".join(z): 6 | print "The string is a palindrome" 7 | else: 8 | print "The string is not a palindrome" 9 | -------------------------------------------------------------------------------- /code/palindromefunc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | def palindrome(s): 4 | z = s 5 | z = [x for x in z] 6 | z.reverse() 7 | if s == "".join(z): 8 | return True 9 | else: 10 | return False 11 | 12 | s = raw_input("Enter a string: ") 13 | if palindrome(s): 14 | print "Yay a palindrome" 15 | else: 16 | print "Oh no, not a palindrome" 17 | -------------------------------------------------------------------------------- /code/powerseries.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | x = float(raw_input("Enter the value of x: ")) 3 | n = term = num = 1 4 | sum = 1.0 5 | while n <= 100: 6 | term *= x / n 7 | sum += term 8 | n += 1 9 | if term < 0.0001: 10 | break 11 | print "No of Times= %d and Sum= %f" % (n, sum) 12 | 13 | 14 | -------------------------------------------------------------------------------- /code/pymfactorial/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Kushal Das 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /code/pymfactorial/README.md: -------------------------------------------------------------------------------- 1 | An example project to teach packaging using [flit](https://flit.pypa.io/en/stable/). 2 | Part of the [pym book](https://pymbook.readthedocs.io/en/latest/projectstructure.html). 3 | -------------------------------------------------------------------------------- /code/pymfactorial/pymfactorial/__init__.py: -------------------------------------------------------------------------------- 1 | "pymfactorial module and command line tool" 2 | 3 | __version__ = "0.1.0" 4 | 5 | from .fact import factorial, cli 6 | __all__ = [factorial, cli] 7 | -------------------------------------------------------------------------------- /code/pymfactorial/pymfactorial/fact.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | def factorial(num): 5 | """ 6 | Returns the factorial value of the given number. 7 | 8 | :arg num: Interger value of whose factorial we will calculate. 9 | 10 | :return: The value of the the factorial or -1 in case negative value passed. 11 | """ 12 | if num >= 0: 13 | if num == 0: 14 | return 1 15 | return num * factorial(num -1) 16 | else: 17 | return -1 18 | 19 | 20 | def cli(): 21 | "The command line entry point" 22 | number = int(sys.argv[1]) 23 | print(f"Factorial is {factorial(number)}") 24 | 25 | -------------------------------------------------------------------------------- /code/pymfactorial/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["flit_core >=3.2,<4"] 3 | build-backend = "flit_core.buildapi" 4 | 5 | [project] 6 | name = "pymfactorial" 7 | authors = [{name = "Kushal Das", email = "mail@kushaldas.in"}] 8 | readme = "README.md" 9 | license = {file = "LICENSE"} 10 | classifiers = ["License :: OSI Approved :: MIT License"] 11 | dynamic = ["version", "description"] 12 | 13 | [project.urls] 14 | Home = "https://github.com/kushaldas/pym" 15 | 16 | [project.scripts] 17 | myfact = "pymfactorial:cli" 18 | 19 | [tool.flit.sdist] 20 | include = ["license", "readme.md"] 21 | 22 | 23 | -------------------------------------------------------------------------------- /code/quadraticequation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import math 3 | 4 | a = int(raw_input("Enter value of a: ")) 5 | b = int(raw_input("Enter value of b: ")) 6 | c = int(raw_input("Enter value of c: ")) 7 | d = b * b - 4 * a * c 8 | if d < 0: 9 | print "ROOTS are imaginary" 10 | else: 11 | root1 = (-b + math.sqrt(d)) / (2.0 * a) 12 | root2 = (-b - math.sqrt(d)) / (2.0 * a) 13 | 14 | -------------------------------------------------------------------------------- /code/salesmansalary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | basic_salary = 1500 3 | bonus_rate = 200 4 | commision_rate = 0.02 5 | numberofcamera = int(raw_input("Enter the number of inputs sold: ")) 6 | price = float(raw_input("Enter the total prices: ")) 7 | bonus = (bonus_rate * numberofcamera) 8 | commision = (commision_rate * numberofcamera * price) 9 | 10 | print "Bonus = %6.2f" % bonus 11 | print "Commision = %6.2f" % commision 12 | print "Gross salary = %6.2f" % ( basic_salary + bonus + commision) 13 | -------------------------------------------------------------------------------- /code/sample.txt: -------------------------------------------------------------------------------- 1 | I love Python 2 | Pradeepto loves KDE 3 | Sankarshan loves Openoffice 4 | -------------------------------------------------------------------------------- /code/sample2.txt: -------------------------------------------------------------------------------- 1 | powerpork 2 | indradg 3 | mishti 4 | sm|CPU 5 | -------------------------------------------------------------------------------- /code/shorthand.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | N = 100 3 | a = 2 4 | while a < N: 5 | print "%d" % a 6 | a *= a 7 | -------------------------------------------------------------------------------- /code/showfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | name = raw_input("Enter the filename: ") 3 | f = open(name) 4 | print f.read() 5 | f.close() 6 | -------------------------------------------------------------------------------- /code/sticks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | sticks = 21 4 | 5 | print "There are 21 sticks, you can take 1-4 number of sticks at a time." 6 | print "Whoever will take the last stick will loose" 7 | 8 | while True: 9 | print "Sticks left: " , sticks 10 | sticks_taken = int(raw_input("Take sticks(1-4):")) 11 | if sticks == 1: 12 | print "You took the last stick, you loose" 13 | break 14 | if sticks_taken >=5 or sticks_taken <=0: 15 | print "Wrong choice" 16 | continue 17 | print "Computer took: " , (5 - sticks_taken) , "\n\n" 18 | sticks -= 5 19 | 20 | -------------------------------------------------------------------------------- /code/student_teacher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | class Person(object): 4 | """ 5 | Returns a ```Person``` object with given name. 6 | 7 | """ 8 | def __init__(self,name): 9 | self.name = name 10 | 11 | def get_details(self): 12 | "Returns a string containing name of the person" 13 | return self.name 14 | 15 | 16 | class Student(Person): 17 | """ 18 | Returns a ```Student``` object, takes 3 arguments, name, branch, year. 19 | 20 | """ 21 | def __init__(self,name,branch,year): 22 | Person.__init__(self,name) 23 | self.branch = branch 24 | self.year = year 25 | 26 | def get_details(self): 27 | "Returns a string containing student's details." 28 | return "%s studies %s and is in %s year." % (self.name, self.branch, self.year) 29 | 30 | 31 | class Teacher(Person): 32 | """ 33 | Returns a ```Teacher``` object, takes a list of strings (list of papers) as 34 | argument. 35 | """ 36 | def __init__(self, name, papers): 37 | Person.__init__(self, name) 38 | self.papers = papers 39 | 40 | def get_details(self): 41 | return "%s teaches %s" % (self.name, ','.join(self.papers)) 42 | 43 | 44 | person1 = Person('Rahul') 45 | student1 = Student('Kushal', 'CSE', 2005) 46 | teacher1 = Teacher('Prashad', ['C', 'C++']) 47 | 48 | print person1.get_details() 49 | print student1.get_details() 50 | print teacher1.get_details() 51 | 52 | -------------------------------------------------------------------------------- /code/students.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | n = int(raw_input("Enter the number of students:")) 3 | data = {} # here we will store the data 4 | languages = ('Physics', 'Maths', 'History') #all languages 5 | for i in range(0, n): #for the n number of students 6 | name = raw_input('Enter the name of the student %d: ' % (i + 1)) #Get the name of the student 7 | marks = [] 8 | for x in languages: 9 | marks.append(int(raw_input('Enter marks of %s: ' % x))) #Get the marks for languages 10 | data[name] = marks 11 | 12 | for x, y in data.iteritems(): 13 | total = sum(y) 14 | print "%s 's total marks %d" % (x, total) 15 | if total < 120: 16 | print "%s failed :(" % x 17 | else: 18 | print "%s passed :)" % y 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /code/students2.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | class Student: 4 | 5 | def __init__(self, name: str, batch: int, branch: str, roll: int) -> None: 6 | self.name = name 7 | self.batch = batch 8 | self.branch = branch 9 | self.roll = roll 10 | self.semester: str = None 11 | self.papers: Dict[str, int] = {} 12 | 13 | def is_passed(self) -> bool: 14 | "To find if the student has pass the exam in the current semester" 15 | for k, v in self.papers.items(): 16 | if v < 34: 17 | return False 18 | 19 | return True 20 | 21 | 22 | def total_score(self) -> int: 23 | "Returns the total score of the student" 24 | total = 0 25 | for k, v in self.papers.items(): 26 | total += v 27 | 28 | return total 29 | 30 | 31 | std1: Student = Student("Kushal", 2005, "cse", 123) 32 | std2 = Student("Sayan", 2005, "cse", 121) 33 | std3 = Student("Anwesha", 2005, "law", 122) 34 | 35 | std1.papers = {"english": 78, "math": 82, "science": 77} 36 | std2.papers = {"english": 80, "math": 92, "science": 78} 37 | std3.papers = {"english": 82, "math": 87, "science": 77} 38 | 39 | for std in [std1, std2, std3]: 40 | print("Passed: {0}. The toral score of {1} is {2}".format(std.is_passed(), std.name, std.total_score())) 41 | 42 | std1 = {"type": "studnet"} -------------------------------------------------------------------------------- /code/temperature.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | fahrenheit = 0.0 4 | print("Fahrenheit Celsius") 5 | while fahrenheit <= 250: 6 | celsius = (fahrenheit - 32.0) / 1.8 # Here we calculate the Celsius value 7 | print("%5.1f %7.2f" % (fahrenheit, celsius)) 8 | fahrenheit = fahrenheit + 25 9 | -------------------------------------------------------------------------------- /code/tempfile: -------------------------------------------------------------------------------- 1 | 0123456789abcdef -------------------------------------------------------------------------------- /code/testhundred.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | number = int(input("Enter an integer: ")) 4 | if number < 100: 5 | print("Your number is smaller than 100") 6 | else: 7 | print("Your number is greater than 100") 8 | -------------------------------------------------------------------------------- /code/theidemo.py: -------------------------------------------------------------------------------- 1 | a = 10 2 | name = "kushal" 3 | c = 44 4 | a = 20 5 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Pythonforyouandme.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Pythonforyouandme.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Pythonforyouandme" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Pythonforyouandme" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /docs/_static/pym.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/_static/pym.png -------------------------------------------------------------------------------- /docs/_templates/sidebarintro.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |

8 | 10 |

11 | 12 |

13 | pym is a book to learn Python. 14 | It targets people who are completely 15 | new to the language. 16 |

17 | 18 |

19 | Feedback is greatly appreciated. If you have any questions, comments, 20 | random praise, or anonymous threats, 21 | shoot me an email. 22 |

23 | 24 | 25 |

Useful Links

26 | 30 | 44 | -------------------------------------------------------------------------------- /docs/_templates/sidebarlogo.html: -------------------------------------------------------------------------------- 1 | 6 |

7 | 9 |

10 | 11 |

12 | pym is a book to learn Python. 13 | It targets people who are completely 14 | new to the language. 15 |

16 | 30 | -------------------------------------------------------------------------------- /docs/_themes/LICENSE: -------------------------------------------------------------------------------- 1 | Modifications: 2 | 3 | Copyright (c) 2010 Kenneth Reitz. 4 | 5 | 6 | Original Project: 7 | 8 | Copyright (c) 2010 by Armin Ronacher. 9 | 10 | 11 | Some rights reserved. 12 | 13 | Redistribution and use in source and binary forms of the theme, with or 14 | without modification, are permitted provided that the following conditions 15 | are met: 16 | 17 | * Redistributions of source code must retain the above copyright 18 | notice, this list of conditions and the following disclaimer. 19 | 20 | * Redistributions in binary form must reproduce the above 21 | copyright notice, this list of conditions and the following 22 | disclaimer in the documentation and/or other materials provided 23 | with the distribution. 24 | 25 | * The names of the contributors may not be used to endorse or 26 | promote products derived from this software without specific 27 | prior written permission. 28 | 29 | We kindly ask you to only use these themes in an unmodified manner just 30 | for Flask and Flask-related products, not for unrelated projects. If you 31 | like the visual style and want to use it for your own projects, please 32 | consider making some larger changes to the themes (such as changing 33 | font faces, sizes, colors or margins). 34 | 35 | THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 36 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 38 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 39 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 40 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 41 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 42 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 43 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 44 | ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE 45 | POSSIBILITY OF SUCH DAMAGE. 46 | -------------------------------------------------------------------------------- /docs/_themes/README.rst: -------------------------------------------------------------------------------- 1 | krTheme Sphinx Style 2 | ==================== 3 | 4 | This repository contains sphinx styles Kenneth Reitz uses in most of 5 | his projects. It is a drivative of Mitsuhiko's themes for Flask and Flask related 6 | projects. To use this style in your Sphinx documentation, follow 7 | this guide: 8 | 9 | 1. put this folder as _themes into your docs folder. Alternatively 10 | you can also use git submodules to check out the contents there. 11 | 12 | 2. add this to your conf.py: :: 13 | 14 | sys.path.append(os.path.abspath('_themes')) 15 | html_theme_path = ['_themes'] 16 | html_theme = 'kr' 17 | 18 | The following themes exist: 19 | 20 | **kr** 21 | the standard flask documentation theme for large projects 22 | 23 | **kr_small** 24 | small one-page theme. Intended to be used by very small addon libraries. 25 | 26 | -------------------------------------------------------------------------------- /docs/_themes/flask_theme_support.py: -------------------------------------------------------------------------------- 1 | # flasky extensions. flasky pygments style based on tango style 2 | from pygments.style import Style 3 | from pygments.token import Keyword, Name, Comment, String, Error, \ 4 | Number, Operator, Generic, Whitespace, Punctuation, Other, Literal 5 | 6 | 7 | class FlaskyStyle(Style): 8 | background_color = "#f8f8f8" 9 | default_style = "" 10 | 11 | styles = { 12 | # No corresponding class for the following: 13 | #Text: "", # class: '' 14 | Whitespace: "underline #f8f8f8", # class: 'w' 15 | Error: "#a40000 border:#ef2929", # class: 'err' 16 | Other: "#000000", # class 'x' 17 | 18 | Comment: "italic #8f5902", # class: 'c' 19 | Comment.Preproc: "noitalic", # class: 'cp' 20 | 21 | Keyword: "bold #004461", # class: 'k' 22 | Keyword.Constant: "bold #004461", # class: 'kc' 23 | Keyword.Declaration: "bold #004461", # class: 'kd' 24 | Keyword.Namespace: "bold #004461", # class: 'kn' 25 | Keyword.Pseudo: "bold #004461", # class: 'kp' 26 | Keyword.Reserved: "bold #004461", # class: 'kr' 27 | Keyword.Type: "bold #004461", # class: 'kt' 28 | 29 | Operator: "#582800", # class: 'o' 30 | Operator.Word: "bold #004461", # class: 'ow' - like keywords 31 | 32 | Punctuation: "bold #000000", # class: 'p' 33 | 34 | # because special names such as Name.Class, Name.Function, etc. 35 | # are not recognized as such later in the parsing, we choose them 36 | # to look the same as ordinary variables. 37 | Name: "#000000", # class: 'n' 38 | Name.Attribute: "#c4a000", # class: 'na' - to be revised 39 | Name.Builtin: "#004461", # class: 'nb' 40 | Name.Builtin.Pseudo: "#3465a4", # class: 'bp' 41 | Name.Class: "#000000", # class: 'nc' - to be revised 42 | Name.Constant: "#000000", # class: 'no' - to be revised 43 | Name.Decorator: "#888", # class: 'nd' - to be revised 44 | Name.Entity: "#ce5c00", # class: 'ni' 45 | Name.Exception: "bold #cc0000", # class: 'ne' 46 | Name.Function: "#000000", # class: 'nf' 47 | Name.Property: "#000000", # class: 'py' 48 | Name.Label: "#f57900", # class: 'nl' 49 | Name.Namespace: "#000000", # class: 'nn' - to be revised 50 | Name.Other: "#000000", # class: 'nx' 51 | Name.Tag: "bold #004461", # class: 'nt' - like a keyword 52 | Name.Variable: "#000000", # class: 'nv' - to be revised 53 | Name.Variable.Class: "#000000", # class: 'vc' - to be revised 54 | Name.Variable.Global: "#000000", # class: 'vg' - to be revised 55 | Name.Variable.Instance: "#000000", # class: 'vi' - to be revised 56 | 57 | Number: "#990000", # class: 'm' 58 | 59 | Literal: "#000000", # class: 'l' 60 | Literal.Date: "#000000", # class: 'ld' 61 | 62 | String: "#4e9a06", # class: 's' 63 | String.Backtick: "#4e9a06", # class: 'sb' 64 | String.Char: "#4e9a06", # class: 'sc' 65 | String.Doc: "italic #8f5902", # class: 'sd' - like a comment 66 | String.Double: "#4e9a06", # class: 's2' 67 | String.Escape: "#4e9a06", # class: 'se' 68 | String.Heredoc: "#4e9a06", # class: 'sh' 69 | String.Interpol: "#4e9a06", # class: 'si' 70 | String.Other: "#4e9a06", # class: 'sx' 71 | String.Regex: "#4e9a06", # class: 'sr' 72 | String.Single: "#4e9a06", # class: 's1' 73 | String.Symbol: "#4e9a06", # class: 'ss' 74 | 75 | Generic: "#000000", # class: 'g' 76 | Generic.Deleted: "#a40000", # class: 'gd' 77 | Generic.Emph: "italic #000000", # class: 'ge' 78 | Generic.Error: "#ef2929", # class: 'gr' 79 | Generic.Heading: "bold #000080", # class: 'gh' 80 | Generic.Inserted: "#00A000", # class: 'gi' 81 | Generic.Output: "#888", # class: 'go' 82 | Generic.Prompt: "#745334", # class: 'gp' 83 | Generic.Strong: "bold #000000", # class: 'gs' 84 | Generic.Subheading: "bold #800080", # class: 'gu' 85 | Generic.Traceback: "bold #a40000", # class: 'gt' 86 | } 87 | -------------------------------------------------------------------------------- /docs/_themes/flask_theme_support.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/_themes/flask_theme_support.pyc -------------------------------------------------------------------------------- /docs/_themes/kr/layout.html: -------------------------------------------------------------------------------- 1 | {%- extends "basic/layout.html" %} 2 | {%- block extrahead %} 3 | {{ super() }} 4 | {% if theme_touch_icon %} 5 | 6 | {% endif %} 7 | 9 | 10 | {% endblock %} 11 | {%- block relbar2 %}{% endblock %} 12 | {%- block footer %} 13 | 26 | 27 | Fork me on GitHub 28 | 29 | 42 | 43 | {%- endblock %} 44 | -------------------------------------------------------------------------------- /docs/_themes/kr/relations.html: -------------------------------------------------------------------------------- 1 |

Related Topics

2 | 20 | -------------------------------------------------------------------------------- /docs/_themes/kr/static/flasky.css_t: -------------------------------------------------------------------------------- 1 | /* 2 | * flasky.css_t 3 | * ~~~~~~~~~~~~ 4 | * 5 | * :copyright: Copyright 2010 by Armin Ronacher. Modifications by Kenneth Reitz. 6 | * :license: Flask Design License, see LICENSE for details. 7 | */ 8 | 9 | {% set page_width = '940px' %} 10 | {% set sidebar_width = '220px' %} 11 | 12 | @import url("basic.css"); 13 | 14 | /* -- page layout ----------------------------------------------------------- */ 15 | 16 | body { 17 | font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro'; 18 | font-size: 17px; 19 | background-color: white; 20 | color: #000; 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | div.document { 26 | width: {{ page_width }}; 27 | margin: 30px auto 0 auto; 28 | } 29 | 30 | div.documentwrapper { 31 | float: left; 32 | width: 100%; 33 | } 34 | 35 | div.bodywrapper { 36 | margin: 0 0 0 {{ sidebar_width }}; 37 | } 38 | 39 | div.sphinxsidebar { 40 | width: {{ sidebar_width }}; 41 | } 42 | 43 | hr { 44 | border: 1px solid #B1B4B6; 45 | } 46 | 47 | div.body { 48 | background-color: #ffffff; 49 | color: #3E4349; 50 | padding: 0 30px 0 30px; 51 | } 52 | 53 | img.floatingflask { 54 | padding: 0 0 10px 10px; 55 | float: right; 56 | } 57 | 58 | div.footer { 59 | width: {{ page_width }}; 60 | margin: 20px auto 30px auto; 61 | font-size: 14px; 62 | color: #888; 63 | text-align: right; 64 | } 65 | 66 | div.footer a { 67 | color: #888; 68 | } 69 | 70 | div.related { 71 | display: none; 72 | } 73 | 74 | div.sphinxsidebar a { 75 | color: #444; 76 | text-decoration: none; 77 | border-bottom: 1px dotted #999; 78 | } 79 | 80 | div.sphinxsidebar a:hover { 81 | border-bottom: 1px solid #999; 82 | } 83 | 84 | div.sphinxsidebar { 85 | font-size: 14px; 86 | line-height: 1.5; 87 | } 88 | 89 | div.sphinxsidebarwrapper { 90 | padding: 18px 10px; 91 | } 92 | 93 | div.sphinxsidebarwrapper p.logo { 94 | padding: 0; 95 | margin: -10px 0 0 -20px; 96 | text-align: center; 97 | } 98 | 99 | div.sphinxsidebar h3, 100 | div.sphinxsidebar h4 { 101 | font-family: 'Garamond', 'Georgia', serif; 102 | color: #444; 103 | font-size: 24px; 104 | font-weight: normal; 105 | margin: 0 0 5px 0; 106 | padding: 0; 107 | } 108 | 109 | div.sphinxsidebar h4 { 110 | font-size: 20px; 111 | } 112 | 113 | div.sphinxsidebar h3 a { 114 | color: #444; 115 | } 116 | 117 | div.sphinxsidebar p.logo a, 118 | div.sphinxsidebar h3 a, 119 | div.sphinxsidebar p.logo a:hover, 120 | div.sphinxsidebar h3 a:hover { 121 | border: none; 122 | } 123 | 124 | div.sphinxsidebar p { 125 | color: #555; 126 | margin: 10px 0; 127 | } 128 | 129 | div.sphinxsidebar ul { 130 | margin: 10px 0; 131 | padding: 0; 132 | color: #000; 133 | } 134 | 135 | div.sphinxsidebar input { 136 | border: 1px solid #ccc; 137 | font-family: 'Georgia', serif; 138 | font-size: 1em; 139 | } 140 | 141 | /* -- body styles ----------------------------------------------------------- */ 142 | 143 | a { 144 | color: #004B6B; 145 | text-decoration: underline; 146 | } 147 | 148 | a:hover { 149 | color: #6D4100; 150 | text-decoration: underline; 151 | } 152 | 153 | div.body h1, 154 | div.body h2, 155 | div.body h3, 156 | div.body h4, 157 | div.body h5, 158 | div.body h6 { 159 | font-family: 'Garamond', 'Georgia', serif; 160 | font-weight: normal; 161 | margin: 30px 0px 10px 0px; 162 | padding: 0; 163 | } 164 | 165 | div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } 166 | div.body h2 { font-size: 180%; } 167 | div.body h3 { font-size: 150%; } 168 | div.body h4 { font-size: 130%; } 169 | div.body h5 { font-size: 100%; } 170 | div.body h6 { font-size: 100%; } 171 | 172 | a.headerlink { 173 | color: #ddd; 174 | padding: 0 4px; 175 | text-decoration: none; 176 | } 177 | 178 | a.headerlink:hover { 179 | color: #444; 180 | background: #eaeaea; 181 | } 182 | 183 | div.body p, div.body dd, div.body li { 184 | line-height: 1.4em; 185 | } 186 | 187 | div.admonition { 188 | background: #fafafa; 189 | margin: 20px -30px; 190 | padding: 10px 30px; 191 | border-top: 1px solid #ccc; 192 | border-bottom: 1px solid #ccc; 193 | } 194 | 195 | div.admonition tt.xref, div.admonition a tt { 196 | border-bottom: 1px solid #fafafa; 197 | } 198 | 199 | dd div.admonition { 200 | margin-left: -60px; 201 | padding-left: 60px; 202 | } 203 | 204 | div.admonition p.admonition-title { 205 | font-family: 'Garamond', 'Georgia', serif; 206 | font-weight: normal; 207 | font-size: 24px; 208 | margin: 0 0 10px 0; 209 | padding: 0; 210 | line-height: 1; 211 | } 212 | 213 | div.admonition p.last { 214 | margin-bottom: 0; 215 | } 216 | 217 | div.highlight { 218 | background-color: white; 219 | } 220 | 221 | dt:target, .highlight { 222 | background: #FAF3E8; 223 | } 224 | 225 | div.note { 226 | background-color: #eee; 227 | border: 1px solid #ccc; 228 | } 229 | 230 | div.seealso { 231 | background-color: #ffc; 232 | border: 1px solid #ff6; 233 | } 234 | 235 | div.topic { 236 | background-color: #eee; 237 | } 238 | 239 | p.admonition-title { 240 | display: inline; 241 | } 242 | 243 | p.admonition-title:after { 244 | content: ":"; 245 | } 246 | 247 | pre, tt { 248 | font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 249 | font-size: 0.9em; 250 | } 251 | 252 | img.screenshot { 253 | } 254 | 255 | tt.descname, tt.descclassname { 256 | font-size: 0.95em; 257 | } 258 | 259 | tt.descname { 260 | padding-right: 0.08em; 261 | } 262 | 263 | img.screenshot { 264 | -moz-box-shadow: 2px 2px 4px #eee; 265 | -webkit-box-shadow: 2px 2px 4px #eee; 266 | box-shadow: 2px 2px 4px #eee; 267 | } 268 | 269 | table.docutils { 270 | border: 1px solid #888; 271 | -moz-box-shadow: 2px 2px 4px #eee; 272 | -webkit-box-shadow: 2px 2px 4px #eee; 273 | box-shadow: 2px 2px 4px #eee; 274 | } 275 | 276 | table.docutils td, table.docutils th { 277 | border: 1px solid #888; 278 | padding: 0.25em 0.7em; 279 | } 280 | 281 | table.field-list, table.footnote { 282 | border: none; 283 | -moz-box-shadow: none; 284 | -webkit-box-shadow: none; 285 | box-shadow: none; 286 | } 287 | 288 | table.footnote { 289 | margin: 15px 0; 290 | width: 100%; 291 | border: 1px solid #eee; 292 | background: #fdfdfd; 293 | font-size: 0.9em; 294 | } 295 | 296 | table.footnote + table.footnote { 297 | margin-top: -15px; 298 | border-top: none; 299 | } 300 | 301 | table.field-list th { 302 | padding: 0 0.8em 0 0; 303 | } 304 | 305 | table.field-list td { 306 | padding: 0; 307 | } 308 | 309 | table.footnote td.label { 310 | width: 0px; 311 | padding: 0.3em 0 0.3em 0.5em; 312 | } 313 | 314 | table.footnote td { 315 | padding: 0.3em 0.5em; 316 | } 317 | 318 | dl { 319 | margin: 0; 320 | padding: 0; 321 | } 322 | 323 | dl dd { 324 | margin-left: 30px; 325 | } 326 | 327 | blockquote { 328 | margin: 0 0 0 30px; 329 | padding: 0; 330 | } 331 | 332 | ul, ol { 333 | margin: 10px 0 10px 30px; 334 | padding: 0; 335 | } 336 | 337 | pre { 338 | background: #eee; 339 | padding: 7px 30px; 340 | margin: 15px -30px; 341 | line-height: 1.3em; 342 | } 343 | 344 | dl pre, blockquote pre, li pre { 345 | margin-left: -60px; 346 | padding-left: 60px; 347 | } 348 | 349 | dl dl pre { 350 | margin-left: -90px; 351 | padding-left: 90px; 352 | } 353 | 354 | tt { 355 | background-color: #ecf0f3; 356 | color: #222; 357 | /* padding: 1px 2px; */ 358 | } 359 | 360 | tt.xref, a tt { 361 | background-color: #FBFBFB; 362 | border-bottom: 1px solid white; 363 | } 364 | 365 | a.reference { 366 | text-decoration: none; 367 | border-bottom: 1px dotted #004B6B; 368 | } 369 | 370 | a.reference:hover { 371 | border-bottom: 1px solid #6D4100; 372 | } 373 | 374 | a.footnote-reference { 375 | text-decoration: none; 376 | font-size: 0.7em; 377 | vertical-align: top; 378 | border-bottom: 1px dotted #004B6B; 379 | } 380 | 381 | a.footnote-reference:hover { 382 | border-bottom: 1px solid #6D4100; 383 | } 384 | 385 | a:hover tt { 386 | background: #EEE; 387 | } 388 | 389 | 390 | @media screen and (max-width: 600px) { 391 | 392 | div.sphinxsidebar { 393 | display: none; 394 | } 395 | 396 | div.document { 397 | width: 100%; 398 | 399 | } 400 | 401 | div.documentwrapper { 402 | margin-left: 0; 403 | margin-top: 0; 404 | margin-right: 0; 405 | margin-bottom: 0; 406 | } 407 | 408 | div.bodywrapper { 409 | margin-top: 0; 410 | margin-right: 0; 411 | margin-bottom: 0; 412 | margin-left: 0; 413 | } 414 | 415 | ul { 416 | margin-left: 0; 417 | } 418 | 419 | .document { 420 | width: auto; 421 | } 422 | 423 | .footer { 424 | width: auto; 425 | } 426 | 427 | .bodywrapper { 428 | margin: 0; 429 | } 430 | 431 | .footer { 432 | width: auto; 433 | } 434 | 435 | .github { 436 | display: none; 437 | } 438 | 439 | } 440 | 441 | /* misc. */ 442 | 443 | .revsys-inline { 444 | display: none!important; 445 | } -------------------------------------------------------------------------------- /docs/_themes/kr/static/small_flask.css: -------------------------------------------------------------------------------- 1 | /* 2 | * small_flask.css_t 3 | * ~~~~~~~~~~~~~~~~~ 4 | * 5 | * :copyright: Copyright 2010 by Armin Ronacher. 6 | * :license: Flask Design License, see LICENSE for details. 7 | */ 8 | 9 | body { 10 | margin: 0; 11 | padding: 20px 30px; 12 | } 13 | 14 | div.documentwrapper { 15 | float: none; 16 | background: white; 17 | } 18 | 19 | div.sphinxsidebar { 20 | display: block; 21 | float: none; 22 | width: 102.5%; 23 | margin: 50px -30px -20px -30px; 24 | padding: 10px 20px; 25 | background: #333; 26 | color: white; 27 | } 28 | 29 | div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, 30 | div.sphinxsidebar h3 a { 31 | color: white; 32 | } 33 | 34 | div.sphinxsidebar a { 35 | color: #aaa; 36 | } 37 | 38 | div.sphinxsidebar p.logo { 39 | display: none; 40 | } 41 | 42 | div.document { 43 | width: 100%; 44 | margin: 0; 45 | } 46 | 47 | div.related { 48 | display: block; 49 | margin: 0; 50 | padding: 10px 0 20px 0; 51 | } 52 | 53 | div.related ul, 54 | div.related ul li { 55 | margin: 0; 56 | padding: 0; 57 | } 58 | 59 | div.footer { 60 | display: none; 61 | } 62 | 63 | div.bodywrapper { 64 | margin: 0; 65 | } 66 | 67 | div.body { 68 | min-height: 0; 69 | padding: 0; 70 | } 71 | 72 | .rtd_doc_footer { 73 | display: none; 74 | } 75 | 76 | .document { 77 | width: auto; 78 | } 79 | 80 | .footer { 81 | width: auto; 82 | } 83 | 84 | .footer { 85 | width: auto; 86 | } 87 | 88 | .github { 89 | display: none; 90 | } -------------------------------------------------------------------------------- /docs/_themes/kr/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = flasky.css 4 | pygments_style = flask_theme_support.FlaskyStyle 5 | 6 | [options] 7 | touch_icon = 8 | -------------------------------------------------------------------------------- /docs/click.rst: -------------------------------------------------------------------------------- 1 | Building command line applications with Click 2 | ============================================== 3 | 4 | 5 | I recommend `click `_ 6 | module to build command line applications. Like any other project from `Armin 7 | Ronacher `_, it has great documentation. In this 8 | post, I am going to write a beginners tutorial, you should the read the 9 | documentation for any more details and examples. 10 | 11 | 12 | Installation, and development tips 13 | ----------------------------------- 14 | 15 | Using virtualenv is highly recommended for developing "click" applications. I 16 | am going to assume that we are in an empty directory and the continue from 17 | there. To start, we will have a simple hello.py file with the following 18 | content: 19 | 20 | :: 21 | 22 | def cli(): 23 | print("Hello World") 24 | 25 | Now we will need a setup.py file. This will help us to use the python module we 26 | are writing as a command line tool. It is also the recommended way to write 27 | command line tools in python, then directly using shebang based scripts. 28 | 29 | :: 30 | 31 | from setuptools import setup 32 | 33 | setup( 34 | name="myhello", 35 | version='0.1', 36 | py_modules=['hello'], 37 | install_requires=[ 38 | 'Click', 39 | ], 40 | entry_points=''' 41 | [console_scripts] 42 | myhello=hello:cli 43 | ''', 44 | ) 45 | 46 | You can see that we mentioned the starting point of our tool in the 47 | entry_points, *hello:cli* points to the right function to start with. We can 48 | then install this on the virtualenv locally. I will also create the virtualenv 49 | below so that becomes easier others. To learn more, read this 50 | `chapter `_ later. 51 | 52 | :: 53 | 54 | $ python3 -m venv env 55 | $ source env/bin/activate 56 | $ python3 -m pip install --editable . 57 | Obtaining file:///home/kdas/code/practice/yoclick 58 | Collecting Click (from myhello==0.1) 59 | Using cached click-6.7-py2.py3-none-any.whl 60 | Installing collected packages: Click, myhello 61 | Running setup.py develop for myhello 62 | Successfully installed Click-6.7 myhello 63 | 64 | $ myhello 65 | Hello World 66 | 67 | Now to convert the same script into a click based tool, we will make the 68 | following modifications: 69 | 70 | :: 71 | 72 | import click 73 | 74 | @click.command() 75 | def cli(): 76 | print("Hello World") 77 | 78 | Now when we execute the command again, we see nothing changed visually, but it 79 | magically has a *--help* command line argument (which is optional). 80 | 81 | :: 82 | 83 | $ myhello 84 | Hello World 85 | $ myhello --help 86 | Usage: myhello [OPTIONS] 87 | 88 | Options: 89 | --help Show this message and exit. 90 | 91 | Using echo for printing text 92 | -------------------------------- 93 | 94 | The click module suggests using *echo* function to print, rather than the 95 | standard print function. So, we will make the required change in our code. 96 | 97 | :: 98 | 99 | import click 100 | 101 | @click.command() 102 | def cli(): 103 | click.echo("Hello World") 104 | 105 | Boolean flags 106 | -------------- 107 | 108 | In a command line tool, we sometimes want to have a boolean option. If the 109 | option is provided then do something, if not provided, then do something else. 110 | In our example, we will call the flag as *--verbose*, it is provided, then we 111 | will print some extra text. 112 | 113 | :: 114 | 115 | import click 116 | 117 | @click.command() 118 | @click.option('--verbose', is_flag=True, help="Will print verbose messages.") 119 | def cli(verbose): 120 | if verbose: 121 | click.echo("We are in the verbose mode.") 122 | click.echo("Hello World") 123 | 124 | 125 | We added another decorator to the cli function. In *click.option()* decorator, 126 | first we passed the flag using *--verbose*, then marked this option as a 127 | boolean flag, and then finally added the help text. 128 | 129 | :: 130 | 131 | $ myhello --help 132 | Usage: myhello [OPTIONS] 133 | 134 | Options: 135 | --verbose Will print verbose messages. 136 | --help Show this message and exit. 137 | $ myhello --verbose 138 | We are in the verbose mode. 139 | Hello World 140 | 141 | By default, any boolean flag is treated as false. 142 | 143 | Standard options in the command line 144 | ------------------------------------ 145 | 146 | We can now add more options to our tool. For example, we will have a *--name* 147 | option which will take a string as input. 148 | 149 | :: 150 | 151 | import click 152 | 153 | @click.command() 154 | @click.option('--verbose', is_flag=True, help="Will print verbose messages.") 155 | @click.option('--name', default='', help='Who are you?') 156 | def cli(verbose,name): 157 | if verbose: 158 | click.echo("We are in the verbose mode.") 159 | click.echo("Hello World") 160 | click.echo('Bye {0}'.format(name)) 161 | 162 | :: 163 | 164 | 165 | $ myhello --help 166 | Usage: myhello [OPTIONS] 167 | 168 | Options: 169 | --verbose Will print verbose messages. 170 | --name TEXT Who are you? 171 | --help Show this message and exit. 172 | $ myhello 173 | Hello World 174 | Bye 175 | $ myhello --name kushal 176 | Hello World 177 | Bye kushal 178 | 179 | 180 | Same option multiple times 181 | --------------------------- 182 | 183 | We may want to take the same option multiple times. Click has a very simple way to do so. 184 | 185 | :: 186 | 187 | import click 188 | 189 | @click.command() 190 | @click.option('--verbose', is_flag=True, help="Will print verbose messages.") 191 | @click.option('--name', '-n', multiple=True, default='', help='Who are you?') 192 | def cli(verbose,name): 193 | if verbose: 194 | click.echo("We are in the verbose mode.") 195 | click.echo("Hello World") 196 | for n in name: 197 | click.echo('Bye {0}'.format(n)) 198 | 199 | In the above example, you can see that we specified the *--name* as a multiple 200 | options. It also means the name parameter in the *cli* function is now a tuple. 201 | 202 | Help text for the script 203 | ------------------------ 204 | 205 | We can add help text for the script using python docstrings. For example: 206 | 207 | :: 208 | 209 | import click 210 | 211 | @click.command() 212 | @click.option('--verbose', is_flag=True, help="Will print verbose messages.") 213 | @click.option('--name', '-n', multiple=True, default='', help='Who are you?') 214 | def cli(verbose,name): 215 | """This is an example script to learn Click.""" 216 | if verbose: 217 | click.echo("We are in the verbose mode.") 218 | click.echo("Hello World") 219 | for n in name: 220 | click.echo('Bye {0}'.format(n)) 221 | 222 | :: 223 | 224 | $ myhello --help 225 | Usage: myhello [OPTIONS] 226 | 227 | This is an example script to learn Click. 228 | 229 | Options: 230 | --verbose Will print verbose messages. 231 | -n, --name TEXT Who are you? 232 | --help Show this message and exit. 233 | 234 | Super fast way to accept password with confirmation 235 | ---------------------------------------------------- 236 | 237 | Click provides a *password_option()* decorator, which can be used to accept a 238 | password over hidden prompt and second confirmation prompt. By the way, I am printing 239 | the password here as an example, never print the password to stdout in any 240 | tool. 241 | 242 | :: 243 | 244 | import click 245 | 246 | @click.command() 247 | @click.option('--verbose', is_flag=True, help="Will print verbose messages.") 248 | @click.option('--name', '-n', multiple=True, default='', help='Who are you?') 249 | @click.password_option() 250 | def cli(verbose,name, password): 251 | """This is an example script to learn Click.""" 252 | if verbose: 253 | click.echo("We are in the verbose mode.") 254 | click.echo("Hello World") 255 | for n in name: 256 | click.echo('Bye {0}'.format(n)) 257 | click.echo('We received {0} as password.'.format(password)) 258 | 259 | 260 | The output looks like below: 261 | 262 | :: 263 | 264 | $ myhello --help 265 | Usage: myhello [OPTIONS] 266 | 267 | This is an example script to learn Click. 268 | 269 | Options: 270 | --verbose Will print verbose messages. 271 | -n, --name TEXT Who are you? 272 | --password TEXT 273 | --help Show this message and exit. 274 | $ myhello 275 | Password: 276 | Repeat for confirmation: 277 | Hello World 278 | We received hello as password. 279 | 280 | 281 | To learn the full usage of password prompts, read `this section `_. 282 | 283 | Must have arguments 284 | -------------------- 285 | 286 | You can also add arguments to your tool. These are must haves, and if no 287 | default value is provided, they are assumed to be strings. In the below 288 | example, the script is expecting a county name to be specified. 289 | 290 | :: 291 | 292 | import click 293 | 294 | @click.command() 295 | @click.option('--verbose', is_flag=True, help="Will print verbose messages.") 296 | @click.option('--name', '-n', multiple=True, default='', help='Who are you?') 297 | @click.argument('country') 298 | def cli(verbose,name, country): 299 | """This is an example script to learn Click.""" 300 | if verbose: 301 | click.echo("We are in the verbose mode.") 302 | click.echo("Hello {0}".format(country)) 303 | for n in name: 304 | click.echo('Bye {0}'.format(n)) 305 | 306 | The output looks like: 307 | 308 | :: 309 | 310 | $ myhello 311 | Usage: myhello [OPTIONS] COUNTRY 312 | 313 | Error: Missing argument "country". 314 | $ myhello India 315 | Hello India 316 | 317 | 318 | Click has many other useful features, like *yes parameter*, *file path input*. 319 | I am not going to write about all of those here, but you can always read it from the 320 | `upstream documentation `_. 321 | -------------------------------------------------------------------------------- /docs/collections.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | ================== 4 | Collections module 5 | ================== 6 | 7 | In this chapter we will learn about a module called *Collections*. This module implements some nice data structures which will help you to solve various real life problems. 8 | 9 | :: 10 | 11 | >>> import collections 12 | 13 | This is how you can import the module, now we will see the available classes which you can use. 14 | 15 | 16 | .. index:: Counter 17 | 18 | Counter 19 | ======= 20 | 21 | *Counter* is a *dict* subclass which helps to count hashable objects. Inside it elements are stored as dictionary keys and counts are stored as values which can be zero or negative. 22 | 23 | Below we will see one example where we will find occurrences of words in the Python LICENSE file. 24 | 25 | Counter example 26 | --------------- 27 | 28 | :: 29 | 30 | >>> from collections import Counter 31 | >>> import re 32 | >>> path = '/usr/share/doc/python-2.7.3/LICENSE' 33 | >>> words = re.findall('\w+', open(path).read().lower()) 34 | >>> Counter(words).most_common(10) 35 | [('2', 97), ('the', 80), ('or', 78), ('1', 76), ('of', 61), ('to', 50), ('and', 47), ('python', 46), ('psf', 44), ('in', 38)] 36 | 37 | Counter objects has a method called *elements* which returns an iterator over elements repeating each as many times as its count. Elements are returned in arbitrary order. 38 | 39 | :: 40 | 41 | >>> c = Counter(a=4, b=2, c=0, d=-2) 42 | >>> list(c.elements()) 43 | ['a', 'a', 'a', 'a', 'b', 'b'] 44 | 45 | *most_common* is a method which returns most common elements and their counts from the most common to the least. 46 | 47 | :: 48 | 49 | >>> Counter('abracadabra').most_common(3) 50 | [('a', 5), ('r', 2), ('b', 2)] 51 | 52 | .. index:: defaultdict 53 | 54 | defaultdict 55 | =========== 56 | 57 | *defaultdict* is a dictionary like object which provides all methods provided by dictionary but takes first argument (default_factory) as default data type for the dictionary. Using defaultdict is faster than doing the same using *dict.set_default* method. 58 | 59 | defaultdict example 60 | ------------------- 61 | 62 | :: 63 | >>> from collections import defaultdict 64 | >>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] 65 | >>> d = defaultdict(list) 66 | >>> for k, v in s: 67 | ... d[k].append(v) 68 | ... 69 | >>> d.items() 70 | dict_items([('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]) 71 | 72 | In the example you can see even if the key is not there in the defaultdict object, it automatically creates an empty list. *list.append* then helps to append the value to the list. 73 | 74 | .. index:: namedtuple 75 | 76 | namedtuple 77 | ========== 78 | 79 | Named tuples helps to have meaning of each position in a tuple and allow us to code with better readability and self-documenting code. You can use them in any place where you are using *tuples*. In the example we will create a namedtuple to show hold information for points. 80 | 81 | Named tuple 82 | ----------- 83 | 84 | :: 85 | 86 | >>> from collections import namedtuple 87 | >>> Point = namedtuple('Point', ['x', 'y']) # Defining the namedtuple 88 | >>> p = Point(10, y=20) # Creating an object 89 | >>> p 90 | Point(x=10, y=20) 91 | >>> p.x + p.y 92 | 30 93 | >>> p[0] + p[1] # Accessing the values in normal way 94 | 30 95 | >>> x, y = p # Unpacking the tuple 96 | >>> x 97 | 10 98 | >>> y 99 | 20 100 | 101 | 102 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Python for you and me documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Jul 9 14:32:48 2013. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | sys.path.append(os.path.abspath("_themes")) 17 | html_theme_path = ["_themes"] 18 | html_theme = "cloud" 19 | 20 | # If extensions (or modules to document with autodoc) are in another directory, 21 | # add these directories to sys.path here. If the directory is relative to the 22 | # documentation root, use os.path.abspath to make it absolute, like shown here. 23 | # sys.path.insert(0, os.path.abspath('.')) 24 | 25 | # -- General configuration ----------------------------------------------------- 26 | 27 | # If your documentation needs a minimal Sphinx version, state it here. 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be extensions 31 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 32 | extensions = [ 33 | "sphinx.ext.intersphinx", 34 | ] 35 | 36 | # Add any paths that contain templates here, relative to this directory. 37 | templates_path = ["_templates"] 38 | 39 | # The suffix of source filenames. 40 | source_suffix = ".rst" 41 | 42 | # The encoding of source files. 43 | # source_encoding = 'utf-8-sig' 44 | 45 | # The master toctree document. 46 | master_doc = "index" 47 | 48 | # General information about the project. 49 | project = u"Python for you and me" 50 | copyright = u"2008-2022, Kushal Das" 51 | 52 | # The version info for the project you're documenting, acts as replacement for 53 | # |version| and |release|, also used in various other places throughout the 54 | # built documents. 55 | # 56 | # The short X.Y version. 57 | version = "0.5" 58 | # The full version, including alpha/beta/rc tags. 59 | release = "0.5.beta1" 60 | 61 | # The language for content autogenerated by Sphinx. Refer to documentation 62 | # for a list of supported languages. 63 | # language = None 64 | 65 | # There are two options for replacing |today|: either, you set today to some 66 | # non-false value, then it is used: 67 | # today = '' 68 | # Else, today_fmt is used as the format for a strftime call. 69 | # today_fmt = '%B %d, %Y' 70 | 71 | # List of patterns, relative to source directory, that match files and 72 | # directories to ignore when looking for source files. 73 | exclude_patterns = ["_build"] 74 | 75 | # The reST default role (used for this markup: `text`) to use for all documents. 76 | # default_role = None 77 | 78 | # If true, '()' will be appended to :func: etc. cross-reference text. 79 | # add_function_parentheses = True 80 | 81 | # If true, the current module name will be prepended to all description 82 | # unit titles (such as .. function::). 83 | # add_module_names = True 84 | 85 | # If true, sectionauthor and moduleauthor directives will be shown in the 86 | # output. They are ignored by default. 87 | # show_authors = False 88 | 89 | # The name of the Pygments (syntax highlighting) style to use. 90 | pygments_style = "sphinx" 91 | 92 | # A list of ignored prefixes for module index sorting. 93 | # modindex_common_prefix = [] 94 | 95 | 96 | # -- Options for HTML output --------------------------------------------------- 97 | 98 | # The theme to use for HTML and HTML Help pages. See the documentation for 99 | # a list of builtin themes. 100 | # html_theme = 'default' 101 | 102 | html_sidebars = { 103 | "index": ["sidebarintro.html", "sourcelink.html", "searchbox.html"], 104 | "**": [ 105 | "sidebarlogo.html", 106 | "localtoc.html", 107 | "relations.html", 108 | "sourcelink.html", 109 | "searchbox.html", 110 | ], 111 | } 112 | 113 | # Theme options are theme-specific and customize the look and feel of a theme 114 | # further. For a list of options available for each theme, see the 115 | # documentation. 116 | # html_theme_options = {} 117 | 118 | # Add any paths that contain custom themes here, relative to this directory. 119 | # html_theme_path = [] 120 | 121 | # The name for this set of Sphinx documents. If None, it defaults to 122 | # " v documentation". 123 | # html_title = None 124 | 125 | # A shorter title for the navigation bar. Default is the same as html_title. 126 | # html_short_title = None 127 | 128 | # The name of an image file (relative to this directory) to place at the top 129 | # of the sidebar. 130 | # html_logo = None 131 | 132 | # The name of an image file (within the static path) to use as favicon of the 133 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 134 | # pixels large. 135 | # html_favicon = None 136 | 137 | # Add any paths that contain custom static files (such as style sheets) here, 138 | # relative to this directory. They are copied after the builtin static files, 139 | # so a file named "default.css" will overwrite the builtin "default.css". 140 | html_static_path = ["_static"] 141 | 142 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 143 | # using the given strftime format. 144 | # html_last_updated_fmt = '%b %d, %Y' 145 | 146 | # If true, SmartyPants will be used to convert quotes and dashes to 147 | # typographically correct entities. 148 | # html_use_smartypants = True 149 | 150 | # Custom sidebar templates, maps document names to template names. 151 | # html_sidebars = {} 152 | 153 | # Additional templates that should be rendered to pages, maps page names to 154 | # template names. 155 | # html_additional_pages = {} 156 | 157 | # If false, no module index is generated. 158 | # html_domain_indices = True 159 | 160 | # If false, no index is generated. 161 | # html_use_index = True 162 | 163 | # If true, the index is split into individual pages for each letter. 164 | # html_split_index = False 165 | 166 | # If true, links to the reST sources are added to the pages. 167 | # html_show_sourcelink = True 168 | 169 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 170 | # html_show_sphinx = True 171 | 172 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 173 | # html_show_copyright = True 174 | 175 | # If true, an OpenSearch description file will be output, and all pages will 176 | # contain a tag referring to it. The value of this option must be the 177 | # base URL from which the finished HTML is served. 178 | # html_use_opensearch = '' 179 | 180 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 181 | # html_file_suffix = None 182 | 183 | # Output file base name for HTML help builder. 184 | htmlhelp_basename = "Pythonforyouandmedoc" 185 | 186 | 187 | # -- Options for LaTeX output -------------------------------------------------- 188 | 189 | latex_elements = { 190 | # The paper size ('letterpaper' or 'a4paper'). 191 | #'papersize': 'letterpaper', 192 | # The font size ('10pt', '11pt' or '12pt'). 193 | #'pointsize': '10pt', 194 | # Additional stuff for the LaTeX preamble. 195 | #'preamble': '', 196 | } 197 | 198 | # Grouping the document tree into LaTeX files. List of tuples 199 | # (source start file, target name, title, author, documentclass [howto/manual]). 200 | latex_documents = [ 201 | ( 202 | "index", 203 | "Pythonforyouandme.tex", 204 | u"Python for you and me", 205 | u"Kushal Das", 206 | "manual", 207 | ), 208 | ] 209 | 210 | # The name of an image file (relative to this directory) to place at the top of 211 | # the title page. 212 | # latex_logo = None 213 | 214 | # For "manual" documents, if this is true, then toplevel headings are parts, 215 | # not chapters. 216 | # latex_use_parts = False 217 | 218 | # If true, show page references after internal links. 219 | # latex_show_pagerefs = False 220 | 221 | # If true, show URL addresses after external links. 222 | # latex_show_urls = False 223 | 224 | # Documents to append as an appendix to all manuals. 225 | # latex_appendices = [] 226 | 227 | # If false, no module index is generated. 228 | # latex_domain_indices = True 229 | 230 | 231 | # -- Options for manual page output -------------------------------------------- 232 | 233 | # One entry per manual page. List of tuples 234 | # (source start file, name, description, authors, manual section). 235 | man_pages = [ 236 | ( 237 | "index", 238 | "pythonforyouandme", 239 | u"Python for you and me Documentation", 240 | [u"Kushal Das"], 241 | 1, 242 | ) 243 | ] 244 | 245 | # If true, show URL addresses after external links. 246 | # man_show_urls = False 247 | 248 | 249 | # -- Options for Texinfo output ------------------------------------------------ 250 | 251 | # Grouping the document tree into Texinfo files. List of tuples 252 | # (source start file, target name, title, author, 253 | # dir menu entry, description, category) 254 | texinfo_documents = [ 255 | ( 256 | "index", 257 | "Pythonforyouandme", 258 | u"Python for you and me Documentation", 259 | u"Kushal Das", 260 | "Pythonforyouandme", 261 | "One line description of project.", 262 | "Miscellaneous", 263 | ), 264 | ] 265 | 266 | # Documents to append as an appendix to all manuals. 267 | # texinfo_appendices = [] 268 | 269 | # If false, no module index is generated. 270 | # texinfo_domain_indices = True 271 | 272 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 273 | # texinfo_show_urls = 'footnote' 274 | 275 | 276 | # -- Options for Epub output --------------------------------------------------- 277 | 278 | # Bibliographic Dublin Core info. 279 | epub_title = u"Python for you and me" 280 | epub_author = u"Kushal Das" 281 | epub_publisher = u"Kushal Das" 282 | epub_copyright = u"2008-2022, Kushal Das" 283 | 284 | # The language of the text. It defaults to the language option 285 | # or en if the language is not set. 286 | # epub_language = '' 287 | 288 | # The scheme of the identifier. Typical schemes are ISBN or URL. 289 | # epub_scheme = '' 290 | 291 | # The unique identifier of the text. This can be a ISBN number 292 | # or the project homepage. 293 | # epub_identifier = '' 294 | 295 | # A unique identification for the text. 296 | # epub_uid = '' 297 | 298 | # A tuple containing the cover image and cover page html template filenames. 299 | # epub_cover = () 300 | 301 | # HTML files that should be inserted before the pages created by sphinx. 302 | # The format is a list of tuples containing the path and title. 303 | # epub_pre_files = [] 304 | 305 | # HTML files shat should be inserted after the pages created by sphinx. 306 | # The format is a list of tuples containing the path and title. 307 | # epub_post_files = [] 308 | 309 | # A list of files that should not be packed into the epub file. 310 | # epub_exclude_files = [] 311 | 312 | # The depth of the table of contents in toc.ncx. 313 | # epub_tocdepth = 3 314 | 315 | # Allow duplicate toc entries. 316 | # epub_tocdup = True 317 | 318 | 319 | # Example configuration for intersphinx: refer to the Python standard library. 320 | intersphinx_mapping = {"python": ("http://docs.python.org/3", None)} 321 | latex_preamble = r""" 322 | \usepackage{upquote} 323 | """ 324 | -------------------------------------------------------------------------------- /docs/editors.rst: -------------------------------------------------------------------------------- 1 | Using VS Code as your primary Python editor 2 | =========================================== 3 | 4 | If you have reached this chapter in the book, then I think you can take a 5 | step up in the programming world by using a new editor which has a lot more 6 | features than our starting editor (mu). 7 | 8 | `VS Code `_ is an Open Source multi-platform 9 | code editor from Microsoft which I personally like a lot. In this chapter, I 10 | am going to show you how you can start using it. 11 | 12 | 13 | Installing VS Code 14 | ------------------ 15 | 16 | Download and install VS Code in your Linux distribution following `the official 17 | guidelines `_. Please make 18 | sure that you are following all the steps given in that page. You should add 19 | the project repository properly (either deb or rpm repo) and always verify the 20 | package (the gpg signed packages in the repo makes it easier). 21 | 22 | Remember that VS Code ships monthly, means every month you will get update of 23 | this editor with many new features and bug fixes as required. 24 | 25 | 26 | Using VS Code 27 | ------------- 28 | 29 | 30 | .. figure:: img/code_welcome.png 31 | 32 | The above is the starting screen of VS Code, you should notice the small 33 | information box in the right hand corner. 34 | 35 | You can disable ``telemetry`` and thus sending the commands and other 36 | information that Microsoft collects. Go to the settings page by 37 | using ``File->Preference->Settings`` in the menu. 38 | 39 | 40 | .. figure:: img/code_disable_telemetry.png 41 | 42 | 43 | Install the Python extension 44 | ----------------------------- 45 | 46 | The next step would be to install the `Python extension 47 | `_ in VS Code. 48 | Go to "Extensions" from the left hand activity bar, and install the Python 49 | extension. 50 | 51 | .. figure:: img/code_install_python.png 52 | 53 | 54 | Start working on your code 55 | --------------------------- 56 | 57 | Now, you can start working on your favorite project. Open up the directory in 58 | VS Code, and start editing. 59 | 60 | Feel free to go through the `VS Code documentation 61 | `_ to learn more about the editor. 62 | 63 | .. important:: 64 | 65 | Learn about various shortcuts from `this gist `_. 66 | 67 | Install the Device Simulator Express extension 68 | ----------------------------------------------- 69 | 70 | .. figure:: img/installing_devicesimulator.gif 71 | 72 | 73 | Follow `this page `_ to install the simulator, if you are on Linux, remember to 74 | remove the Windows dependency from the requirements.txt file as shown in the 75 | GIF file below. 76 | 77 | .. figure:: img/how_to_get_device_simulator.gif 78 | 79 | -------------------------------------------------------------------------------- /docs/exceptions.rst: -------------------------------------------------------------------------------- 1 | .. index:: Exception 2 | 3 | ====================== 4 | Exceptions 5 | ====================== 6 | 7 | In this chapter we will learn about exceptions in Python and how to 8 | handle them in your code. 9 | 10 | 11 | Any error which happens during the execution of the code is an exception. Each 12 | exception generally shows some error message. 13 | 14 | NameError 15 | ========== 16 | 17 | When one starts writing code, this will be one of the most common exception 18 | he/she will find. This happens when someone tries to access a variable which is 19 | not defined. 20 | :: 21 | 22 | >>> print(kushal) 23 | Traceback (most recent call last): 24 | File "", line 1, in 25 | NameError: name 'kushal' is not defined 26 | 27 | The last line contains the details of the error message, the rest of the lines 28 | shows the details of how it happened (or what caused that exception). 29 | 30 | .. index:: TypeError 31 | 32 | TypeError 33 | ========== 34 | 35 | `TypeError` is also one of the most found exception. This happens when someone tries 36 | to do an operation with different kinds of incompatible data types. A common example 37 | is to do addition of Integers and a string. 38 | :: 39 | 40 | >>> print(1 + "kushal") 41 | Traceback (most recent call last): 42 | File "", line 1, in 43 | TypeError: unsupported operand type(s) for +: 'int' and 'str' 44 | 45 | How to handle exceptions? 46 | ========================= 47 | 48 | We use `try...except` blocks to handle any exception. The basic syntax looks like 49 | :: 50 | 51 | try: 52 | statements to be inside try clause 53 | statement2 54 | statement3 55 | ... 56 | except ExceptionName: 57 | statements to evaluated in case of ExceptionName happens 58 | 59 | It works in the following way: 60 | 61 | - First all lines between `try` and `except` statements. 62 | - If `ExceptionName` happens during execution of the statements then `except` clause statements execute 63 | - If no exception happens then the statements inside `except` clause does not execute. 64 | - If the `Exception` is not handled in the `except` block then it goes out of `try` block. 65 | 66 | The following examples showcase these scenarios. 67 | :: 68 | 69 | >>> def get_number(): 70 | ... "Returns a float number" 71 | ... number = float(input("Enter a float number: ")) 72 | ... return number 73 | ... 74 | >>> 75 | >>> while True: 76 | ... try: 77 | ... print(get_number()) 78 | ... except ValueError: 79 | ... print("You entered a wrong value.") 80 | ... 81 | Enter a float number: 45.0 82 | 45.0 83 | Enter a float number: 24,0 84 | You entered a wrong value. 85 | Enter a float number: Traceback (most recent call last): 86 | File "", line 3, in 87 | File "", line 3, in get_number 88 | KeyboardInterrupt 89 | 90 | As the first input I provided a proper float value and it printed it back, next 91 | I entered a value with a comma, so the `except` clause executed and the print 92 | statement executed. 93 | 94 | In the third time I pressed *Ctrl+c* which caused a `KeyboardInterrupt`, which is 95 | not handled in the `except` block so the execution stopped with that exception. 96 | 97 | An empty `except` statement can catch any exception. Read the following example:: 98 | 99 | >>> try: 100 | ... input() # Press Ctrl+c for a KeyboardInterrupt 101 | ... except: 102 | ... print("Unknown Exception") 103 | ... 104 | Unknown Exception 105 | 106 | Raising exceptions 107 | =================== 108 | 109 | One can raise an exception using `raise` statement. 110 | :: 111 | 112 | >>> raise ValueError("A value error happened.") 113 | Traceback (most recent call last): 114 | File "", line 1, in 115 | ValueError: A value error happened. 116 | 117 | 118 | We can catch these exceptions like any other normal exceptions. 119 | :: 120 | 121 | >>> try: 122 | ... raise ValueError("A value error happened.") 123 | ... except ValueError: 124 | ... print("ValueError in our code.") 125 | ... 126 | ValueError in our code. 127 | 128 | .. index:: finally 129 | 130 | Using finally for cleanup 131 | ========================== 132 | 133 | If we want to have some statements which must be executed under all circumstances, 134 | we can use `finally` clause, it will be always executed before finishing `try` 135 | statements. 136 | :: 137 | 138 | >>> try: 139 | ... fobj = open("hello.txt", "w") 140 | ... res = 12 / 0 141 | ... except ZeroDivisionError: 142 | ... print("We have an error in division") 143 | ... finally: 144 | ... fobj.close() 145 | ... print("Closing the file object.") 146 | ... 147 | We have an error in division 148 | Closing the file object. 149 | 150 | In this example we are making sure that the file object we open, must get closed 151 | in the `finally` clause. 152 | -------------------------------------------------------------------------------- /docs/file.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | ============= 4 | File handling 5 | ============= 6 | 7 | A file is some information or data which stays in the computer storage devices. You already know about different kinds of file , like your music files, video files, text files. Python gives you easy ways to manipulate these files. Generally we divide files in two categories, text file and binary file. Text files are simple text where as the binary files contain binary data which is only readable by computer. 8 | 9 | File opening 10 | ============ 11 | 12 | To open a file we use *open()* function. It requires two arguments, first the file path or file name, second which mode it should open. Modes are like 13 | 14 | + "r" -> open read only, you can read the file but can not edit / delete anything inside 15 | 16 | + "w" -> open with write power, means if the file exists then delete all content and open it to write 17 | 18 | + "a" -> open in append mode 19 | 20 | The default mode is read only, ie if you do not provide any mode it will open the file as read only. Let us open a file 21 | 22 | :: 23 | 24 | >>> fobj = open("love.txt") 25 | >>> fobj 26 | <_io.TextIOWrapper name='love.txt' mode='r' encoding='UTF-8'> 27 | 28 | Closing a file 29 | ============== 30 | 31 | After opening a file one should always close the opened file. We use method *close()* for this. 32 | 33 | :: 34 | 35 | >>> fobj = open("love.txt") 36 | >>> fobj 37 | <_io.TextIOWrapper name='love.txt' mode='r' encoding='UTF-8'> 38 | >>> fobj.close() 39 | 40 | .. important:: 41 | Always make sure you *explicitly* close each open file, once its job is done and you have no reason to keep it open. 42 | Because 43 | 44 | - There is an upper limit to the number of files a program can open. If you exceed that limit, there is no reliable way of recovery, so the program could crash. 45 | - Each open file consumes some main-memory for the data-structures associated with it, like file descriptor/handle or file locks etc. So you could essentially end-up wasting lots of memory if you have more files open that are not useful or usable. 46 | - Open files always stand a chance of corruption and data loss. 47 | 48 | Reading a file 49 | ============== 50 | 51 | To read the whole file at once use the *read()* method. 52 | 53 | :: 54 | 55 | >>> fobj = open("sample.txt") 56 | >>> fobj.read() 57 | 'I love Python\nPradeepto loves KDE\nSankarshan loves Openoffice\n' 58 | 59 | If you call *read()* again it will return empty string as it already read the whole file. readline() can help you to read one line each time from the file. 60 | 61 | :: 62 | 63 | >>> fobj = open("sample.txt") 64 | >>> fobj.readline() 65 | 'I love Python\n' 66 | >>> fobj.readline() 67 | 'Pradeepto loves KDE\n' 68 | 69 | To read all the lines in a list we use *readlines()* method. 70 | 71 | :: 72 | 73 | >>> fobj = open("sample.txt") 74 | >>> fobj.readlines() 75 | ['I love Python\n', 'Pradeepto loves KDE\n', 'Sankarshan loves Openoffice\n'] 76 | 77 | You can even loop through the lines in a file object. 78 | 79 | :: 80 | 81 | >>> fobj = open("sample.txt") 82 | >>> for x in fobj: 83 | ... print(x, end=' ') 84 | ... 85 | I love Python 86 | Pradeepto loves KDE 87 | Sankarshan loves Openoffice 88 | 89 | Let us write a program which will take the file name as the input from the user and show the content of the file in the console. 90 | 91 | :: 92 | 93 | #!/usr/bin/env python3 94 | name = input("Enter the file name: ") 95 | fobj = open(name) 96 | print(fobj.read()) 97 | fobj.close() 98 | 99 | In the last line you can see that we closed the file object with the help of close() method. 100 | 101 | The output 102 | 103 | :: 104 | 105 | $ ./showfile.py 106 | Enter the filename: sample.txt 107 | I love Python 108 | Pradeepto loves KDE 109 | Sankarshan loves Openoffice 110 | 111 | Using the with statement 112 | ========================= 113 | 114 | In real life scenarios we should try to use `with` statement. It will take care of closing the file for you. 115 | :: 116 | 117 | >>> with open('setup.py') as fobj: 118 | ... for line in fobj: 119 | ... print line, 120 | ... 121 | #!/usr/bin/env python3 122 | """Factorial project""" 123 | from setuptools import find_packages, setup 124 | 125 | setup(name = 'factorial', 126 | version = '0.1', 127 | description = "Factorial module.", 128 | long_description = "A test module for our book.", 129 | platforms = ["Linux"], 130 | author="Kushal Das", 131 | author_email="kushaldas@gmail.com", 132 | url="https://pymbook.readthedocs.io/en/latest/", 133 | license = "http://www.gnu.org/copyleft/gpl.html", 134 | packages=find_packages() 135 | ) 136 | 137 | 138 | 139 | Writing in a file 140 | ================= 141 | 142 | Let us open a file then we will write some random text into it by using the *write()* method. 143 | We can also pass the file object to the print function call, so that it writes in the file. 144 | 145 | :: 146 | 147 | >>> fobj = open("ircnicks.txt", 'w') 148 | >>> fobj.write('powerpork\n') 149 | >>> fobj.write('indrag\n') 150 | >>> fobj.write('mishti\n') 151 | >>> fobj.write('sankarshan') 152 | >>> print("This is the last line.", file=fobj) 153 | >>> fobj.close() 154 | 155 | Now read the file we just created 156 | 157 | :: 158 | 159 | >>> fobj = open('ircnicks.txt') 160 | >>> s = fobj.read() 161 | >>> print(s) 162 | powerpork 163 | indrag 164 | mishti 165 | sankarshan 166 | This is the last line. 167 | 168 | copyfile.py 169 | =========== 170 | 171 | In this example we will copy a given text file to another file. 172 | 173 | :: 174 | 175 | #!/usr/bin/env python3 176 | import sys 177 | if len(sys.argv) < 3: 178 | print("Wrong parameter") 179 | print("./copyfile.py file1 file2") 180 | sys.exit(1) 181 | with open(sys.argv[1]) as f1: 182 | s = f1.read() 183 | with open(sys.argv[2], 'w') as f2: 184 | f2.write(s) 185 | 186 | .. note:: This way of reading file is not always a good idea, a file can be very large to read and fit in the memory. It is always better to read a known size of the file and write that to the new file. 187 | 188 | You can see we used a new module here *sys*. *sys.argv* contains all command line parameters. Remember *cp* command in shell, after *cp* we type first the file to be copied and then the new file name. 189 | 190 | The first value in *sys.argv* is the name of the command itself. 191 | 192 | :: 193 | 194 | #!/usr/bin/env python3 195 | import sys 196 | print("First value", sys.argv[0]) 197 | print("All values") 198 | for i, x in enumerate(sys.argv): 199 | print(i, x) 200 | 201 | The output 202 | 203 | :: 204 | 205 | $ ./argvtest.py Hi there 206 | First value ./argvtest.py 207 | All values 208 | 0 ./argvtest.py 209 | 1 Hi 210 | 2 there 211 | 212 | Here we used a new function *enumerate(iterableobject)*, which returns the index number and the value from the iterable object. 213 | 214 | Count spaces, tabs and new lines in a file 215 | ========================================== 216 | 217 | Let us try to write an application which will count the spaces, tabs, and lines in any given file. 218 | 219 | :: 220 | 221 | #!/usr/bin/env python3 222 | 223 | import os 224 | import sys 225 | 226 | 227 | def parse_file(path): 228 | """ 229 | Parses the text file in the given path and returns space, tab & new line 230 | details. 231 | 232 | :arg path: Path of the text file to parse 233 | 234 | :return: A tuple with count of spacaes, tabs and lines. 235 | """ 236 | fd = open(path) 237 | i = 0 238 | spaces = 0 239 | tabs = 0 240 | for i,line in enumerate(fd): 241 | spaces += line.count(' ') 242 | tabs += line.count('\t') 243 | #Now close the open file 244 | fd.close() 245 | 246 | #Return the result as a tuple 247 | return spaces, tabs, i + 1 248 | 249 | def main(path): 250 | """ 251 | Function which prints counts of spaces, tabs and lines in a file. 252 | 253 | :arg path: Path of the text file to parse 254 | :return: True if the file exits or False. 255 | """ 256 | if os.path.exists(path): 257 | spaces, tabs, lines = parse_file(path) 258 | print("Spaces %d. tabs %d. lines %d" % (spaces, tabs, lines)) 259 | return True 260 | else: 261 | return False 262 | 263 | 264 | if __name__ == '__main__': 265 | if len(sys.argv) > 1: 266 | main(sys.argv[1]) 267 | else: 268 | sys.exit(-1) 269 | sys.exit(0) 270 | 271 | You can see that we have two functions in the program , *main* and *parse_file* where the second one actually parses the file and returns the result and we print the result in *main* function. By splitting up the code in smaller units (functions) helps us to organize the codebase and also it will be easier to write test cases for the functions. 272 | 273 | 274 | 275 | Let us write some real code 276 | =========================== 277 | 278 | Do you know how many CPU(s) are there in your processor? or what is the model name? 279 | Let us write some code which can help us to know these things. 280 | 281 | If you are in Linux, then you can actually view the output of the *lscpu* command first. 282 | You can actually find the information in a file located at */proc/cpuinfo*. 283 | 284 | Now try to write code which will open the file in read only mode and then read the file 285 | line by line and find out the number of CPU(s). 286 | 287 | .. tip:: Always remember to read files line by line than reading them as a whole. Sometimes you may have to read files which are way bigger than your available RAM. 288 | 289 | After you do this, try to write your own lscpu command in Python :) 290 | -------------------------------------------------------------------------------- /docs/flask.rst: -------------------------------------------------------------------------------- 1 | Introduction to Flask 2 | ===================== 3 | 4 | What is flask? 5 | -------------- 6 | 7 | `Flask `_ is a web framework. This means flask provides 8 | you with tools, libraries and technologies that allow you to build a web 9 | application. This web application can be some web pages, a blog, a wiki or go as 10 | big as a web-based calendar application or a commercial website. 11 | 12 | Flask is part of the categories of the micro-framework. Micro-framework are 13 | normally framework with little to no dependencies to external libraries. This 14 | has pros and cons. Pros would be that the framework is light, there are little 15 | dependency to update and watch for security bugs, cons is that some time you 16 | will have to do more work by yourself or increase yourself the list of 17 | dependencies by adding plugins. 18 | In the case of Flask, its dependencies are: 19 | 20 | * `Werkzeug `_ a WSGI utility library 21 | * `jinja2 `_ which is its template engine 22 | 23 | .. note:: WSGI is basically a protocol defined so that Python application can 24 | communicate with a web-server and thus be used as web-application outside of 25 | CGI. 26 | 27 | What are template engines? 28 | -------------------------- 29 | 30 | Have you ever built a website? Did you face the problem that to keep the style 31 | of the website consistent, you have had to write multiple times the same text? 32 | Did you ever tried to change the style of such website? 33 | 34 | If your website contains only few pages, changing its style will take you some 35 | time but is doable. However, if you have a lot of pages (for example the list of 36 | items you sell in your store), this task become overwhelming. 37 | 38 | Using templates you are able to set a basic layout for your pages and mention 39 | which element will change. 40 | This way you can define your header once and keep it consistent over all the pages of 41 | your website, and if you need to change your header, you will only have to 42 | update it in one place. 43 | 44 | Using a template engine will save you a lot of time when creating your 45 | application but also when updating and maintaining it. 46 | 47 | A "Hello world" application in flask 48 | ------------------------------------- 49 | 50 | We are going to perform a very basic application with flask. 51 | 52 | * Create the structure of the project 53 | 54 | :: 55 | 56 | mkdir -p hello_flask/{templates,static} 57 | 58 | This is the basic structure of your web application:: 59 | 60 | $ tree hello_flask/ 61 | hello_flask/ 62 | |-- static 63 | `-- templates 64 | 65 | The ``templates`` folder is the place where the templates will be put. 66 | The ``static`` folder is the place where any files (images, css, javascript) 67 | needed by the web application will be put. 68 | 69 | * Create the application file 70 | 71 | :: 72 | 73 | cd hello_flask 74 | vim hello_flask.py 75 | 76 | Put the following code in this file:: 77 | 78 | #!/usr/bin/env python 79 | 80 | import flask 81 | 82 | 83 | # Create the application. 84 | APP = flask.Flask(__name__) 85 | 86 | 87 | @APP.route('/') 88 | def index(): 89 | """ Displays the index page accessible at '/' 90 | """ 91 | return flask.render_template('index.html') 92 | 93 | 94 | if __name__ == '__main__': 95 | APP.debug=True 96 | APP.run() 97 | 98 | 99 | * Create the template ``index.html`` 100 | 101 | :: 102 | 103 | vim templates/index.html 104 | 105 | 106 | Put the following code in this file 107 | 108 | .. code-block:: html 109 | 110 | 111 | 112 | 113 | 114 | Hello world! 115 | 118 | 119 | 120 | 121 | It works! 122 | 123 | 124 | 125 | 126 | 127 | * Run the flask application 128 | 129 | :: 130 | 131 | python hello_flask.py 132 | 133 | 134 | Access `http://127.0.0.1:5000/ `_ this should simply 135 | show you in black on white the text "It works!" (see Figure below). 136 | 137 | .. figure:: img/hello_flask_Index.png 138 | :width: 600 px 139 | :target: img/hello_flask_Index.png 140 | :align: center 141 | 142 | 143 | Using arguments in Flask 144 | ------------------------ 145 | 146 | In this section we are going to see how to use a page according to the URL used 147 | by the user. 148 | 149 | For this we will update ``hello_flask.py``. 150 | 151 | * Add the following entry in ``hello_flask.py`` 152 | 153 | :: 154 | 155 | @APP.route('/hello//') 156 | def hello(name): 157 | """ Displays the page greats who ever comes to visit it. 158 | """ 159 | return flask.render_template('hello.html', name=name) 160 | 161 | * Create the following template ``hello.html`` 162 | 163 | .. code-block:: html 164 | 165 | 166 | 167 | 168 | 169 | Hello 170 | 173 | 174 | 175 | 176 | Hello {{name}} 177 | 178 | 179 | 180 | 181 | * Run the flask application 182 | 183 | :: 184 | 185 | python hello_flask.py 186 | 187 | 188 | Access `http://127.0.0.1:5000/ `_ this should simply 189 | show you in black on white the text "It works!". 190 | 191 | Access `http://127.0.0.1:5000/hello/you `_ 192 | this should return you the text "Hello you" (see Figure below). 193 | 194 | .. figure:: img/hello_flask_hello.png 195 | :width: 600 px 196 | :target: img/hello_flask_hello.png 197 | :align: center 198 | 199 | Whatever you put behind ``/hello/`` in the URL will be returned to you in the 200 | page. 201 | 202 | This is your first use of the template, we set up a variable ``name`` in 203 | ``hello_flask.py`` (see the return line of the function ``hello``). This 204 | variable is then displayed in the page itself using the syntax ``{{name}}``. 205 | 206 | Additional work 207 | ---------------- 208 | 209 | Make use of the templates 210 | 211 | At the moment for each page we have created a template, this is actually bad 212 | practice, what we should do is create a ``master`` template and have each page 213 | use it. 214 | 215 | * Create the template ``master.html`` 216 | 217 | .. code-block:: html 218 | 219 | 220 | 221 | 222 | 223 | {% block title %}{% endblock %} - Hello Flask! 224 | 227 | 228 | 229 | 230 | {% block body %}{% endblock %} 231 | 232 | 233 | 234 | 235 | * Adjust the template ``index.html`` 236 | 237 | .. code-block:: html 238 | 239 | {% extends "master.html" %} 240 | 241 | {% block title %}Home{% endblock %} 242 | 243 | {% block body %} 244 | It works! 245 | {% endblock %} 246 | 247 | As you can see, in the ``master.html`` template we have defined two sections, 248 | blocks which are named ``title`` and ``body``. 249 | 250 | In the template ``index.html`` we say that this template relies on the template 251 | ``master.html``, then we define the content to put in these two sections 252 | (blocks). In the first block ``title`` we say to put the word `Home`, In the 253 | second block we define what we want to have in the body of the page. 254 | 255 | * As an exercise, transform the other template ``hello.html`` to use the 256 | ``master.html`` template as well. 257 | 258 | * Add link to the front page from the hello page 259 | 260 | Flask uses a specific syntax to create links from a page to another. This is 261 | fact generates the link dynamically according to the decorator set to the 262 | function linked to. In addition it takes care of where the application is 263 | deployed. 264 | 265 | For example, if you website is deployed at: ``/myapp/`` flask will automatically 266 | happend ``/myapp/`` to all links without the need for you to specify it. 267 | 268 | To create a link in a template, flask relies on the function ``url_for()``. This 269 | function takes as first argument the function you want to call (link to). The 270 | following arguments are the arguments of function itself (for example the 271 | argument ``name`` of the function ``hello``. 272 | 273 | Adjust the template ``hello.html`` to add a link to the front page 274 | 275 | :: 276 | 277 | 278 | 279 | * As an assignment add a link in the front page to the hello page for `you`. 280 | -------------------------------------------------------------------------------- /docs/hardwaresimulation.rst: -------------------------------------------------------------------------------- 1 | 2 | ================================== 3 | Learning using hardware simulation 4 | ================================== 5 | 6 | From this section and in the future chapters, there will be examples and problems 7 | which is using a special device simulation in VS Code editor. 8 | 9 | We will use the simulation to have a `Circuit Playground Express device `_, 10 | and learn to interact with the device. We will be able to turn on lights of different 11 | colours, and many other nice examples. 12 | 13 | .. note:: 14 | 15 | Visit `Adafruit `_ website to find many amazing hardware and learning materials. 16 | 17 | 18 | Circuit Playground Express 19 | ========================== 20 | 21 | 22 | .. figure:: img/cpx.gif 23 | 24 | 25 | The above is the image of the real hardware, in the simulation we will use, 26 | we can use the following: 27 | 28 | - Green LED 29 | - Red LED 30 | - Push Buttons A and B 31 | - Slider Switch 32 | - Speaker: Play .wav file 33 | - 10 NeoPixels 34 | - Light sensor 35 | - Motion sensors 36 | - Acceleration detection 37 | - Device shake detection 38 | - Temperature sensor 39 | - 7 Capacitive Touch sensors 40 | 41 | 42 | .. rst-class:: floater 43 | 44 | .. seealso:: 45 | 46 | Go to the (:doc:`editors`) to learn how to install VS Code and the device simulation, 47 | and then come back to this chapter. 48 | 49 | 50 | Turning on all NeoPixels on the board with Red colour 51 | ===================================================== 52 | 53 | .. figure:: img/red_light.gif 54 | 55 | :: 56 | 57 | # import CPX library 58 | from adafruit_circuitplayground.express import cpx 59 | import time 60 | 61 | RED = (255,0, 0) 62 | 63 | 64 | while True: 65 | # start your code here 66 | cpx.pixels.fill(RED) 67 | 68 | On the top of the code, we are writing a line starting with **from** to get the Python module 69 | which can interact wtih the device, as **cpx**. Next line, we are also importing *time* module, 70 | which we will use later. 71 | 72 | Then we defined a colour Red in the *RED* variable as a (R, G, B) tuple. 73 | 74 | Next, the `while True:` line starts a loop and it will keep running, and inside using the same indentation, 75 | we call a function `cpx.pixels.fill` with the desired color (in this case RED). 76 | 77 | Can you now write a code which will turn all the NeoPixel lights on the device Yellow? For this, 78 | you will have to search the RGB value of Yellow. 79 | 80 | .. figure:: img/yellow_light.png 81 | 82 | 83 | .. rst-class:: html-toggle 84 | 85 | Yellow light solution 86 | --------------------- 87 | 88 | :: 89 | 90 | from adafruit_circuitplayground.express import cpx 91 | import time 92 | 93 | YELLOW = (255, 255, 0) 94 | 95 | 96 | while True: 97 | # start your code here 98 | cpx.pixels.fill(YELLOW) 99 | 100 | 101 | Learning about time.sleep 102 | -------------------------- 103 | 104 | 105 | The `time` module has an important function, *sleep*, which takes the amount 106 | of time the code will sleep (means it will do nothing), and then, the next 107 | instruction will execute. We can use this to keep the light on or offf for 108 | certain amount of time. Take the following example, where we are keeping the 109 | NeoPixels on for 1 second and then, turning them off (RGB value (0,0,0)) for 110 | 0.5 seconds. 111 | 112 | :: 113 | 114 | # import CPX library 115 | from adafruit_circuitplayground.express import cpx 116 | import time 117 | 118 | WHITE = (255, 255, 255) 119 | OFF = (0, 0, 0) 120 | 121 | while True: 122 | # start your code here 123 | cpx.pixels.fill(WHITE) 124 | time.sleep(1) 125 | cpx.pixels.fill(OFF) 126 | time.sleep(0.5) 127 | 128 | 129 | .. figure:: img/onoff.gif 130 | 131 | 132 | RGB problem 133 | ------------- 134 | 135 | 136 | Can you modify the code in a such a way that it shows Red, and then Green and 137 | then Blue on all NeoPixels? It will look like the following image. 138 | 139 | .. figure:: img/rgb.gif 140 | 141 | 142 | .. rst-class:: html-toggle 143 | 144 | RGB solution 145 | -------------- 146 | 147 | :: 148 | 149 | # import CPX library 150 | from adafruit_circuitplayground.express import cpx 151 | import time 152 | 153 | RED = (255, 0, 0) 154 | GREEN = (0, 255, 0) 155 | BLUE = (0, 0, 255) 156 | 157 | 158 | while True: 159 | cpx.pixels.fill(RED) 160 | time.sleep(1) 161 | cpx.pixels.fill(GREEN) 162 | time.sleep(1) 163 | cpx.pixels.fill(BLUE) 164 | time.sleep(1) 165 | 166 | -------------------------------------------------------------------------------- /docs/ifelse.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | ========================== 4 | If-else , the control flow 5 | ========================== 6 | 7 | While working on real life of problems we have to make decisions. Decisions 8 | like which camera to buy or which cricket bat is better. At the time of writing 9 | a computer program we do the same. We make the decisions using if-else 10 | statements, we change the flow of control in the program by using them. 11 | 12 | If statement 13 | ============ 14 | 15 | The syntax looks like 16 | 17 | :: 18 | 19 | if expression: 20 | do this 21 | 22 | If the value of *expression* is true (anything other than zero), do the what is 23 | written below under indentation. Please remember to give proper indentation, 24 | all the lines indented will be evaluated on the True value of the expression. 25 | One simple example is to take some number as input and check if the number is 26 | less than 100 or not. 27 | 28 | :: 29 | 30 | #!/usr/bin/env python3 31 | number = int(input("Enter a number: ")) 32 | if number < 100: 33 | print("The number is less than 100") 34 | 35 | Then we execute the file. 36 | 37 | :: 38 | 39 | $ ./number100.py 40 | Enter a number: 12 41 | The number is less than 100 42 | 43 | Else statement 44 | ============== 45 | 46 | Now in the above example we want to print "Greater than" if the number is 47 | greater than 100. For that we have to use the *else* statement. This works when 48 | the *if* statement is not fulfilled. 49 | 50 | :: 51 | 52 | #!/usr/bin/env python3 53 | number = int(input("Enter a number: ")) 54 | if number < 100: 55 | print("The number is less than 100") 56 | else: 57 | print("The number is greater than 100") 58 | 59 | The output 60 | 61 | :: 62 | 63 | $ ./number100.py 64 | Enter a number: 345 65 | The number is greater than 100 66 | 67 | Another very basic example 68 | 69 | :: 70 | 71 | >>> x = int(input("Please enter an integer: ")) 72 | >>> if x < 0: 73 | ... x = 0 74 | ... print('Negative changed to zero') 75 | ... elif x == 0: 76 | ... print('Zero') 77 | ... elif x == 1: 78 | ... print('Single') 79 | ... else: 80 | ... print('More') 81 | 82 | Truth value testing 83 | =================== 84 | 85 | The elegant way to test Truth values is like 86 | 87 | :: 88 | 89 | if x: 90 | pass 91 | 92 | .. warning:: Don't do this 93 | 94 | :: 95 | 96 | if x == True: 97 | pass 98 | 99 | 100 | .. versionadded:: 3.10 101 | 102 | match statements 103 | ================= 104 | 105 | From Python 3.10 we have `match` statements. We can use these instead of if/elif/else blocks. 106 | For example, in the following code, we are taking an integer as input and then matching the value with some predefined 107 | HTTP status codes and print the names. 108 | 109 | :: 110 | 111 | status = int(input("Give us a status code: ")) 112 | match status: 113 | case 200: 114 | print("OK") 115 | case 201: 116 | print("Created") 117 | case 301: 118 | print("Moved Permanently") 119 | case 302: 120 | print("Found") 121 | case _: 122 | print("The status is unknown to us.") 123 | 124 | The last line, we are matching against anything else, we call it *wildcard* matching. 125 | 126 | We can even match complex objects, say against tuples, or other objects. 127 | 128 | :: 129 | 130 | status = (100,500) 131 | match status: 132 | case (x,y): 133 | print(f"X and Y are: {x}, {y}") 134 | case x: 135 | print(x) 136 | 137 | status = 42 138 | match status: 139 | case (x,y): 140 | print(f"X and Y are: {x}, {y}") 141 | case x: 142 | print(x) 143 | 144 | -------------------------------------------------------------------------------- /docs/igd.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | ==================================== 4 | Iterators, generators and decorators 5 | ==================================== 6 | 7 | In this chapter we will learn about iterators, generators and decorators. 8 | 9 | Iterators 10 | ========= 11 | 12 | Python iterator objects are required to support two methods while following the iterator 13 | protocol. 14 | 15 | *__iter__* returns the iterator object itself. This is used in *for* 16 | and *in* statements. 17 | 18 | *__next__* method returns the next value from the iterator. If there is no more items 19 | to return then it should raise *StopIteration* exception. 20 | 21 | :: 22 | 23 | class Counter(object): 24 | def __init__(self, low, high): 25 | self.current = low 26 | self.high = high 27 | 28 | def __iter__(self): 29 | 'Returns itself as an iterator object' 30 | return self 31 | 32 | def __next__(self): 33 | 'Returns the next value till current is lower than high' 34 | if self.current > self.high: 35 | raise StopIteration 36 | else: 37 | self.current += 1 38 | return self.current - 1 39 | 40 | Now we can use this iterator in our code. 41 | 42 | :: 43 | 44 | >>> c = Counter(5,10) 45 | >>> for i in c: 46 | ... print(i, end=' ') 47 | ... 48 | 5 6 7 8 9 10 49 | 50 | Remember that an iterator object can be used only once. It means after it raises *StopIteration* 51 | once, it will keep raising the same exception. 52 | 53 | :: 54 | 55 | >>> c = Counter(5,6) 56 | >>> next(c) 57 | 5 58 | >>> next(c) 59 | 6 60 | >>> next(c) 61 | Traceback (most recent call last): 62 | File "", line 1, in 63 | File "", line 11, in next 64 | StopIteration 65 | >>> next(c) 66 | Traceback (most recent call last): 67 | File "", line 1, in 68 | File "", line 11, in next 69 | StopIteration 70 | 71 | Using the iterator in for loop example we saw, the following example tries to show the code 72 | behind the scenes. 73 | 74 | :: 75 | 76 | >>> iterator = iter(c) 77 | >>> while True: 78 | ... try: 79 | ... x = iterator.__next__() 80 | ... print(x, end=' ') 81 | ... except StopIteration as e: 82 | ... break 83 | ... 84 | 5 6 7 8 9 10 85 | 86 | Generators 87 | ========== 88 | 89 | In this section we learn about Python generators. They were introduced in Python 2.3. It 90 | is an easier way to create iterators using a keyword *yield* from a function. 91 | 92 | :: 93 | 94 | >>> def my_generator(): 95 | ... print("Inside my generator") 96 | ... yield 'a' 97 | ... yield 'b' 98 | ... yield 'c' 99 | ... 100 | >>> my_generator() 101 | 102 | 103 | In the above example we create a simple generator using the yield statements. We can use it 104 | in a for loop just like we use any other iterators. 105 | 106 | :: 107 | 108 | >>> for char in my_generator(): 109 | ... print(char) 110 | ... 111 | Inside my generator 112 | a 113 | b 114 | c 115 | 116 | In the next example we will create the same Counter class using a generator function and use it 117 | in a for loop. 118 | 119 | :: 120 | 121 | def counter_generator(low, high): 122 | while low <= high: 123 | yield low 124 | low += 1 125 | 126 | >>> for i in counter_generator(5,10): 127 | ... print(i, end=' ') 128 | ... 129 | 5 6 7 8 9 10 130 | 131 | Inside the while loop when it reaches to the *yield* statement, the value of low is returned 132 | and the generator state is suspended. During the second *next* call the generator resumed where 133 | it freeze-ed before and then the value of *low* is increased by one. It continues with the 134 | while loop and comes to the *yield* statement again. 135 | 136 | When you call an generator function it returns a \*generator* object. If you call \*dir* 137 | on this object you will find that it contains *__iter__* and \*__next__* methods among the 138 | other methods. 139 | 140 | :: 141 | 142 | >>> c = counter_generator(5,10) 143 | >>> dir(c) 144 | ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', 145 | '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', 146 | '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__reduce__', 147 | '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 148 | 'close', 'gi_code', 'gi_frame', 'gi_running', 'send', 'throw'] 149 | 150 | We mostly use generators for laze evaluations. This way generators become a good approach 151 | to work with lots of data. If you don't want to load all the data in the memory, you can use 152 | a generator which will pass you each piece of data at a time. 153 | 154 | One of the biggest example of such example is *os.path.walk()* function which uses a callback 155 | function and current *os.walk* generator. Using the generator implementation saves memory. 156 | 157 | We can have generators which produces infinite values. The following is a one such example. 158 | 159 | :: 160 | 161 | >>> def infinite_generator(start=0): 162 | ... while True: 163 | ... yield start 164 | ... start += 1 165 | ... 166 | >>> for num in infinite_generator(4): 167 | ... print(num, end=' ') 168 | ... if num > 20: 169 | ... break 170 | ... 171 | 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 172 | 173 | If we go back to the example of *my_generator* we will find one feature of generators. 174 | They are not re-usable. 175 | 176 | :: 177 | 178 | >>> g = my_generator() 179 | >>> for c in g: 180 | ... print(c) 181 | ... 182 | Inside my generator 183 | a 184 | b 185 | c 186 | >>> for c in g: 187 | ... print(c) 188 | ... 189 | 190 | One way to create a reusable generator is Object based generators which do not hold any state. Any class with a *__iter__* method which yields data can be used as an object generator. 191 | In the following example we will recreate our counter generator. 192 | 193 | :: 194 | 195 | >>> class Counter(object): 196 | ... def __init__(self, low, high): 197 | ... self.low = low 198 | ... self.high = high 199 | ... def __iter__(self): 200 | ... counter = self.low 201 | ... while self.high >= counter: 202 | ... yield counter 203 | ... counter += 1 204 | ... 205 | >>> gobj = Counter(5, 10) 206 | >>> for num in gobj: 207 | ... print(num, end=' ') 208 | ... 209 | 5 6 7 8 9 10 210 | >>> for num in gobj: 211 | ... print(num, end=' ') 212 | ... 213 | 5 6 7 8 9 10 214 | 215 | Generator expressions 216 | ===================== 217 | 218 | In this section we will learn about generator expressions which is a high 219 | performance, memory efficient generalization of list comprehensions and generators. 220 | 221 | For example we will try to sum the squares of all numbers from 1 to 9. 222 | 223 | :: 224 | 225 | >>> sum([x*x for x in range(1,10)]) 226 | 227 | The example actually first creates a list of the square values in memory and then it 228 | iterates over it and finally after sum it frees the memory. You can understand the memory 229 | usage in case of a big list. 230 | 231 | We can save memory usage by using a generator expression. 232 | 233 | :: 234 | 235 | sum(x*x for x in range(1,10)) 236 | 237 | The syntax of generator expression says that always needs to be directly inside a set of parentheses and cannot have a comma on either side. Which basically means both the examples below are valid generator expression usage example. 238 | 239 | :: 240 | 241 | >>> sum(x*x for x in range(1,10)) 242 | 285 243 | >>> g = (x*x for x in range(1,10)) 244 | >>> g 245 | at 0x7fc559516b90> 246 | 247 | We can have chaining of generators or generator expressions. In the following 248 | example we will read the file \*/var/log/cron* and will find if any particular 249 | job (in the example we are searching for anacron) is running successfully or not. 250 | 251 | We can do the same using a shell command *tail -f /var/log/cron |grep anacron* 252 | 253 | :: 254 | 255 | >>> jobtext = 'anacron' 256 | >>> all_lines = (line for line in open('/var/log/cron', 'r') ) 257 | >>> job = ( line for line in all_lines if line.find(jobtext) != -1) 258 | >>> text = next(job) 259 | >>> text 260 | "May 6 12:17:15 dhcp193-104 anacron[23052]: Job `cron.daily' terminated\n" 261 | >>> text = next(job) 262 | >>> text 263 | 'May 6 12:17:15 dhcp193-104 anacron[23052]: Normal exit (1 job run)\n' 264 | >>> text = next(job) 265 | >>> text 266 | 'May 6 13:01:01 dhcp193-104 run-parts(/etc/cron.hourly)[25907]: starting 0anacron\n' 267 | 268 | You can write a for loop to the lines. 269 | 270 | Closures 271 | ======== 272 | 273 | Closures are nothing but functions that are returned by another function. We use 274 | closures to remove code duplication. In the following example we create 275 | a simple closure for adding numbers. 276 | 277 | :: 278 | 279 | >>> def add_number(num): 280 | ... def adder(number): 281 | ... 'adder is a closure' 282 | ... return num + number 283 | ... return adder 284 | ... 285 | >>> a_10 = add_number(10) 286 | >>> a_10(21) 287 | 31 288 | >>> a_10(34) 289 | 44 290 | >>> a_5 = add_number(5) 291 | >>> a_5(3) 292 | 8 293 | 294 | *adder* is a closure which adds a given number to a pre-defined one. 295 | 296 | Decorators 297 | ========== 298 | 299 | Decorator is way to dynamically add some new behavior to some objects. We achieve 300 | the same in Python by using closures. 301 | 302 | In the example we will create a simple example which will print some statement before 303 | and after the execution of a function. 304 | 305 | :: 306 | 307 | >>> def my_decorator(func): 308 | ... def wrapper(*args, **kwargs): 309 | ... print("Before call") 310 | ... result = func(*args, **kwargs) 311 | ... print("After call") 312 | ... return result 313 | ... return wrapper 314 | ... 315 | >>> @my_decorator 316 | ... def add(a, b): 317 | ... "Our add function" 318 | ... return a + b 319 | ... 320 | >>> add(1, 3) 321 | Before call 322 | After call 323 | 4 324 | -------------------------------------------------------------------------------- /docs/img/averagen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/averagen.png -------------------------------------------------------------------------------- /docs/img/checkname_pyper.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/checkname_pyper.gif -------------------------------------------------------------------------------- /docs/img/code_disable_telemetry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/code_disable_telemetry.png -------------------------------------------------------------------------------- /docs/img/code_install_python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/code_install_python.png -------------------------------------------------------------------------------- /docs/img/code_welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/code_welcome.png -------------------------------------------------------------------------------- /docs/img/cpx.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/cpx.gif -------------------------------------------------------------------------------- /docs/img/greater_notyping.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/greater_notyping.gif -------------------------------------------------------------------------------- /docs/img/greater_withtyping.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/greater_withtyping.gif -------------------------------------------------------------------------------- /docs/img/hello_flask_Index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/hello_flask_Index.png -------------------------------------------------------------------------------- /docs/img/hello_flask_hello.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/hello_flask_hello.png -------------------------------------------------------------------------------- /docs/img/helloworld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/helloworld.png -------------------------------------------------------------------------------- /docs/img/helloworld_pyper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/helloworld_pyper.png -------------------------------------------------------------------------------- /docs/img/how_to_get_device_simulator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/how_to_get_device_simulator.gif -------------------------------------------------------------------------------- /docs/img/installing_devicesimulator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/installing_devicesimulator.gif -------------------------------------------------------------------------------- /docs/img/investment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/investment.png -------------------------------------------------------------------------------- /docs/img/list_first.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/list_first.png -------------------------------------------------------------------------------- /docs/img/mu_running_code.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/mu_running_code.gif -------------------------------------------------------------------------------- /docs/img/mu_starting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/mu_starting.gif -------------------------------------------------------------------------------- /docs/img/oneneoatatime.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/oneneoatatime.gif -------------------------------------------------------------------------------- /docs/img/onoff.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/onoff.gif -------------------------------------------------------------------------------- /docs/img/red_light.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/red_light.gif -------------------------------------------------------------------------------- /docs/img/redthenblue.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/redthenblue.gif -------------------------------------------------------------------------------- /docs/img/rgb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/rgb.gif -------------------------------------------------------------------------------- /docs/img/temperature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/temperature.png -------------------------------------------------------------------------------- /docs/img/testhundred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/testhundred.png -------------------------------------------------------------------------------- /docs/img/textinput_pyper.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/textinput_pyper.gif -------------------------------------------------------------------------------- /docs/img/theidemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/theidemo.gif -------------------------------------------------------------------------------- /docs/img/twocard_pyper.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/twocard_pyper.gif -------------------------------------------------------------------------------- /docs/img/yellow_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kushaldas/pym/5fc552f50d8d72e82f83a6b667a46f1d9683a21c/docs/img/yellow_light.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Python for you and me documentation master file, created by 2 | sphinx-quickstart on Tue Jul 9 14:32:48 2013. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Python for you and me 7 | ================================== 8 | 9 | This is a simple book to learn Python programming language, it is for the programmers who are new to Python. 10 | 11 | You can find the latest version of the book `here `_. 12 | 13 | If you are new to command line in Linux, you can read `lym `_. 14 | 15 | Contents: 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | 20 | installation 21 | thebeginning 22 | mu 23 | variablesanddatatypes 24 | operatorsexpressions 25 | ifelse 26 | hardwaresimulation 27 | looping 28 | loopingonhardware 29 | datastructure 30 | strings 31 | functions 32 | file 33 | exceptions 34 | classes 35 | modules 36 | collections 37 | editors 38 | pep8 39 | igd 40 | virtualenv 41 | typehinting 42 | testing 43 | projectstructure 44 | click 45 | pypercard 46 | flask 47 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 |  2 | 3 | ============ 4 | Installation 5 | ============ 6 | 7 | In this chapter you will learn how to install Python 3, the latest version of the language. 8 | 9 | 10 | On Windows 11 | ========== 12 | 13 | Download the latest Windows(TM) installer from the Python site, `x86_64 14 | `_. Install it just 15 | as any other Windows software. 16 | 17 | On GNU/Linux 18 | ============ 19 | 20 | Install the latest Python from the distribution's repository. 21 | 22 | For Fedora 23 and above Python3 is in the system by default. 23 | 24 | 25 | For Debian/Ubuntu 26 | 27 | :: 28 | 29 | [user@host]$ sudo apt-get install python3-all python3-venv python3-pip 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/loopingonhardware.rst: -------------------------------------------------------------------------------- 1 | ====================== 2 | Looping over hardware 3 | ====================== 4 | 5 | 6 | In this chapter we learn about looping using hardware (simulation). 7 | 8 | 9 | 10 | One NeoPixel at a time 11 | ----------------------- 12 | 13 | .. figure:: img/oneneoatatime.gif 14 | 15 | The `cpx.pixels` can be accessed by index numbers, from 0 to 9. This way, we can turn on 16 | one NeoPixel at a time. 17 | 18 | .. code-block:: python 19 | :linenos: 20 | 21 | # import CPX library 22 | from adafruit_circuitplayground.express import cpx 23 | import time 24 | 25 | BLUE = (0, 0, 255) 26 | 27 | i = 0 28 | 29 | while True: 30 | # start your code here 31 | if i == 10: 32 | time.sleep(10) 33 | continue 34 | cpx.pixels[i] = BLUE 35 | i += 1 36 | time.sleep(0.5) 37 | 38 | On line number *7*, we declared a variable which selects the correct NeoPixel, 39 | and then on line number 14 we are turning on that NeoPixel to Blue color, and 40 | then increasing the variable to go to the next NeoPixel. The conditional *if 41 | statement* on line 11 makes sure that when we turn on all the lights, we sleep 42 | for 10 seconds and continue to do so. 43 | 44 | 45 | First Red and then Blue 46 | ------------------------ 47 | 48 | 49 | .. figure:: img/redthenblue.gif 50 | 51 | Here using two for loops, we are first turning on each NeoPixel in Red and then in Blue. 52 | 53 | .. code-block:: python 54 | :linenos: 55 | 56 | # import CPX library 57 | from adafruit_circuitplayground.express import cpx 58 | import time 59 | 60 | RED = (255, 0, 0) 61 | BLUE = (0, 0, 255) 62 | 63 | while True: 64 | for i in range(0, 10): 65 | cpx.pixels[i] = RED 66 | time.sleep(0.5) 67 | 68 | time.sleep(0.5) 69 | 70 | for i in range(0, 10): 71 | cpx.pixels[i] = BLUE 72 | time.sleep(0.5) 73 | 74 | -------------------------------------------------------------------------------- /docs/mu.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | Using mu editor 3 | ================ 4 | 5 | Using a proper editor to write code can help a lot while programming or while 6 | working on actual projects. In this chapter we will learn about **mu editor**, 7 | which is a very simple and beginner friendly editor for anyone starting with 8 | Python. It is developed by Nicholas Tollervey. 9 | 10 | If you already have an editor of your choice, you can skip this chapter. 11 | 12 | Installation 13 | ============= 14 | 15 | The total download size is around 150MB. Means it will take some time. Give 16 | the following command as your normal user. 17 | 18 | :: 19 | 20 | $ python3 -m pip install -U mu-editor --user 21 | 22 | 23 | 24 | Using mu 25 | ========= 26 | 27 | You can open the editor from the command line, type **mu** in the terminal. 28 | 29 | :: 30 | 31 | $ python3 -m mu 32 | 33 | 34 | .. figure:: img/mu_starting.gif 35 | 36 | 37 | Select Python 3 at the starting screen. Now, your mu editor is ready. 38 | 39 | 40 | Executing code 41 | =============== 42 | 43 | You will have to write any code you want to execute, and then save it with a 44 | proper filename (ends with .py). Then click on the **Run** button to execute 45 | the code. If you want a REPL, then click on the **REPL** button. 46 | 47 | .. note:: Remember not to give any space in the filename. Use _ if required, example: download_photos.py 48 | 49 | .. figure:: img/mu_running_code.gif 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /docs/operatorsexpressions.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | ========================= 4 | Operators and expressions 5 | ========================= 6 | 7 | In Python most of the lines you will write will be expressions. Expressions are made of operators and operands. An expression is like *2 + 3* . 8 | 9 | Operators 10 | ========= 11 | 12 | Operators are the symbols which tells the Python interpreter to do some mathematical or logical operation. Few basic examples of mathematical operators are given below: 13 | 14 | :: 15 | 16 | >>> 2 + 3 17 | 5 18 | >>> 23 - 3 19 | 20 20 | >>> 22.0 / 12 21 | 1.8333333333333333 22 | 23 | To get floating result you need to the division using any of operand as floating number. To do modulo operation use % operator 24 | 25 | :: 26 | 27 | >>> 14 % 3 28 | 2 29 | 30 | Example of integer arithmetic 31 | ============================= 32 | 33 | The code 34 | 35 | :: 36 | 37 | #!/usr/bin/env python3 38 | days = int(input("Enter days: ")) 39 | months = days / 30 40 | days = days % 30 41 | print("Months = %d Days = %d" % (months, days)) 42 | 43 | The output 44 | 45 | :: 46 | 47 | $ ./integer.py 48 | Enter days: 265 49 | Months = 8 Days = 25 50 | 51 | In the first line I am taking the input of days, then getting the months and days and at last printing them. You can do it in a easy way 52 | 53 | :: 54 | 55 | #!/usr/bin/env python3 56 | days = int(input("Enter days: ")) 57 | print("Months = %d Days = %d" % (divmod(days, 30))) 58 | 59 | The divmod(num1, num2) function returns two values , first is the division of num1 and num2 and in second the modulo of num1 and num2. 60 | 61 | Relational Operators 62 | ==================== 63 | 64 | You can use the following operators as relational operators 65 | 66 | Relational Operators 67 | -------------------- 68 | 69 | +----------+-----------------------------+ 70 | | Operator | Meaning | 71 | +----------+-----------------------------+ 72 | | \< | Is less than | 73 | +----------+-----------------------------+ 74 | | <= | Is less than or equal to | 75 | +----------+-----------------------------+ 76 | | > | Is greater than | 77 | +----------+-----------------------------+ 78 | | >= | Is greater than or equal to | 79 | +----------+-----------------------------+ 80 | | \=\= | Is equal to | 81 | +----------+-----------------------------+ 82 | | != | Is not equal to | 83 | +----------+-----------------------------+ 84 | 85 | Some examples 86 | 87 | :: 88 | 89 | >>> 1 < 2 90 | True 91 | >>> 3 > 34 92 | False 93 | >>> 23 == 45 94 | False 95 | >>> 34 != 323 96 | True 97 | 98 | *//* operator gives the floor division result 99 | 100 | :: 101 | 102 | >>> 4.0 // 3 103 | 1.0 104 | >>> 4.0 / 3 105 | 1.3333333333333333 106 | 107 | Logical Operators 108 | ================= 109 | 110 | To do logical AND , OR we use *and* ,*or* keywords. *x and y* returns *False* if *x* is *False* else it returns evaluation of *y*. If *x* is *True*, it returns *True*. 111 | 112 | :: 113 | 114 | >>> 1 and 4 115 | 4 116 | >>> 1 or 4 117 | 1 118 | >>> -1 or 4 119 | -1 120 | >>> 0 or 4 121 | 4 122 | 123 | Shorthand Operator 124 | ================== 125 | 126 | *x op = expression* is the syntax for shorthand operators. It will be evaluated like *x = x op expression* , Few examples are 127 | 128 | :: 129 | 130 | >>> a = 12 131 | >>> a += 13 132 | >>> a 133 | 25 134 | >>> a /= 3 135 | >>> a 136 | 8.333333333333334 137 | >>> a += (26 * 32) 138 | >>> a 139 | 840.3333333333334 140 | 141 | shorthand.py example 142 | 143 | .. code-block:: python 144 | 145 | #!/usr/bin/env python3 146 | N = 100 147 | a = 2 148 | while a < N: 149 | print("%d" % a) 150 | a *= a 151 | 152 | The output 153 | 154 | :: 155 | 156 | $ ./shorthand.py 157 | 2 158 | 4 159 | 16 160 | 161 | Expressions 162 | =========== 163 | 164 | Generally while writing expressions we put spaces before and after every operator so that the code becomes clearer to read, like 165 | 166 | :: 167 | 168 | a = 234 * (45 - 56.0 / 34) 169 | 170 | One example code used to show expressions 171 | 172 | :: 173 | 174 | #!/usr/bin/env python3 175 | a = 9 176 | b = 12 177 | c = 3 178 | x = a - b / 3 + c * 2 - 1 179 | y = a - b / (3 + c) * (2 - 1) 180 | z = a - (b / (3 + c) * 2) - 1 181 | print("X = ", x) 182 | print("Y = ", y) 183 | print("Z = ", z) 184 | 185 | The output 186 | 187 | :: 188 | 189 | $ ./evaluationexp.py 190 | X = 10 191 | Y = 7 192 | Z = 4 193 | 194 | At first *x* is being calculated. The steps are like this 195 | 196 | :: 197 | 198 | 9 - 12 / 3 + 3 * 2 -1 199 | 9 - 4 + 3 * 2 - 1 200 | 9 - 4 + 6 - 1 201 | 5 + 6 - 1 202 | 11 - 1 203 | 10 204 | 205 | Now for *y* and *z* we have parentheses, so the expressions evaluated in different way. Do the calculation yourself to check them. 206 | 207 | Type Conversions 208 | ================ 209 | 210 | We have to do the type conversions manually. Like 211 | :: 212 | 213 | float(string) -> float value 214 | int(string) -> integer value 215 | str(integer) or str(float) -> string representation 216 | >>> a = 8.126768 217 | >>> str(a) 218 | '8.126768' 219 | 220 | evaluateequ.py 221 | ============== 222 | 223 | This is a program to evaluate 1/x+1/(x+1)+1/(x+2)+ ... +1/n series upto n, in our case x = 1 and n =10 224 | 225 | .. code-block:: python 226 | 227 | #!/usr/bin/env python3 228 | sum = 0.0 229 | for i in range(1, 11): 230 | sum += 1.0 / i 231 | print("%2d %6.4f" % (i , sum)) 232 | 233 | The output 234 | 235 | :: 236 | 237 | $ ./evaluateequ.py 238 | 1 1.0000 239 | 2 1.5000 240 | 3 1.8333 241 | 4 2.0833 242 | 5 2.2833 243 | 6 2.4500 244 | 7 2.5929 245 | 8 2.7179 246 | 9 2.8290 247 | 10 2.9290 248 | 249 | In the line *sum += 1.0 / i* what is actually happening is *sum = sum + 1.0 / i*. 250 | 251 | quadraticequation.py 252 | ==================== 253 | 254 | This is a program to evaluate the quadratic equation 255 | 256 | :: 257 | 258 | #!/usr/bin/env python3 259 | import math 260 | a = int(input("Enter value of a: ")) 261 | b = int(input("Enter value of b: ")) 262 | c = int(input("Enter value of c: ")) 263 | d = b * b - 4 * a * c 264 | if d < 0: 265 | print("ROOTS are imaginary") 266 | else: 267 | root1 = (-b + math.sqrt(d)) / (2.0 * a) 268 | root2 = (-b - math.sqrt(d)) / (2.0 * a) 269 | print("Root 1 = ", root1) 270 | print("Root 2 = ", root2) 271 | 272 | salesmansalary.py 273 | ================= 274 | 275 | In this example we are going to calculate the salary of a camera salesman. His basic salary is 1500, for every camera he will sell he will get 200 and the commission on the month's sale is 2 %. The input will be number of cameras sold and total price of the cameras. 276 | 277 | :: 278 | 279 | #!/usr/bin/env python3 280 | basic_salary = 1500 281 | bonus_rate = 200 282 | commision_rate = 0.02 283 | numberofcamera = int(input("Enter the number of inputs sold: ")) 284 | price = float(input("Enter the total prices: ")) 285 | bonus = (bonus_rate * numberofcamera) 286 | commision = (commision_rate * numberofcamera * price) 287 | print("Bonus = %6.2f" % bonus) 288 | print("Commision = %6.2f" % commision) 289 | print("Gross salary = %6.2f" % (basic_salary + bonus + commision)) 290 | 291 | The output 292 | 293 | :: 294 | 295 | $ ./salesmansalary.py 296 | Enter the number of inputs sold: 5 297 | Enter the total prices: 20450 298 | Bonus = 1000.00 299 | Commision = 2045.00 300 | Gross salary = 4545.00 301 | -------------------------------------------------------------------------------- /docs/projectstructure.rst: -------------------------------------------------------------------------------- 1 | 2 | ==================== 3 | A project structure 4 | ==================== 5 | 6 | This chapter explains a full Python project structure. What kind of directory 7 | layout you can use and how make release a software to the world. 8 | 9 | We will call our example project *factorial*. 10 | :: 11 | 12 | $ mkdir pymfactorial 13 | $ cd pymfactorial/ 14 | 15 | Primary code 16 | ============= 17 | 18 | The name of the Python module will be *pymfactorial*, so we will create the directory 19 | next. 20 | 21 | :: 22 | 23 | $ mkdir -p pymfactorial/pymfactorial 24 | $ cd pymfactorial/ 25 | 26 | The primary code will be in a file called *fact.py* 27 | :: 28 | 29 | import sys 30 | 31 | def factorial(num): 32 | """ 33 | Returns the factorial value of the given number. 34 | 35 | :arg num: Interger value of whose factorial we will calculate. 36 | 37 | :return: The value of the the factorial or -1 in case negative value passed. 38 | """ 39 | if num >= 0: 40 | if num == 0: 41 | return 1 42 | return num * factorial(num -1) 43 | else: 44 | return -1 45 | 46 | 47 | def cli(): 48 | "The command line entry point" 49 | number = int(sys.argv[1]) 50 | print(f"Factorial is {factorial(number)}") 51 | 52 | 53 | We also have a *__init__.py* file for the module. 54 | 55 | :: 56 | 57 | "pymfactorial module and command line tool" 58 | 59 | __version__ = "0.1.0" 60 | 61 | from fact import factorial 62 | __all__ = [factorial, cli] 63 | 64 | We also added a *README.md* file. So, the directory structure looks like 65 | 66 | :: 67 | 68 | $ ls 69 | pymfactorial README.md 70 | $ ls pymfactorial/ 71 | fact.py __init__.py 72 | 73 | 74 | LICENSE file 75 | ============= 76 | 77 | Always remember to add a proper license to your project. You can take help 78 | from `this site `_ if you are new to software 79 | licensing. 80 | 81 | The following is the content of our project, which is licensed under **MIT**. 82 | 83 | :: 84 | 85 | MIT License 86 | 87 | Copyright (c) 2021 Kushal Das 88 | 89 | Permission is hereby granted, free of charge, to any person obtaining a copy 90 | of this software and associated documentation files (the "Software"), to deal 91 | in the Software without restriction, including without limitation the rights 92 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 93 | copies of the Software, and to permit persons to whom the Software is 94 | furnished to do so, subject to the following conditions: 95 | 96 | The above copyright notice and this permission notice shall be included in all 97 | copies or substantial portions of the Software. 98 | 99 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 100 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 101 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 102 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 103 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 104 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 105 | SOFTWARE. 106 | 107 | 108 | Installing flit package 109 | ==================================== 110 | 111 | You have to install *flit* package in your system. For this we are 112 | using a virtualenv. We will also install *wheel* 113 | package. 114 | 115 | :: 116 | 117 | $ python3 -m venv .venv 118 | $ source .venv/bin/activate 119 | $ python3 -m pip install flit wheel 120 | 121 | 122 | pyproject.toml 123 | =============== 124 | 125 | Finally we have to write a *pyproject.toml* which then can be used to create a source 126 | tarball or installing the software, or create a wheel to be uploaded to PyPI. 127 | 128 | `flit init` command will help to create the initial file for us, provide the proper input as it asks. 129 | 130 | :: 131 | 132 | $ flit init 133 | Module name [pymfactorial]: 134 | Author [Kushal Das]: 135 | Author email [kushal@sunet.se]: mail@kushaldas.in 136 | Home page [https://github.com/kushaldas/pymfactorial]: https://github.com/kushaldas/pym 137 | Choose a license (see http://choosealicense.com/ for more info) 138 | 1. MIT - simple and permissive 139 | 2. Apache - explicitly grants patent rights 140 | 3. GPL - ensures that code based on this is shared with the same terms 141 | 4. Skip - choose a license later 142 | Enter 1-4 [4]: 1 143 | 144 | Written pyproject.toml; edit that file to add optional extra info. 145 | 146 | This command created the `pyproject.toml` file in the same folder, we can check the conent. 147 | 148 | :: 149 | 150 | [build-system] 151 | requires = ["flit_core >=3.2,<4"] 152 | build-backend = "flit_core.buildapi" 153 | 154 | [project] 155 | name = "pymfactorial" 156 | authors = [{name = "Kushal Das", email = "mail@kushaldas.in"}] 157 | readme = "README.md" 158 | license = {file = "LICENSE"} 159 | classifiers = ["License :: OSI Approved :: MIT License"] 160 | dynamic = ["version", "description"] 161 | 162 | [project.urls] 163 | Home = "https://github.com/kushaldas/pym" 164 | 165 | 166 | Next we will update the file to make sure that we include the `LICENSE` and 167 | `README.md` file in the source tarball. We also mark the `cli` function as 168 | the starting point for the command line tool. 169 | 170 | :: 171 | 172 | [build-system] 173 | requires = ["flit_core >=3.2,<4"] 174 | build-backend = "flit_core.buildapi" 175 | 176 | [project] 177 | name = "pymfactorial" 178 | authors = [{name = "Kushal Das", email = "mail@kushaldas.in"}] 179 | readme = "README.md" 180 | license = {file = "LICENSE"} 181 | classifiers = ["License :: OSI Approved :: MIT License"] 182 | dynamic = ["version", "description"] 183 | 184 | [project.urls] 185 | Home = "https://github.com/kushaldas/pym" 186 | 187 | [project.scripts] 188 | myfact = "pymfactorial:cli" 189 | 190 | [tool.flit.sdist] 191 | include = ["LICENSE", "README.MD"] 192 | 193 | 194 | Please read `flit metadata documentation `_ for details of the various keys and their values mentioned above. 195 | 196 | 197 | 198 | Building a package 199 | ================== 200 | 201 | To create a source release and also a binary wheel for distribution, use the following 202 | command. 203 | 204 | :: 205 | 206 | $ flit build 207 | 208 | One can see the output files under *dist* directory. 209 | :: 210 | 211 | $ ls dist/ 212 | 213 | .. warning:: Remember to use a virtualenv while trying to install the code :) 214 | 215 | 216 | Python Package Index (PyPI) 217 | ============================ 218 | 219 | Do you remember the **pip** command we are using still now? Ever thought from 220 | where those packages are coming from? The answer is `PyPI `_. 221 | It is a repository of software for the Python programming language. 222 | 223 | For our example, we will use the test server of PyPI which is `https://test.pypi.org/ `_ 224 | 225 | Creating account 226 | ----------------- 227 | 228 | First register yourself in `this link 229 | `_. You will receive 230 | an email with a link, go to that link and confirm your registration. 231 | 232 | 233 | .. note:: Remember to change the name of the project 234 | to something else in the `setup.py` to test following 235 | instructions. 236 | 237 | Uploading your project 238 | ----------------------- 239 | 240 | Now finally we can upload our project to the PyPI server using **twine** command. 241 | Remember that this command needs to be invoked immediately after you build the 242 | source/binary distribution files. 243 | 244 | First, we will have to install **twine** using **pip** (we are using a virtualenv). 245 | 246 | :: 247 | 248 | $ python3 -m pip install twine 249 | $ twine upload --repository-url https://test.pypi.org/legacy/ dist/* 250 | Uploading distributions to https://test.pypi.org/legacy/ 251 | Enter your username: kushaldas 252 | Enter your password: 253 | Uploading pymfactorial-0.1-py3-none-any.whl 254 | 100%|██████████████████████████████████████| 4.29k/4.29k [00:01<00:00, 3.77kB/s] 255 | Uploading pymfactorial-0.1.tar.gz 256 | 100%|██████████████████████████████████████| 3.83k/3.83k [00:00<00:00, 7.57kB/s] 257 | 258 | Now if you visit the `site `_, you will 259 | find your project is ready to be used by others. 260 | 261 | Install from the test PyPI 262 | =========================== 263 | 264 | You can use the following command to install from the test PyPI. 265 | 266 | :: 267 | 268 | $ python3 -m pip install --index-url https://test.pypi.org/simple/ pymfactorial 269 | 270 | More readings 271 | ============== 272 | 273 | Please visit https://packaging.python.org to learn more about Python packaging. 274 | There are many guides and tutorials available on that site. `PEP-621 275 | `_ is also an important read. 276 | -------------------------------------------------------------------------------- /docs/pypercard.rst: -------------------------------------------------------------------------------- 1 | =================================================== 2 | Simple GUI application development using PyperCard 3 | =================================================== 4 | 5 | In this chapter we will learn about creating very simple GUI application using 6 | [PyperCard](https://pypercard.readthedocs.io/en/latest/). PyperCard is a 7 | HyperCard inspired Pythonic GUI framework for beginner programmers. 8 | 9 | 10 | 11 | Installing PyperCard in a virtualenv 12 | ------------------------------------- 13 | 14 | The first step would be installing PyperCard in a virtualenv. 15 | 16 | 17 | :: 18 | 19 | python3 -m venv venv 20 | source venv/bin/activate 21 | python3 -m pip install pypercard 22 | 23 | 24 | This may take some time, and specially while building Kivy, which is a dependency. 25 | 26 | 27 | If you see any error in building *Kivy* on your distribution, you will have to install all dependencies 28 | on your operating system. 29 | 30 | On Debian Buster 31 | 32 | :: 33 | 34 | sudo apt install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev pkg-config libgl1-mesa-dev libgles2-mesa-dev python3-setuptools libgstreamer1.0-dev git-core gstreamer1.0-plugins-{bad,base,good,ugly} gstreamer1.0-{omx,alsa} python3-dev libmtdev-dev xclip xsel libjpeg-dev mesa-common-dev 35 | 36 | 37 | 38 | Hello World example 39 | ------------------- 40 | 41 | 42 | .. code-block:: python 43 | :linenos: 44 | 45 | from pypercard import Card, CardApp 46 | 47 | 48 | card = Card("hello", text="Hello, World!", text_color="yellow") 49 | 50 | app = CardApp(stack=[card, ]) 51 | app.run() 52 | 53 | 54 | In the first line, we are importing two classes from the module. ``Card`` is 55 | the class for every screen in our application, and ``CardApp`` is the primary 56 | application. 57 | 58 | .. note:: 59 | 60 | Remember that each card in your application must have an unique name. 61 | 62 | If you execute the code, `python3 hello.py`, you will see the following GUI 63 | window. It does not do much, it shows the string "Hello World!" with the text 64 | color we mentioned (Yellow). 65 | 66 | .. figure:: img/helloworld_pyper.png 67 | 68 | 69 | Two Cards and a button 70 | ----------------------- 71 | 72 | .. code-block:: python 73 | :linenos: 74 | 75 | from pypercard import Card, CardApp 76 | 77 | 78 | first_card = Card( 79 | "first_card", 80 | text="Hello, World!", 81 | text_color="yellow", 82 | buttons=[{"label": "Next", "target": "byescreen"}], 83 | ) 84 | card2 = Card("byescreen", text="Hack the planet!", text_color="white") 85 | 86 | app = CardApp(stack=[first_card, card2]) 87 | app.run() 88 | 89 | 90 | In this code, we have two different cards. The ``first_card`` also got a button, with a text *Next*, and the *target* as the name 91 | of the next card to show. In this case, we are showing the card named *bye* 92 | 93 | .. figure:: img/twocard_pyper.gif 94 | 95 | 96 | Taking simple text input 97 | ------------------------- 98 | 99 | 100 | In this example, we will learn how to take simple text input. 101 | 102 | .. code-block:: python 103 | :linenos: 104 | 105 | 106 | from pypercard import Card, CardApp, Inputs 107 | 108 | 109 | def store_name(data_store, form_value): 110 | """ 111 | Stores the user input in the data_store dictionary 112 | """ 113 | if form_value: 114 | data_store["name"] = form_value 115 | return "showname" 116 | else: 117 | return "error" 118 | 119 | 120 | card = Card( 121 | "start", 122 | text="Enter your name", 123 | text_color="yellow", 124 | form=Inputs.TEXTBOX, 125 | buttons=[{"label": "Next", "target": store_name}], 126 | ) 127 | 128 | card2 = Card("showname", text="May the force be with you {name}.", text_color="white") 129 | 130 | errorcard = Card( 131 | "error", 132 | text="You forgot to enter a name", 133 | text_color="RED", 134 | buttons=[{"label": "Start again", "target": "start"}], 135 | ) 136 | app = CardApp(stack=[card, card2, errorcard]) 137 | app.run() 138 | 139 | At line 1, we are importing **Inputs**, which has various graphical objects 140 | to take user input. 141 | 142 | In line 19, you can see that we passed a new keyword argument to the ``card`` 143 | object called *form* and saying that it is a ``Inputs.TEXTBOX``. Another big 144 | change is that as a target of the button, we are passing a function called 145 | ``store_name``. This can be any function which takes two arguments, first one 146 | is called ``data_store``, a dictionary passed from the application itself, and 147 | then ``form_value`` is the actual user input via the card. Here, we are 148 | checking if there is a proper user input, then we are storing the value in the 149 | dictionary with the key **name** and returning the next card name 150 | **showname**, otherwise we are showing the **error** card from the stack. 151 | 152 | In line 23, we are creating the **showname** card, where you can see we can 153 | directly use any keyname of ``data_store``. 154 | 155 | .. figure:: img/textinput_pyper.gif 156 | 157 | Check name problem 158 | ------------------- 159 | 160 | Here is a small problem for you, change the code such a way, so that if the 161 | name starts with **Python**, then the next screen will tell us the version of 162 | Python we are running. 163 | 164 | .. figure:: img/checkname_pyper.gif 165 | 166 | .. rst-class:: html-toggle 167 | 168 | Check name solution 169 | -------------------- 170 | 171 | .. code-block:: python 172 | :linenos: 173 | 174 | from pypercard import Card, CardApp, Inputs 175 | import sys 176 | 177 | 178 | def store_name(data_store, form_value): 179 | """ 180 | Stores the user input in the data_store dictionary 181 | """ 182 | if form_value: 183 | if form_value.startswith("Python"): 184 | data_store["msg"] = sys.version.replace("\n", "") 185 | else: 186 | data_store["msg"] = "May the force be with you {0}.".format(form_value) 187 | return "showname" 188 | else: 189 | return "error" 190 | 191 | 192 | card = Card( 193 | "start", 194 | text="Enter your name", 195 | text_color="yellow", 196 | form=Inputs.TEXTBOX, 197 | buttons=[{"label": "Next", "target": store_name}], 198 | ) 199 | card2 = Card( 200 | "showname", 201 | text="{msg}", 202 | text_color="white", 203 | buttons=[{"label": "Start again", "target": "start"}], 204 | ) 205 | 206 | errorcard = Card( 207 | "error", 208 | text="You forgot to enter a name", 209 | text_color="RED", 210 | buttons=[{"label": "Start again", "target": "start"}], 211 | ) 212 | app = CardApp(stack=[card, card2, errorcard]) 213 | app.run() 214 | -------------------------------------------------------------------------------- /docs/strings.rst: -------------------------------------------------------------------------------- 1 | 2 | ======= 3 | Strings 4 | ======= 5 | 6 | Strings are nothing but simple text. In Python we declare strings in between "" or '' or ''' ''' or """ """. The examples below will help you to understand string in a better way. 7 | 8 | :: 9 | 10 | >>> s = "I love Python 🐍" 11 | >>> s 12 | 'I love Python 🐍' 13 | >>> s = 'I love Python 🐍' 14 | >>> s = "Here is a line \ 15 | ... split in two lines" 16 | >>> s 17 | 'Here is a line split in two lines' 18 | >>> s = "Here is a line \n split in two lines" 19 | >>> s 20 | 'Here is a line \n split in two lines' 21 | >>> print(s) 22 | Here is a line 23 | split in two lines 24 | 25 | Now if you want to multiline strings you have to use triple single/double quotes. 26 | 27 | :: 28 | 29 | >>> s = """ This is a 30 | ... multiline string, so you can 31 | ... write many lines""" 32 | >>> print(s) 33 | This is a 34 | multiline string, so you can 35 | write many lines 36 | 37 | 38 | We can have two string literals side by side, and it will behave like a single string. For example 39 | 40 | :: 41 | 42 | >>> s = "Hello " "World" 43 | >>> print(s) 44 | Hello World 45 | 46 | This will help you to spilt a long string into smaller chunks in function calls. 47 | 48 | 49 | You can find length of any string using the `len` function call. 50 | 51 | :: 52 | 53 | >>> s = "Python" 54 | >>> len(s) 55 | 6 56 | 57 | 58 | Different methods available for Strings 59 | ======================================= 60 | 61 | Every string object is having couple of builtin methods available, we already saw some of them like *s.split(" ")*. 62 | 63 | :: 64 | 65 | >>> s = "kushal das" 66 | >>> s.title() 67 | 'Kushal Das' 68 | 69 | *title()* method returns a titlecased version of the string, words start with uppercase characters, all remaining cased characters are lowercase. 70 | 71 | :: 72 | 73 | >>> z = s.upper() 74 | >>> z 75 | 'KUSHAL DAS' 76 | >>> z.lower() 77 | 'kushal das' 78 | 79 | *upper()* returns a total uppercase version whereas *lower()* returns a lower case version of the string. 80 | 81 | :: 82 | 83 | >>> s = "I am A pRoGraMMer" 84 | >> s.swapcase() 85 | 'i AM a PrOgRAmmER' 86 | 87 | *swapcase()* returns the string with case swapped :) 88 | 89 | :: 90 | 91 | >>> s = "jdwb 2323bjb" 92 | >>> s.isalnum() 93 | False 94 | >>> s = "jdwb2323bjb" 95 | >>> s.isalnum() 96 | True 97 | 98 | Because of the space in the first line *isalnum()* returned *False* , it checks for all characters are alpha numeric or not. 99 | 100 | :: 101 | 102 | >>> s = "SankarshanSir" 103 | >>> s.isalpha() 104 | True 105 | >>> s = "Sankarshan Sir" 106 | >>> s.isalpha() 107 | False 108 | 109 | *isalpha()* checkes for only alphabets. 110 | 111 | :: 112 | 113 | >>> s = "1234" 114 | >>> s.isdigit() # To check if all the characters are digits or not 115 | True 116 | >>> s = "Fedora9 is coming" 117 | >>> s.islower() # To check if all chracters are lower case or not 118 | False 119 | >>> s = "Fedora9 Is Coming" 120 | >>> s.istitle() # To check if it is a title or not 121 | True 122 | >>> s = "INDIA" 123 | >>> s.isupper() # To check if characters are in upper case or not 124 | True 125 | 126 | To split any string we have *split()*. It takes a string as an argument , depending on that it will split the main string and returns a list containing splitted strings. 127 | 128 | :: 129 | 130 | >>> s = "We all love Python" 131 | >>> s.split(" ") 132 | ['We', 'all', 'love', 'Python'] 133 | >>> x = "Nishant:is:waiting" 134 | >>> x.split(':') 135 | ['Nishant', 'is', 'waiting'] 136 | 137 | The opposite method for *split()* is *join()*. It takes a list contains strings as input and join them. 138 | 139 | :: 140 | 141 | >>> "-".join("GNU/Linux is great".split(" ")) 142 | 'GNU/Linux-is-great' 143 | 144 | In the above example first we are splitting the string "GNU/Linux is great" based on the white space, then joining them with "-". 145 | 146 | Strip the strings 147 | ================= 148 | 149 | Strings do have few methods to do striping. The simplest one is *strip(chars)*. If you provide the chars argument then it will strip any combination of them. By default it strips only whitespace or newline characters. 150 | 151 | :: 152 | 153 | >>> s = " abc\n " 154 | >>> s.strip() 155 | 'abc' 156 | 157 | You can particularly strip from the left hand or right hand side also using *lstrip(chars)* or *rstrip(chars)*. 158 | 159 | :: 160 | 161 | >>> s = "www.foss.in" 162 | >>> s.lstrip("cwsd.") 163 | 'foss.in' 164 | >>> s.rstrip("cnwdi.") 165 | 'www.foss' 166 | 167 | 168 | Justifying text 169 | =============== 170 | 171 | We can use `rjust` or `ljust` methods to either right justify or left justify 172 | any given string. We have to provide the number of characters we want to 173 | justify, and the character we want use for the justification (while a 174 | whitespace too). 175 | 176 | :: 177 | 178 | >>> "ACAB".rjust(10, "-") 179 | '------ACAB' 180 | >>> "ACAB".ljust(10, "-") 181 | 'ACAB------' 182 | 183 | 184 | Finding text 185 | ============ 186 | 187 | Strings have some methods which will help you in finding text/substring in a string. Examples are given below: 188 | 189 | :: 190 | 191 | >>> s = "faulty for a reason" 192 | >>> s.find("for") 193 | 7 194 | >>> s.find("fora") 195 | -1 196 | >>> s.startswith("fa") #To check if the string startswith fa or not 197 | True 198 | >>> s.endswith("reason") #To check if the string endswith reason or not 199 | True 200 | 201 | *find()* helps to find the first occurrence of the substring given, if not found it returns -1. 202 | 203 | Palindrome checking 204 | =================== 205 | 206 | Palindrome are the kind of strings which are same from left or right whichever way you read them. Example "madam". In this example we will take the word as input from the user and say if it is palindrome or not. 207 | 208 | .. code-block:: python 209 | 210 | #!/usr/bin/env python3 211 | s = input("Please enter a string: ") 212 | z = s[::-1] 213 | if s == z: 214 | print("The string is a palindrome") 215 | else: 216 | print("The string is not a palindrome") 217 | 218 | The output 219 | 220 | :: 221 | 222 | $ ./palindrome.py 223 | Please enter a string: madam1 224 | The string is not a palindrome 225 | $ ./palindrome.py 226 | Please enter a string: madam 227 | The string is a palindrome 228 | 229 | Number of words 230 | =============== 231 | 232 | In this example we will count the number of words in a given line 233 | 234 | :: 235 | 236 | #!/usr/bin/env python3 237 | s = input("Enter a line: ") 238 | print("The number of words in the line are %d" % (len(s.split(" ")))) 239 | 240 | The output 241 | :: 242 | 243 | $ ./countwords.py 244 | Enter a line: Sayamindu is a great programmer 245 | The number of words in the line are 5 246 | 247 | 248 | Iterating over all characters of a string 249 | ========================================== 250 | 251 | You can iterate over a string using simple `for` loop. 252 | 253 | :: 254 | 255 | >>> for ch in "Python": 256 | ... print(ch) 257 | ... 258 | P 259 | y 260 | t 261 | h 262 | o 263 | n 264 | 265 | -------------------------------------------------------------------------------- /docs/testing.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Simple testing in Python 3 | ======================== 4 | 5 | 6 | 7 | What we should test ? 8 | ===================== 9 | 10 | If possible everything in our codebase, each and every function. But it depends 11 | as a choice of the developers. You can skip it if it is not practical to write 12 | a robust test. As `Nick Coghlan `_ said in a 13 | guest session -- *... with a solid test suite, you can make big changes, 14 | confident that the externally visible behavior will remain the same* 15 | 16 | To have effective tests, you should remember to write/split your code in 17 | smaller functions which can be tested separately. It is very easy to keep 18 | writing longer functions, which can do a lot of things at once. But, it will be 19 | increasingly difficult to test those functions. If you keep them short, and 20 | make sure that one function does one thing well, it will help to write better 21 | test cases. 22 | 23 | Unit testing 24 | ============= 25 | 26 | A method by which individual units of source code. `Wikipedia `_ says 27 | *In computer programming, unit testing is a method by which individual units of source code, 28 | sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine if they are fit for use.* 29 | 30 | 31 | unittest module 32 | =============== 33 | In Python we have ``unittest`` module to help us. 34 | 35 | Factorial code 36 | =============== 37 | 38 | In this example we will write a file `factorial.py`. 39 | :: 40 | 41 | import sys 42 | 43 | def fact(n): 44 | """ 45 | Factorial function 46 | 47 | :arg n: Number 48 | :returns: factorial of n 49 | 50 | """ 51 | if n == 0: 52 | return 1 53 | return n * fact(n -1) 54 | 55 | def div(n): 56 | """ 57 | Just divide 58 | """ 59 | res = 10 / n 60 | return res 61 | 62 | 63 | def main(n): 64 | res = fact(n) 65 | print(res) 66 | 67 | if __name__ == '__main__': 68 | if len(sys.argv) > 1: 69 | main(int(sys.argv[1])) 70 | 71 | 72 | Output 73 | :: 74 | 75 | $ python factorial.py 5 76 | 77 | Which function to test ? 78 | ======================== 79 | As you can see ``fact(n)`` is function which is doing all calculations, so 80 | we should test that at least. 81 | 82 | 83 | Our first test case 84 | =================== 85 | 86 | Now we will write our first test case. 87 | :: 88 | 89 | import unittest 90 | from factorial import fact 91 | 92 | class TestFactorial(unittest.TestCase): 93 | """ 94 | Our basic test class 95 | """ 96 | 97 | def test_fact(self): 98 | """ 99 | The actual test. 100 | Any method which starts with ``test_`` will considered as a test case. 101 | """ 102 | res = fact(5) 103 | self.assertEqual(res, 120) 104 | 105 | 106 | if __name__ == '__main__': 107 | unittest.main() 108 | 109 | 110 | Running the test: 111 | 112 | :: 113 | 114 | $ python factorial_test.py 115 | . 116 | ---------------------------------------------------------------------- 117 | Ran 1 test in 0.000s 118 | 119 | OK 120 | 121 | 122 | Description 123 | =========== 124 | We are importing ``unittest`` module first and then the required functions 125 | which we want to test. 126 | 127 | A testcase is created by subclassing ``unittest.TestCase``. 128 | 129 | Now open the test file and change *120* to *121* and see what happens :) 130 | 131 | 132 | Different assert statements 133 | =========================== 134 | +-----------------------------------------+-----------------------------+---------------+ 135 | | Method | Checks that | New in | 136 | +=========================================+=============================+===============+ 137 | | `assertEqual(a, b)` | ``a == b`` | | 138 | +-----------------------------------------+-----------------------------+---------------+ 139 | | `assertNotEqual(a, b)` | ``a != b`` | | 140 | +-----------------------------------------+-----------------------------+---------------+ 141 | | `assertTrue(x)` | ``bool(x) is True`` | | 142 | +-----------------------------------------+-----------------------------+---------------+ 143 | | `assertFalse(x)` | ``bool(x) is False`` | | 144 | +-----------------------------------------+-----------------------------+---------------+ 145 | | `assertIs(a, b)` | ``a is b`` | 2.7 | 146 | +-----------------------------------------+-----------------------------+---------------+ 147 | | `assertIsNot(a, b)` | ``a is not b`` | 2.7 | 148 | +-----------------------------------------+-----------------------------+---------------+ 149 | | `assertIsNone(x)` | ``x is None`` | 2.7 | 150 | +-----------------------------------------+-----------------------------+---------------+ 151 | | `assertIsNotNone(x)` | ``x is not None`` | 2.7 | 152 | +-----------------------------------------+-----------------------------+---------------+ 153 | | `assertIn(a, b)` | ``a in b`` | 2.7 | 154 | +-----------------------------------------+-----------------------------+---------------+ 155 | | `assertNotIn(a, b)` | ``a not in b`` | 2.7 | 156 | +-----------------------------------------+-----------------------------+---------------+ 157 | | `assertIsInstance(a, b)` | ``isinstance(a, b)`` | 2.7 | 158 | +-----------------------------------------+-----------------------------+---------------+ 159 | | `assertNotIsInstance(a, b)` | ``not isinstance(a, b)`` | 2.7 | 160 | +-----------------------------------------+-----------------------------+---------------+ 161 | 162 | 163 | Testing exceptions 164 | ================== 165 | If we call ``div(0)`` in factorial.py , we can see if raises an exception. 166 | 167 | We can also test these exceptions, like: 168 | 169 | :: 170 | 171 | self.assertRaises(ZeroDivisionError, div, 0) 172 | 173 | Full code 174 | :: 175 | 176 | import unittest 177 | from factorial import fact, div 178 | 179 | class TestFactorial(unittest.TestCase): 180 | """ 181 | Our basic test class 182 | """ 183 | 184 | def test_fact(self): 185 | """ 186 | The actual test. 187 | Any method which starts with ``test_`` will considered as a test case. 188 | """ 189 | res = fact(5) 190 | self.assertEqual(res, 120) 191 | 192 | def test_error(self): 193 | """ 194 | To test exception raise due to run time error 195 | """ 196 | self.assertRaises(ZeroDivisionError, div, 0) 197 | 198 | 199 | 200 | if __name__ == '__main__': 201 | unittest.main() 202 | 203 | 204 | .. note:: The following example is for Linux only, you will have to modify the code so that it can find mount details in other operating systems properly. 205 | 206 | mounttab.py 207 | ============ 208 | 209 | Here we have only one function *mount_details()* doing the parsing and printing mount details. 210 | 211 | :: 212 | 213 | import os 214 | 215 | 216 | def mount_details(): 217 | """ 218 | Prints the mount details 219 | """ 220 | if os.path.exists('/proc/mounts'): 221 | fd = open('/proc/mounts') 222 | for line in fd: 223 | line = line.strip() 224 | words = line.split() 225 | print(f'{words[0]} on {words[1]} type {words[2]}', end=' ') 226 | if len(words) > 5: 227 | print('(%s)' % ' '.join(words[3:-2])) 228 | else: 229 | print('') 230 | 231 | 232 | if __name__ == '__main__': 233 | mount_details() 234 | 235 | 236 | After refactoring 237 | ================= 238 | 239 | Now we refactored the code and have one new function *parse_mounts* which we can test easily. 240 | 241 | :: 242 | 243 | import os 244 | 245 | def parse_mounts(): 246 | """ 247 | It parses /proc/mounts and returns a list of tuples 248 | """ 249 | result = [] 250 | if os.path.exists('/proc/mounts'): 251 | fd = open('/proc/mounts') 252 | for line in fd: 253 | line = line.strip() 254 | words = line.split() 255 | if len(words) > 5: 256 | res = (words[0],words[1],words[2], '(%s)' % ' '.join(words[3:-2])) 257 | else: 258 | res = (words[0],words[1],words[2]) 259 | result.append(res) 260 | return result 261 | 262 | def mount_details(): 263 | """ 264 | Prints the mount details 265 | """ 266 | result = parse_mounts() 267 | for line in result: 268 | if len(line) == 4: 269 | print('%s on %s type %s %s' % line) 270 | else: 271 | print('%s on %s type %s' % line) 272 | 273 | 274 | if __name__ == '__main__': 275 | mount_details() 276 | 277 | and the test code for the same. 278 | :: 279 | 280 | #!/usr/bin/env python 281 | import unittest 282 | from mounttab2 import parse_mounts 283 | 284 | class TestMount(unittest.TestCase): 285 | """ 286 | Our basic test class 287 | """ 288 | 289 | def test_parsemount(self): 290 | """ 291 | The actual test. 292 | Any method which starts with ``test_`` will considered as a test case. 293 | """ 294 | result = parse_mounts() 295 | self.assertIsInstance(result, list) 296 | self.assertIsInstance(result[0], tuple) 297 | 298 | def test_rootext4(self): 299 | """ 300 | Test to find root filesystem 301 | """ 302 | result = parse_mounts() 303 | for line in result: 304 | if line[1] == '/' and line[2] != 'rootfs': 305 | self.assertEqual(line[2], 'ext4') 306 | 307 | 308 | if __name__ == '__main__': 309 | unittest.main() 310 | 311 | :: 312 | 313 | $ python mounttest.py 314 | .. 315 | ---------------------------------------------------------------------- 316 | Ran 2 tests in 0.001s 317 | 318 | OK 319 | 320 | 321 | Test coverage 322 | ============= 323 | 324 | Test coverage is a simple way to find untested parts of a codebase. It does not 325 | tell you how good your tests are. 326 | 327 | In Python we already have a nice coverage tool to help us. You can install it in Fedora 328 | 329 | :: 330 | 331 | # dnf install python3-coverage 332 | 333 | Or using `pip`. 334 | :: 335 | 336 | $ python3 -m pip install coverage 337 | 338 | Coverage Example 339 | ================ 340 | :: 341 | 342 | $ coverage -x mounttest.py 343 | 344 | 345 | $ coverage -rm 346 | Name Stmts Miss Cover Missing 347 | ----------------------------------------- 348 | mounttab2 21 7 67% 16, 24-29, 33 349 | mounttest 14 0 100% 350 | ----------------------------------------- 351 | TOTAL 35 7 80% 352 | 353 | -------------------------------------------------------------------------------- /docs/thebeginning.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | ============= 4 | The Beginning 5 | ============= 6 | 7 | Let's look at our first code, hello world. Because Python is an interpreted 8 | language, you can write the code into the Python interpreter directly or you 9 | can write the code in a file and then run the file. In this topic, we will 10 | first write the code using the interpreter, after starting Python in the 11 | command prompt (shell or terminal). If you are new to Linux command line, 12 | you can read about Linux commands in `this 13 | book `. 14 | 15 | 16 | The following is from Fedora 34 machine running Python 3.10 17 | 18 | :: 19 | 20 | Python 3.10.1 (main, Dec 9 2021, 00:00:00) [GCC 11.2.1 20211203 (Red Hat 11.2.1-7)] on linux 21 | Type "help", "copyright", "credits" or "license" for more information. 22 | >>> 23 | 24 | 25 | Using the Python interpreter 26 | ============================== 27 | 28 | In our first code we are going to print "Hello World!" using the interpreter. To generate the output, type the following: 29 | 30 | :: 31 | 32 | >>> print("Hello World!") 33 | Hello World! 34 | 35 | Using a source file 36 | ===================== 37 | 38 | As a serious programmer, you might want to write the above code into a source 39 | file. Use any text editor you like to create the file called helloworld.py. I 40 | used vi. You can even use GUI based tools like `Kate 41 | `_ or `gedit 42 | `_. In the later part of the book, I will help you to use a few different editors. 43 | 44 | Open a shell or terminal and perform these steps. 45 | 46 | 1. Enter the following text: 47 | 48 | .. image:: img/helloworld.png 49 | 50 | 51 | 2. Type the following command to make the file executable: 52 | 53 | :: 54 | 55 | $ chmod +x helloworld.py 56 | 57 | 3. Run the code by typing the filename. 58 | 59 | :: 60 | 61 | $ ./helloworld.py 62 | Hello World! 63 | 64 | On the first line you can *#!*, what we call it sha-bang. The sha-bang indicates 65 | that the Python interpreter should run this code. On the next line we are 66 | printing a text message. In Python we call all the lines of text "strings." 67 | 68 | Whitespaces and indentation 69 | =========================== 70 | 71 | In Python whitespace is an important thing. We divide different identifiers using spaces. Whitespace in the beginning of the line is known as indentation, but if you give wrong indentation it will throw an error. Below are some examples: 72 | 73 | :: 74 | 75 | >>> a = 12 76 | File "", line 1 77 | a = 12 78 | IndentationError: unexpected indent 79 | 80 | .. warning:: 81 | There is an extra space in the beginning of the second line which is causing the error, so always look for the proper indentation. 82 | You can even get into this indentation errors if you mix up tabs and spaces. Like if you use spaces and only use spaces for indentation, don't use tabs in that case. For you it may look same, but the code will give you error if you try to run it. 83 | 84 | This also introduce us to the first error. It is okay to see more errors while 85 | you are learning to code or learning Python for the first time. Start reading 86 | the errors from the end, and slowly go up (if there are many lines). We will 87 | learn more in the exceptions chapter of this book. 88 | 89 | 90 | We can have few basic rules ready for spaces and indentation. 91 | 92 | - Use 4 spaces for indentation. 93 | 94 | - Never mix tab and spaces. 95 | 96 | - One blank line between functions. 97 | 98 | - Two blank lines between classes. 99 | 100 | There are more places where you should be following the same type of whitespace rules: 101 | 102 | - Add a space after "," in dicts, lists, tuples, and argument lists and after ":" in dicts. 103 | 104 | - Spaces around assignments and comparisons (except in argument list) 105 | 106 | - No spaces just inside parentheses. 107 | 108 | 109 | .. note:: 99% of programming errors I saw are due to typing mistakes. People can learn logic well, but you should be able to type well too. Learn touch typing, that one single skill will help you to become much better programmer than many other skills. 110 | 111 | Comments 112 | ======== 113 | 114 | Comments are snippets of English text that explain what this code does. Write comments in the code so that is easier for others to understand. A comment line starts with *#*. Everything after that is ignored as a comment and does not affect the program. 115 | 116 | :: 117 | 118 | >>> # This is a comment 119 | >>> # The next line will add two numbers 120 | >>> a = 12 + 34 121 | >>> print(c) #this is a comment too :) 122 | 123 | Comments are mainly for people who *develop* or *maintain* the codebase. So if you have any complex code, you should write enough comments inside so that anyone else can understand the code by reading the comments. Always give a space after # and then start writing the comment. You can also use some standard comments like: 124 | 125 | :: 126 | 127 | # FIXME -- fix these code later 128 | # TODO -- in future you have to do this 129 | 130 | Modules 131 | ======= 132 | 133 | Modules are Python files that contain different function definitions or variables that can be reused. Module files should always end with a .py extension. Python itself has a vast module library with the default installation. We will use some of them later. To use a module you have to import it first. 134 | 135 | :: 136 | 137 | >>> import math 138 | >>> print(math.e) 139 | 2.71828182846 140 | 141 | We will learn more about modules in the Modules chapter. 142 | 143 | 144 | Evaluation your code from a Python file in the interpreter 145 | ========================================================== 146 | 147 | Many times we want to see how the code is working, and values of different 148 | variables inside of the code. We can do this interactively by copy-pasting the 149 | related code in the interpreter, but there is a better solution. We can use 150 | *-i* flag to the *python* interpreter and then interprets the given code, and 151 | provide the interpreter shell. 152 | 153 | We will have the following code in a file name *theidemo.py*. 154 | 155 | :: 156 | 157 | a = 10 158 | name = "kushal" 159 | c = 44 160 | a = 20 161 | 162 | 163 | Now let us see how the *-i* flag can be used. 164 | 165 | .. image:: img/theidemo.gif 166 | 167 | 168 | -------------------------------------------------------------------------------- /docs/typehinting.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | Type hinting and annotations 3 | ============================== 4 | 5 | This is one of the new feature of the language. We can do the similar kind of 6 | work in Python2 also, but with different syntax. Please remember that Python 7 | will stay as a dynamically typed language, this type hinting does not effect 8 | your code anyway. 9 | 10 | The major benefit of having type hints in your codebase is about future 11 | maintenance of the codebase. When a new developer will try to contribute to 12 | your project, having type hints will save a lot of time for that new person. 13 | It can also help to detect some of the runtime issues we see due to passing 14 | of wrong variable types in different function calls. 15 | 16 | First example of type annotation 17 | ================================== 18 | 19 | Let us start with a simple example, adding of two integers. 20 | 21 | :: 22 | 23 | def add(a, b): 24 | return a + b 25 | 26 | Now, the above example will work for any object which supports *+* operator. 27 | But, we want to specify that it is expecting only Integers as parameters, and 28 | the function call will return another Integer. 29 | 30 | :: 31 | 32 | def add(a: int, b: int) -> int: 33 | return a + b 34 | 35 | You can see that the return type of the function call is defined after *->*. 36 | We can do the same in Python2 using a comment (before any docstring). 37 | :: 38 | 39 | def add(a, b): 40 | # type: (int, int) -> int 41 | return a + b 42 | 43 | 44 | Using mypy and more examples 45 | ============================= 46 | 47 | `Mypy `_ is a static type checker written for Python. If we use the type 48 | annotations as explained above, mypy can help by finding common problems in 49 | our code. You can use mypy in various ways in your development workflow, may 50 | be in CI as a proper test. 51 | 52 | Installing mypy 53 | --------------- 54 | 55 | We can install mypy inside of a virtual environment. 56 | 57 | :: 58 | 59 | $ pipenv install mypy 60 | Installing mypy… 61 | Looking in indexes: https://pypi.python.org/simple 62 | Collecting mypy 63 | Downloading https://files.pythonhosted.org/packages/e2/3f/e20e2544b35e862fbed4e26a89e3d857007c5bd32abc019ef21c02aecd98/mypy-0.600-py3-none-any.whl (1.3MB) 64 | Collecting typed-ast<1.2.0,>=1.1.0 (from mypy) 65 | Downloading https://files.pythonhosted.org/packages/5b/4e/79e873aa89b8038ca6474c00afe96f9468973b604e7f737cb82697a680c0/typed_ast-1.1.0-cp35-cp35m-manylinux1_x86_64.whl (724kB) 66 | Installing collected packages: typed-ast, mypy 67 | Successfully installed mypy-0.600 typed-ast-1.1.0 68 | 69 | Adding mypy to Pipfile's [packages]… 70 | Pipfile.lock (627f99) out of date, updating to (67e074)… 71 | Locking [dev-packages] dependencies… 72 | Locking [packages] dependencies… 73 | Updated Pipfile.lock (67e074)! 74 | Installing dependencies from Pipfile.lock (67e074)… 75 | 🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 7/7 — 00:00:01 76 | To activate this project's virtualenv, run the following: 77 | $ pipenv shell 78 | 79 | 80 | Our example code 81 | ----------------- 82 | 83 | We will be working on the following example code. This isn't much useful, 84 | but we can use this to learn about type annotations and mypy. 85 | 86 | :: 87 | 88 | class Student: 89 | 90 | def __init__(self, name, batch, branch, roll): 91 | self.name = name 92 | self.batch = batch 93 | self.branch = branch 94 | self.roll = roll 95 | self.semester = None 96 | self.papers = {} 97 | 98 | def is_passed(self): 99 | "To find if the student has pass the exam in the current semester" 100 | for k, v in self.papers.items(): 101 | if v < 34: 102 | return False 103 | 104 | return True 105 | 106 | 107 | def total_score(self): 108 | "Returns the total score of the student" 109 | total = 0 110 | for k, v in self.papers.items(): 111 | total += v 112 | 113 | return total 114 | 115 | 116 | std1 = Student("Kushal", 2005, "cse", "123") 117 | std2 = Student("Sayan", 2005, "cse", 121) 118 | std3 = Student("Anwesha", 2005, "law", 122) 119 | 120 | std1.papers = {"english": 78, "math": 82, "science": 77} 121 | std2.papers = {"english": 80, "math": 92, "science": "78"} 122 | std3.papers = {"english": 82, "math": 87, "science": 77} 123 | 124 | for std in [std1, std2, std3]: 125 | print("Passed: {0}. The toral score of {1} is {2}".format(std.is_passed(), std.name, std.total_score())) 126 | 127 | 128 | You may find some errors in the code, but in case of a large codebase we can 129 | not detect the similar issues unless we see the runtime errors. 130 | 131 | Using mypy 132 | ----------- 133 | 134 | We can just call mypy on our source file, I named it as *students2.py* 135 | 136 | :: 137 | 138 | $ mypy studets2.py 139 | 140 | Enabling the first few type annotations 141 | ---------------------------------------- 142 | 143 | We will add some type annotations to the *__init__* method. For reducing the 144 | code length, I am only showing the changed code below. 145 | 146 | :: 147 | 148 | class Student: 149 | 150 | def __init__(self, name: str, batch: int, branch: str, roll: int) -> None: 151 | self.name = name 152 | self.batch = batch 153 | self.branch = branch 154 | self.roll = roll 155 | self.semester = None 156 | self.papers = {} 157 | 158 | 159 | :: 160 | 161 | $ mypy students2.py 162 | students2.py:11: error: Need type annotation for variable 163 | students2.py:31: error: Argument 4 to "Student" has incompatible type "str"; expected "int" 164 | 165 | You can see mypy is complaining about variable which does not have type 166 | annotations, and also found that in line 31, as argument 4 we are passing 167 | *str*, where as we were supposed to send in an Integer for the rull number. 168 | Let us fix these. 169 | 170 | :: 171 | 172 | from typing import Dict 173 | 174 | class Student: 175 | 176 | def __init__(self, name: str, batch: int, branch: str, roll: int) -> None: 177 | self.name = name 178 | self.batch = batch 179 | self.branch = branch 180 | self.roll = roll 181 | self.semester: str = None 182 | self.papers: Dict[str, int] = {} 183 | 184 | def is_passed(self) -> bool: 185 | "To find if the student has pass the exam in the current semester" 186 | for k, v in self.papers.items(): 187 | if v < 34: 188 | return False 189 | 190 | return True 191 | 192 | 193 | def total_score(self) -> int: 194 | "Returns the total score of the student" 195 | total = 0 196 | for k, v in self.papers.items(): 197 | total += v 198 | 199 | return total 200 | 201 | 202 | std1: Student = Student("Kushal", 2005, "cse", 123) 203 | std2: Student = Student("Sayan", 2005, "cse", 121) 204 | std3: Student = Student("Anwesha", 2005, "law", 122) 205 | 206 | std1.papers = {"english": 78, "math": 82, "science": 77} 207 | std2: Student.papers = {"english": 80, "math": 92, "science": 78} 208 | std3.papers = {"english": 82, "math": 87, "science": 77} 209 | 210 | for std in [std1, std2, std3]: 211 | print("Passed: {0}. The toral score of {1} is {2}".format(std.is_passed(), std.name, std.total_score())) 212 | 213 | :: 214 | 215 | $ mypy students2.py 216 | 217 | Now, it does not complain about any error. You can see that in line 1, we 218 | imported Dict from the typing module. And, then using the same we added the 219 | type annotation of the *self.paper* variable. We are saying that it is a 220 | dictionary which has string keys, and Integers as values. We also used our 221 | *Student* class as type of std1, std2, and std3 variables. 222 | 223 | Now let us say we by mistake assign a new list to the papers variable. 224 | 225 | :: 226 | 227 | std1.papers = ["English", "Math"] 228 | 229 | 230 | Or maybe assigned a wrong kind of dictionary. 231 | 232 | :: 233 | 234 | std2.papers = {1: "Engish", 2: "Math"} 235 | 236 | We can see what mypy says in these cases 237 | 238 | :: 239 | 240 | $ mypy students2.py 241 | students2.py:35: error: Incompatible types in assignment (expression has type List[str], variable has type Dict[str, int]) 242 | students2.py:36: error: Dict entry 0 has incompatible type "int": "str" 243 | students2.py:36: error: Dict entry 1 has incompatible type "int": "str" 244 | 245 | 246 | More examples of type annotations 247 | ================================== 248 | 249 | :: 250 | 251 | from typing import List, Tuple, Sequence, Optional 252 | 253 | values: List[int] = [] 254 | city: int = 350 # The city code, not a name 255 | 256 | 257 | # This function returns a Tuple of two values, a str and an int 258 | def get_details() -> Tuple[str, int]: 259 | return "Python", 5 260 | 261 | # The following is an example of Tuple unpacking 262 | name: str 263 | marks: int 264 | name, marks = get_details() 265 | 266 | 267 | def print_all(values: Sequence) -> None: 268 | for v in values: 269 | print(v) 270 | 271 | 272 | print_all([1,2,3]) 273 | print_all({"name": "kushal", "class": 5}) 274 | # alltypes.py:23: error: Argument 1 to "print_all" has incompatible type Dict[str, object]; expected Sequence[Any] 275 | # But running the code will give us no error with wrong output 276 | 277 | def add_ten(number: Optional[int] = None) -> int: 278 | if number: 279 | return number + 10 280 | else: 281 | return 42 282 | 283 | print(add_ten()) 284 | print(add_ten(12)) 285 | 286 | You can learn more about types from `PEP 484 287 | `_. The `typing module 288 | `_ has detailed explanation and 289 | more examples about how to add type annotations in your codebase. 290 | 291 | You can also view `the talk `_ 292 | from Carl Meyer to learn about type checking in Python. 293 | -------------------------------------------------------------------------------- /docs/variablesanddatatypes.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | ======================= 4 | Variables and Datatypes 5 | ======================= 6 | 7 | Every programming language has its own grammar rules just like the languages we speak. 8 | 9 | Keywords and Identifiers 10 | ======================== 11 | 12 | The following identifiers are used as reserved words, or keywords of the language, and cannot be used as ordinary identifiers. They must be typed exactly as written here: 13 | 14 | :: 15 | 16 | False class finally is return 17 | None continue for lambda try 18 | True def from nonlocal while 19 | and del global not with 20 | as elif if or yield 21 | assert else import pass 22 | break except in raise 23 | 24 | In Python we don't specify what kind of data we are going to put in a variable. So you can directly write abc = 1 and abc will become an integer datatype. If you write abc = 1.0 abc will become of floating type. Here is a small program to add two given numbers 25 | 26 | :: 27 | 28 | >>> a = 13 29 | >>> b = 23 30 | >>> a + b 31 | 36 32 | 33 | From the above example you can understand that to declare a variable in Python , what you need is just to type the name and the value. Python can also manipulate strings They can be enclosed in single quotes or double quotes like 34 | 35 | :: 36 | 37 | >>> 'India' 38 | 'India' 39 | >>> 'India\'s best' 40 | "India's best" 41 | >>> "Hello World!" 42 | 'Hello World!' 43 | 44 | Reading input from the Keyboard 45 | =============================== 46 | 47 | Generally the real life Python codes do not need to read input from the 48 | keyboard. In Python we use input function to do input. *input("String to show")* 49 | , this will return a string as output. Let us write a program to read a number 50 | from the keyboard and check if it is less than 100 or not. Name of the program 51 | is *testhundred.py* 52 | 53 | 54 | .. image:: img/testhundred.png 55 | 56 | The output 57 | 58 | :: 59 | 60 | $ ./testhundred.py 61 | Enter an integer: 13 62 | Your number is smaller than 100 63 | $ ./testhundred.py 64 | Enter an integer: 123 65 | Your number is greater than 100 66 | 67 | In the next program we are going to calculate investments. 68 | 69 | .. image:: img/investment.png 70 | 71 | The output 72 | 73 | :: 74 | 75 | $ ./investment.py 76 | Enter amount: 10000 77 | Enter Interest rate: 0.14 78 | Enter period: 5 79 | Year 1 Rs. 11400.00 80 | Year 2 Rs. 12996.00 81 | Year 3 Rs. 14815.44 82 | Year 4 Rs. 16889.60 83 | Year 5 Rs. 19254.15 84 | 85 | Some Examples 86 | ============= 87 | 88 | Some examples of variables and datatypes: 89 | 90 | Average of N numbers 91 | -------------------- 92 | 93 | In the next program we will do an average of N numbers. 94 | 95 | .. image:: img/averagen.png 96 | 97 | The output 98 | 99 | :: 100 | 101 | $ ./averagen.py 102 | 1 103 | 2.3 104 | 4.67 105 | 1.42 106 | 7 107 | 3.67 108 | 4.08 109 | 2.2 110 | 4.25 111 | 8.21 112 | N = 10 , Sum = 38.800000 113 | Average = 3.880000 114 | 115 | Temperature conversion 116 | ---------------------- 117 | 118 | In this program we will convert the given temperature to Celsius from Fahrenheit by using the formula C=(F-32)/1.8 119 | 120 | .. image:: img/temperature.png 121 | 122 | The output 123 | 124 | :: 125 | 126 | $ ./temperature.py 127 | Fahrenheit Celsius 128 | 0.0 -17.78 129 | 25.0 -3.89 130 | 50.0 10.00 131 | 75.0 23.89 132 | 100.0 37.78 133 | 125.0 51.67 134 | 150.0 65.56 135 | 175.0 79.44 136 | 200.0 93.33 137 | 225.0 107.22 138 | 250.0 121.11 139 | 140 | Multiple assignments in a single line 141 | ===================================== 142 | 143 | You can even assign values to multiple variables in a single line, like 144 | 145 | :: 146 | 147 | >>> a , b = 45, 54 148 | >>> a 149 | 45 150 | >>> b 151 | 54 152 | 153 | Using this swapping two numbers becomes very easy 154 | 155 | :: 156 | 157 | >>> a, b = b , a 158 | >>> a 159 | 54 160 | >>> b 161 | 45 162 | 163 | To understand how this works, you will have to learn about a data type called 164 | *tuple*. We use *comma* to create tuple. In the right hand side we create the 165 | tuple (we call this as tuple packing) and in the left hand side we do tuple 166 | unpacking into a new tuple. 167 | 168 | Below we have another example of tuple unpacking. 169 | 170 | :: 171 | 172 | >>> data = ("Kushal Das", "India", "Python") 173 | >>> name, country, language = data 174 | >>> name 175 | 'Kushal Das' 176 | >>> country 177 | 'India' 178 | >>> language 179 | 'Python' 180 | 181 | Tuples can not be modified. You will have to create another new tuple if you 182 | want have any changes. Many times, we create variables written in CAPS to mark 183 | values which will not be changed when the program is running (constants). For 184 | example, if we think about colours as tuples of RGB values, then we can define 185 | them as: 186 | 187 | :: 188 | 189 | >>> RED = (255, 0, 0) 190 | >>> GREEN = (0, 255, 0) 191 | >>> BLUE = (0, 0, 255) 192 | >>> print(RED) 193 | (255, 0, 0) 194 | 195 | 196 | 197 | Formatting strings 198 | =================== 199 | 200 | In Python 3, there are a few different ways to format a string. We use these 201 | methods to format a text dynamically. I will go though a few examples below. 202 | 203 | 204 | In Python 3.6, we have a new way to do string formatting. `PEP 498 205 | `_ introduces the concept called 206 | **f-strings**. 207 | 208 | Here is the same example using *f-strings*:: 209 | 210 | >>> name = "Kushal" 211 | >>> language = "Python" 212 | >>> msg = f"{name} loves {language}." 213 | >>> print(msg) 214 | Kushal loves Python. 215 | 216 | F-strings provide a simple and readable way to embed Python expressions in a 217 | string. Here are a few more examples. 218 | 219 | :: 220 | 221 | >>> answer = 42 222 | >>> print(f"The answer is {answer}") 223 | The answer is 42 224 | >>> import datetime 225 | >>> d = datetime.date(2004, 9, 8) 226 | >>> f"{d} was a {d:%A}, we started the mailing list back then." 227 | '2004-09-08 was a Wednesday, we started the mailing list back then.' 228 | 229 | If you want to know more about how this feature came into Python, watch this 230 | `talk `_ from `Mariatta Wijaya 231 | `_. 232 | 233 | 234 | From Python3.8 we can use the following style to help printing values along 235 | with the variable name. This is very useful while debugging the code. 236 | 237 | :: 238 | 239 | >>> a = 1 240 | >>> b = 2 241 | >>> print(f"{a=} and {b=}") 242 | a=1 and b=2 243 | 244 | 245 | 246 | .format method 247 | --------------- 248 | 249 | We can also use `format` method in a string inside. 250 | 251 | :: 252 | 253 | >>> name = "Kushal" 254 | >>> language = "Python" 255 | >>> msg = "{0} loves {1}.".format(name, language) 256 | >>> print(msg) 257 | Kushal loves Python. 258 | 259 | 260 | Left of right aligned 261 | ---------------------- 262 | 263 | We can use `:<` or `:>` in `.format` call to print left or right aligned. In 264 | the following example we are printing first left aligned (10 characters) and 265 | right aligned. 266 | 267 | :: 268 | 269 | >>> print("{:<10}".format("Sweden")) 270 | Sweden 271 | >>> print("{:>10}".format("Sweden")) 272 | Sweden 273 | 274 | -------------------------------------------------------------------------------- /docs/virtualenv.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | ========== 4 | Virtualenv 5 | ========== 6 | 7 | Virtual Python Environment or venv is a Python environment which will help you 8 | to install different versions of Python modules in a local directory using which 9 | you can develop and test your code without requiring to install everything 10 | systemwide. 11 | 12 | Installation 13 | ============ 14 | 15 | In Python3 we can use the **venv** module to create virtual environments. 16 | 17 | Usage 18 | ===== 19 | 20 | We will create a directory call *virtual* inside which we will have two 21 | different virtual environment. 22 | 23 | The following commands will create an env called virt1. 24 | 25 | :: 26 | 27 | $ cd virtual 28 | $ python3 -m venv virt1 29 | $ 30 | 31 | Now we can activate the virt1 environment. 32 | 33 | :: 34 | 35 | $ source virt1/bin/activate 36 | (virt1)[user@host]$ 37 | 38 | The first part of the prompt is now the name of the virtual environment, it 39 | will help you identify which environment you are in when you have multiple 40 | environments. 41 | 42 | To deactivate the environment use *deactivate* command. 43 | 44 | :: 45 | 46 | (virt1)$ deactivate 47 | $ 48 | 49 | So, now we will install a Python module called redis. 50 | 51 | :: 52 | 53 | (virt1)$ python3 -m pip install redis 54 | Collecting redis 55 | Downloading redis-2.10.5-py2.py3-none-any.whl (60kB) 56 | 100% |████████████████████████████████| 61kB 607kB/s 57 | Installing collected packages: redis 58 | Successfully installed redis-2.10.5 59 | 60 | .. rst-class:: floater 61 | 62 | .. seealso:: 63 | 64 | Read `this blog post `_ from Brett Cannon to understand why you should use 65 | `python3 -m pip` to install packages. 66 | 67 | 68 | Now we will create another virtual environment *virt2* where we will 69 | install the same redis module but an old 2.4 version of it. 70 | 71 | :: 72 | 73 | $ python3 -m venv virt2 74 | $ source virt2/bin/activate 75 | (virt2)$ 76 | (virt2)$ python3 -m pip install redis==2.4 77 | Downloading/unpacking redis 78 | Downloading redis-2.4.0.tar.gz 79 | Running setup.py egg_info for package redis 80 | Installing collected packages: redis 81 | Running setup.py install for redis 82 | Successfully installed redis 83 | Cleaning up... 84 | 85 | This way you can have many different environments for all of your development 86 | needs. 87 | 88 | 89 | .. note:: Always remember to create virtualenvs while developing new applications. This will help you keep the system modules clean. 90 | 91 | 92 | Pipenv 93 | ======= 94 | 95 | `Pipenv `_ is a tool created by `Kenneth Reitz 96 | `_ which helps to create, manage the 97 | virtualenvs for your projects. It also helps to install/uninstall/update the 98 | dependencies of your project. 99 | 100 | 101 | Installing pipenv 102 | ------------------ 103 | 104 | We can install pipenv by the following command. 105 | 106 | :: 107 | 108 | $ python3 -m pip install --user pipenv 109 | 110 | 111 | Using pipenv 112 | ------------- 113 | 114 | You can go to your project directory, and then use the command **pipenv 115 | install** to create a new virtualenv for you. You can also pass any module 116 | name which *pipenv* will install on the environment. 117 | 118 | :: 119 | 120 | $ mkdir myproject 121 | $ cd myproject 122 | $ pipenv install requests 123 | Creating a virtualenv for this project… 124 | Using /usr/bin/python3 (3.6.5) to create virtualenv… 125 | ⠋Already using interpreter /usr/bin/python3 126 | Using base prefix '/usr' 127 | New python executable in /home/fedora/.local/share/virtualenvs/myproject-dbBcpQ4l/bin/python3 128 | Also creating executable in /home/fedora/.local/share/virtualenvs/myproject-dbBcpQ4l/bin/python 129 | Installing setuptools, pip, wheel...done. 130 | 131 | Virtualenv location: /home/fedora/.local/share/virtualenvs/myproject-dbBcpQ4l 132 | Creating a Pipfile for this project… 133 | Installing requests… 134 | Collecting requests 135 | Downloading https://files.pythonhosted.org/packages/49/df/50aa1999ab9bde74656c2919d9c0c085fd2b3775fd3eca826012bef76d8c/requests-2.18.4-py2.py3-none-any.whl (88kB) 136 | Collecting chardet<3.1.0,>=3.0.2 (from requests) 137 | Downloading https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl (133kB) 138 | Collecting idna<2.7,>=2.5 (from requests) 139 | Downloading https://files.pythonhosted.org/packages/27/cc/6dd9a3869f15c2edfab863b992838277279ce92663d334df9ecf5106f5c6/idna-2.6-py2.py3-none-any.whl (56kB) 140 | Collecting certifi>=2017.4.17 (from requests) 141 | Using cached https://files.pythonhosted.org/packages/7c/e6/92ad559b7192d846975fc916b65f667c7b8c3a32bea7372340bfe9a15fa5/certifi-2018.4.16-py2.py3-none-any.whl 142 | Collecting urllib3<1.23,>=1.21.1 (from requests) 143 | Downloading https://files.pythonhosted.org/packages/63/cb/6965947c13a94236f6d4b8223e21beb4d576dc72e8130bd7880f600839b8/urllib3-1.22-py2.py3-none-any.whl (132kB) 144 | Installing collected packages: chardet, idna, certifi, urllib3, requests 145 | Successfully installed certifi-2018.4.16 chardet-3.0.4 idna-2.6 requests-2.18.4 urllib3-1.22 146 | 147 | Adding requests to Pipfile's [packages]… 148 | Pipfile.lock not found, creating… 149 | Locking [dev-packages] dependencies… 150 | Locking [packages] dependencies… 151 | Updated Pipfile.lock (b14837)! 152 | Installing dependencies from Pipfile.lock (b14837)… 153 | 🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 5/5 — 00:00:02 154 | To activate this project's virtualenv, run the following: 155 | $ pipenv shell 156 | 157 | The above command will create a new virtualenv and then also install 158 | *requests* module in the environment. You can then use **pipenv shell** 159 | command to activate that environment. For our example, we will use 160 | the following Python code in a file named *main.py*. 161 | 162 | :: 163 | 164 | import requests 165 | response = requests.get('https://httpbin.org/ip') 166 | print('Your IP is {0}'.format(response.json()['origin'])) 167 | 168 | 169 | :: 170 | 171 | $ pipenv shell 172 | $ $ python main.py 173 | Your IP is 192.168.1.2 174 | 175 | Exiting from the virtualenv 176 | ---------------------------- 177 | 178 | You can exit from the virtualenv using **exit** command, or by pressing *Ctrl+d*. 179 | 180 | 181 | Pipfile and Pipfile.lock 182 | ========================= 183 | 184 | If you notice your project directory after you have used **pipenv**, you will 185 | find two new files inside, *Pipfile* and *Pipfile.lock*. These files have been 186 | created by the **pipenv** command. You should checkin these two files into 187 | your version control system (say: git), so that others can create the exact 188 | same environment of yours. 189 | 190 | Pipfile 191 | -------- 192 | 193 | The following is the content of our *Pipfile*. It is using the `TOML 194 | `_ file format. 195 | 196 | :: 197 | 198 | [[source]] 199 | verify_ssl = true 200 | name = "pypi" 201 | url = "https://pypi.python.org/simple" 202 | 203 | [dev-packages] 204 | 205 | [requires] 206 | python_version = "3.6.5" 207 | 208 | [packages] 209 | requests = "*" 210 | 211 | On the top it tells which source to use to get the packages. It also mentions 212 | the Python version required. The packages section tells us what all Python 213 | packages we need. The string `"*"` means install the latest version available 214 | on the package index. The exact version details of the packages are stored in 215 | the *Pipfile.lock* file, it is in machine readable `JSON 216 | `_ format. 217 | 218 | Remember to install any dependency for your project using **pipenv** comamnd, 219 | that will automatically update your *Pipfile* and *Pipfile.lock* file. If you 220 | have any dependency which is only required for the development, you can 221 | install them marked as *dev-packages*. In the following example I am installing 222 | *flake8* as development dependency. 223 | 224 | :: 225 | 226 | $ pipenv install --dev flake8 227 | $ cat Pipfile 228 | [[source]] 229 | verify_ssl = true 230 | name = "pypi" 231 | url = "https://pypi.python.org/simple" 232 | 233 | [dev-packages] 234 | "flake8" = "*" 235 | 236 | [requires] 237 | python_version = "3.6.5" 238 | 239 | [packages] 240 | requests = "*" 241 | 242 | You can watch `this talk `_ by 243 | Kenneth from PyCon 2018 to know more about *Pipenv*. 244 | 245 | Through out the rest of the book, we will use **pipenv** to create and manage 246 | virtualenvs for any code. 247 | -------------------------------------------------------------------------------- /publican.cfg: -------------------------------------------------------------------------------- 1 | # Config::Simple 4.59 2 | # Fri Nov 4 13:43:18 2011 3 | 4 | debug: 1 5 | xml_lang: "en-US" 6 | brand: common 7 | 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | cloud_sptheme 3 | -------------------------------------------------------------------------------- /scripts/build_resources.sh: -------------------------------------------------------------------------------- 1 | for filename in `ls pot/*.pot` 2 | do 3 | short=`echo $filename | sed -e s/^pot.// | sed -e s/.pot$//` 4 | long=`echo $filename | sed -e s/^pot.//` 5 | echo [pym.$short] 6 | echo file_filter = \/$short.po 7 | echo source_file = pot/$long 8 | echo source_lang = en 9 | 10 | done 11 | --------------------------------------------------------------------------------