diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..5c98b42 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..570835c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/python-playground.iml b/.idea/python-playground.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/python-playground.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index b6bbd52..cb102d0 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,27 @@ # Playground repo for Python projects -This repo has multiple branches and each branch represent different projects/proof of concepts for playing with Python technologies/frameworks. - -_P.S. `master` branch is empty and has only this `README.md` file_ +This is a learning repo with different projects/proof of concepts for playing with Python technologies/frameworks. ## Table of Contents - [Status Updates](#status-updates) + - [Day 1](#day-1) + - [Day 2](#day-2) + - [Day 3](#day-3) + - [Day 4](#day-4) + - [Day 5](#day-5) + - [Day 6](#day-6) + - [Day 7](#day-7) + - [Day 8](#day-8) + - [Day 10](#day-10) + - [Day 12](#day-12) + - [Day 13](#day-13) - [Installation](#installation) - [Resources](#resources) ## Status Updates -- [learn/pipenv-pipfile - Pipenv and Pipfile](https://github.com/TechPrimers/python-playground/tree/learn/pipenv-pipfile) - - Day 1 - March 25th, 2020 - ## Day 1 +As part of 21 days of lockdown, I started learning python from March 25th, 2020. + +### Day 1 +- `cd pipenv` - `pipenv install` - Similar to `npm install`. Creates 2 files `Pipfile` and `Pipfile.lock` similar to `package-lock.json` in the javascript world with dependencies based on `requirements.txt` - `pipenv shell` - Activates the virtual environment. Much simpler than `virtualenv` - Once the shell is activated, run `python3 hello.py` to bring the Flask app UP!! @@ -34,19 +44,41 @@ _P.S. `master` branch is empty and has only this `README.md` file_ - If a package has `__init__.py`, it becomes a module - `learn` is a module which is used in `modules.py` +### Day 2 + - cd `functions` + - Started using callable functions inside a class + +### Day 3 + - Started using Functions and String manipulation + +### Day 4 + - `cd tuples` + - Started using `tuples` + +### Day 5 + - `cd dictionaries` + - Started using `dictionaries` + - Started using `set` + +### Day 6 + - Started with class usage and best practices + +### Day 7 + - class methods + - static methods + +### Day 8 + - class equals and repr + - Data Class usage + +### Day 10 + - Files and Directories + +### Day 12 + - Lambda -- [learn/functions - Functions](https://github.com/TechPrimers/python-playground/tree/learn/functions) - - Day 2 - - Started using callable functions inside a class - - Day 3 - - Started using Functions and String manipulation -- [learn/tuples - Tuples](https://github.com/TechPrimers/python-playground/tree/learn/tuples) - - Day 4 - - Started using `tuples` -- [learn/dictionaries - Dictionaries](https://github.com/TechPrimers/python-playground/tree/learn/dictionaries) - - Day 5 - - Started using `dictionaries` - - Started using `set` +### Day 13 + - Solving LeetCode program - [Problem](https://leetcode.com/problems/two-sum/) ## Installation Command used in Mac for installing supporting tools @@ -55,3 +87,4 @@ Command used in Mac for installing supporting tools ## Resources - [Introducing Python - Oreilly](https://learning.oreilly.com/library/view/introducing-python-2nd) - Most exhaustive and amazing book..! +- [Projects to build after learning pythong](https://medium.com/javarevisited/8-projects-you-can-buil-to-learn-python-in-2020-251dd5350d56) diff --git a/classes/ClassMethod.py b/classes/ClassMethod.py new file mode 100644 index 0000000..f9e30d5 --- /dev/null +++ b/classes/ClassMethod.py @@ -0,0 +1,15 @@ +class ClassMethod: + count = 0 + def __init__(self): + ClassMethod.count += 1 + + @classmethod + def print(cls): + print(f"Number of objects: {cls.count}") + + @staticmethod + def printLog(): + print("Static Method: ", ClassMethod.count) + + def normal(self): + print("normal") \ No newline at end of file diff --git a/classes/DataClass.py b/classes/DataClass.py new file mode 100644 index 0000000..2ff49af --- /dev/null +++ b/classes/DataClass.py @@ -0,0 +1,6 @@ +from dataclasses import dataclass + +@dataclass +class DataClass: + name: str + age: int = 0 \ No newline at end of file diff --git a/classes/User.py b/classes/User.py new file mode 100644 index 0000000..ffccd98 --- /dev/null +++ b/classes/User.py @@ -0,0 +1,13 @@ +class User: + + def __init__(self, input_name): + self.private_name = input_name + + def get_name(self): + return self.private_name; + + def set_name(self, input_name): + self.private_name = input_name + + name = property(get_name, set_name) + diff --git a/classes/UserAnnotation.py b/classes/UserAnnotation.py new file mode 100644 index 0000000..c9d83c4 --- /dev/null +++ b/classes/UserAnnotation.py @@ -0,0 +1,13 @@ +class UserAnnotation: + + def __init__(self, input_name): + self.private_name = input_name + + @property + def name(self): + return self.private_name; + + @name.setter + def name(self, input_name): + self.private_name = input_name + diff --git a/classes/Word.py b/classes/Word.py new file mode 100644 index 0000000..59ae6c2 --- /dev/null +++ b/classes/Word.py @@ -0,0 +1,10 @@ +class Word: + + def __init__(self, text): + self.text = text + + def __eq__(self, new_word): + return self.text.lower() == new_word.text.lower() + + def __repr__(self): + return f"(Word: {self.text})" \ No newline at end of file diff --git a/classes/class_main.py b/classes/class_main.py new file mode 100644 index 0000000..73efab2 --- /dev/null +++ b/classes/class_main.py @@ -0,0 +1,27 @@ +from User import User +from UserAnnotation import UserAnnotation +from ClassMethod import ClassMethod + +user = User("ajay") +user_annotation = UserAnnotation("ajay") +print(user.get_name()) +user.set_name("raj") + +print(user.private_name) +# Since property() is set via name. we can use name instead of private_name +user.name = "jaga" +print(user.name) +print("User annotation:") +print(user_annotation.private_name) +print(user_annotation.name) +user_annotation.name = "jaga" +print(user_annotation.name) + +ClassMethod.printLog() + +cm = ClassMethod() +cm_a = ClassMethod() +cm_b = ClassMethod() +cm.print() +cm.normal() +ClassMethod.printLog() \ No newline at end of file diff --git a/classes/dataclass_main.py b/classes/dataclass_main.py new file mode 100644 index 0000000..faff4be --- /dev/null +++ b/classes/dataclass_main.py @@ -0,0 +1,6 @@ +from DataClass import DataClass + +data_class = DataClass("ajay", 19) + +print("Name: ", data_class.name) +print("Age: ", data_class.age) \ No newline at end of file diff --git a/classes/word_main.py b/classes/word_main.py new file mode 100644 index 0000000..8650fac --- /dev/null +++ b/classes/word_main.py @@ -0,0 +1,9 @@ +from Word import Word + +word_a = Word("a") +word_b = Word("b") +word_c = Word("b") + +print("A equals B: ", word_a == word_b) +print("B equals C: ", word_b == word_c) +print("A: ", word_a) \ No newline at end of file diff --git a/dictionaries/dictionaries.py b/dictionaries/dictionaries.py new file mode 100644 index 0000000..ceca68c --- /dev/null +++ b/dictionaries/dictionaries.py @@ -0,0 +1,22 @@ +# Order doesn't matter like HashMap +dictionary = {"name": "ajay", "location": "chennai"} + +for item in dictionary: + print(f"key[{item}] value [{dictionary[item]}]in dictionary") + print(f"Another representation: key[{item}] value [{dictionary.get(item)}]in dictionary") + +print("Only keys: ", dictionary.keys()) + +dictionary_keys = list(dictionary.keys()) +print("Keys: ", dictionary_keys) +print("Keys (type): ", type(dictionary_keys)) + + +dictionary_values = list(dictionary.values()) +print("Values: ", dictionary_values) +print("Values (type): ", type(dictionary_values)) + + +dictionary_list_items = list(dictionary.items()) +print("Items: ", dictionary_list_items) +print("Items (type): ", type(dictionary_list_items)) \ No newline at end of file diff --git a/dictionaries/sets.py b/dictionaries/sets.py new file mode 100644 index 0000000..fc305d4 --- /dev/null +++ b/dictionaries/sets.py @@ -0,0 +1,12 @@ +# Set has similar notation to dictionaries with {} however they have only keys +# elements in a set are unique compared to lists +sets = {"z","a", "b", "c"} +print("Type: ", type(sets)) +print("Pop: ", sets.pop()) +print("Sorted Set(list): ", sorted(sets)) + +list_var = ["a", "a", "z", "d", "c", "z"] +print("Sorted List: ", sorted(list_var)) +print("Sorted in reverse: ", sorted(list_var, reverse = True)) + +print("Remove duplicates from list: ", sorted(list(set(list_var)))) diff --git a/files/files.py b/files/files.py new file mode 100644 index 0000000..a955a4f --- /dev/null +++ b/files/files.py @@ -0,0 +1,31 @@ +import os + +file_obj = open("files.txt", "wt") +print("This is a temp file", file=file_obj) +file_obj.write("Second line") +file_obj.close() + +try: + fout = open('files.txt', 'xt') + fout.write('added') +except FileExistsError: + print('files.txt already exists!') + +file_obj = open('files.txt', 'rt') +while True: + line = file_obj.readline(); + if not line: + break; + print("Line: ", line) +file_obj.close() + +file_obj = open('files.txt', 'rt') +lines = file_obj.readlines(); +print("Lines: ", lines) +file_obj.close() +for line in lines: + print("Line...", line) + +print(os.path.isfile('files.txt')) +print(os.path.isfile('files.temp')) +print(os.path.exists('files.txt')) \ No newline at end of file diff --git a/files/files.txt b/files/files.txt new file mode 100644 index 0000000..6c3bf22 --- /dev/null +++ b/files/files.txt @@ -0,0 +1,2 @@ +This is a temp file +Second line \ No newline at end of file diff --git a/functions/functions.py b/functions/functions.py new file mode 100644 index 0000000..e1c6c91 --- /dev/null +++ b/functions/functions.py @@ -0,0 +1,9 @@ +class Functions: + + def __init__(self): + self._cache = [] + + def __call__(self, name): + if name not in self._cache: + self._cache.append(name) + return self._cache \ No newline at end of file diff --git a/functions/functions_main.py b/functions/functions_main.py new file mode 100644 index 0000000..28f8973 --- /dev/null +++ b/functions/functions_main.py @@ -0,0 +1,4 @@ +from functions import Functions +func = Functions() +print(func("ajay")) +print(func("jaga")) \ No newline at end of file diff --git a/functions/listComprehension b/functions/listComprehension new file mode 100644 index 0000000..6c75ccf --- /dev/null +++ b/functions/listComprehension @@ -0,0 +1,35 @@ +input_list = [1, 2, 3, 4, 4, 5, 6, 7, 7] + +output_list = [] + +# Using loop for constructing output list +for var in input_list: + if var % 2 == 0: + output_list.append(var) + +print("Output List using for loop:", output_list) + + + +input_list = [1, 2, 3, 4, 4, 5, 6, 7, 7] + + +list_using_comp = [var for var in input_list if var % 2 == 0] + +print("Output List using list comprehensions:", + list_using_comp) + + + +output_list = [] +for var in range(1, 10): + output_list.append(var ** 2) + +print("Output List using for loop:", output_list) + + + +list_using_comp = [var**2 for var in range(1, 10)] + +print("Output List using list comprehension:", + list_using_comp) diff --git a/functions/strings.py b/functions/strings.py new file mode 100644 index 0000000..bc5627b --- /dev/null +++ b/functions/strings.py @@ -0,0 +1,38 @@ +# Strings are immutable. None of the changes affect the original variable unless assigned +import string + +extractor="Hello World" +print("Full String: ", extractor[:]) + +print("Offset from 3: ", extractor[3:]) +print("Offset from :3 ", extractor[:3]) +print("Offset from 3:8 ", extractor[3:8]) + +print("Last 3 characters: ", extractor[-3:]) +print("Last 3 characters: ", extractor[4:-3]) + +print("By space: ", extractor.split(" ")) + +strip_variable = "This has punctuations ..!!" +print("Strip Punctuations: ", strip_variable.strip(string.punctuation)) +print("Strip White spaces: ", strip_variable.strip(string.whitespace)) +print("Strip Punctuations and White spaces: ", strip_variable.strip(string.whitespace + string.punctuation)) + +print("Find the: ", strip_variable.find("the")) +print("rFind the: ", strip_variable.rfind("the")) +print("Find has: ", strip_variable.find("has")) + +# Returns substring not found error unlike -1 in find +# print("Index the: ", strip_variable.index("the")) +# print("rIndex the: ", strip_variable.rindex("the")) + + +count_variable = "This has repeated texts for counting texts" +print("Count: ", count_variable.count("text")) + +alpha_variable = "Thishasnumbersandtexts2" +print("alpha_variable isAlphanumberic: ", alpha_variable.isalnum()) +print("count_variable isAlphanumberic: ", count_variable.isalnum()) + +title = "This is a title" +print("Title: ", title.title()) diff --git a/lambda/lambda_main.py b/lambda/lambda_main.py new file mode 100644 index 0000000..cbd9216 --- /dev/null +++ b/lambda/lambda_main.py @@ -0,0 +1,2 @@ +name_lambda = lambda name: name.split()[-1] +print("Name: ", name_lambda("ajay")) diff --git a/leetcode/Solution.py b/leetcode/Solution.py new file mode 100644 index 0000000..831268d --- /dev/null +++ b/leetcode/Solution.py @@ -0,0 +1,17 @@ +from typing import List +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + for j in range(0, len(nums)): + for i in range(0, len(nums)): + if (i!=j): + sumOf=nums[j] + nums[i] + if (sumOf == target): + return j, i +# Enumeration is faster than this +# def twoSum(self, nums, target): +# a ={} +# for i, num in enumerate(nums): +# if target-num in a: +# return [a[target - num], i] +# else: +# a[num] = i \ No newline at end of file diff --git a/leetcode/twosum.py b/leetcode/twosum.py new file mode 100644 index 0000000..afeac06 --- /dev/null +++ b/leetcode/twosum.py @@ -0,0 +1,4 @@ +from Solution import Solution + +sol = Solution() +print(sol.twoSum([11, 7,22, 2], 9)) diff --git a/pipenv/Pipfile b/pipenv/Pipfile new file mode 100644 index 0000000..defc7d4 --- /dev/null +++ b/pipenv/Pipfile @@ -0,0 +1,13 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +Flask = "===1.1.1" +pypdf2 = "*" + +[requires] +python_version = "3.8" diff --git a/pipenv/Pipfile.lock b/pipenv/Pipfile.lock new file mode 100644 index 0000000..bc6502e --- /dev/null +++ b/pipenv/Pipfile.lock @@ -0,0 +1,102 @@ +{ + "_meta": { + "hash": { + "sha256": "52eb69fabc11142aeeb55a8404070de9f9b99ac42460d20b32985aa8243b7f27" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "click": { + "hashes": [ + "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc", + "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a" + ], + "version": "==7.1.1" + }, + "flask": { + "hashes": [ + "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52", + "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6" + ], + "index": "pypi", + "version": "==1.1.1" + }, + "itsdangerous": { + "hashes": [ + "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", + "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" + ], + "version": "==1.1.0" + }, + "jinja2": { + "hashes": [ + "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250", + "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49" + ], + "version": "==2.11.1" + }, + "markupsafe": { + "hashes": [ + "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", + "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", + "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", + "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", + "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", + "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", + "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", + "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", + "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", + "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", + "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", + "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", + "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", + "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", + "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", + "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", + "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", + "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", + "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", + "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", + "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", + "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" + ], + "version": "==1.1.1" + }, + "pypdf2": { + "hashes": [ + "sha256:e28f902f2f0a1603ea95ebe21dff311ef09be3d0f0ef29a3e44a932729564385" + ], + "index": "pypi", + "version": "==1.26.0" + }, + "werkzeug": { + "hashes": [ + "sha256:169ba8a33788476292d04186ab33b01d6add475033dfc07215e6d219cc077096", + "sha256:6dc65cf9091cf750012f56f2cad759fa9e879f511b5ff8685e456b4e3bf90d16" + ], + "version": "==1.0.0" + } + }, + "develop": {} +} diff --git a/pipenv/basics.py b/pipenv/basics.py new file mode 100644 index 0000000..f109121 --- /dev/null +++ b/pipenv/basics.py @@ -0,0 +1,3 @@ +name = input("Enter your name: ") +print("Name: ",name) +print(f"Name: {name}") diff --git a/pipenv/example.pdf b/pipenv/example.pdf new file mode 100644 index 0000000..efba1fb Binary files /dev/null and b/pipenv/example.pdf differ diff --git a/pipenv/hello.py b/pipenv/hello.py new file mode 100644 index 0000000..0a54f08 --- /dev/null +++ b/pipenv/hello.py @@ -0,0 +1,10 @@ + +from flask import Flask +# set the project root directory as the static folder, you can set others. +app = Flask(__name__) + +@app.route("/hello") +def hello(): + return "Hello World!" + +app.run(debug=True) diff --git a/pipenv/learn/__init__.py b/pipenv/learn/__init__.py new file mode 100644 index 0000000..2c9f264 --- /dev/null +++ b/pipenv/learn/__init__.py @@ -0,0 +1,2 @@ +from learn.learn import Learn +# This will simplify import as learn than learn.learn for consumer diff --git a/pipenv/learn/learn.py b/pipenv/learn/learn.py new file mode 100644 index 0000000..c1c51c0 --- /dev/null +++ b/pipenv/learn/learn.py @@ -0,0 +1,6 @@ +class Learn: + def __init__(self, text): + self.text = text + + def share(self): + return self.text diff --git a/pipenv/modules.py b/pipenv/modules.py new file mode 100644 index 0000000..532a216 --- /dev/null +++ b/pipenv/modules.py @@ -0,0 +1,4 @@ +import learn + +l = learn.Learn("This is a learning program") +print(l.share()) \ No newline at end of file diff --git a/pipenv/pdf_reader.py b/pipenv/pdf_reader.py new file mode 100644 index 0000000..5abc868 --- /dev/null +++ b/pipenv/pdf_reader.py @@ -0,0 +1,20 @@ +# importing required modules +import PyPDF2 + +# creating a pdf file object +pdfFileObj = open('example.pdf', 'rb') + +# creating a pdf reader object +pdfReader = PyPDF2.PdfFileReader(pdfFileObj) + +# printing number of pages in pdf file +print("No of pages: ", pdfReader.numPages) + +# creating a page object +pageObj = pdfReader.getPage(0) + +# extracting text from page +print("Text: ", pageObj.extractText()) + +# closing the pdf file object +pdfFileObj.close() diff --git a/pipenv/requirements.txt b/pipenv/requirements.txt new file mode 100644 index 0000000..3862655 --- /dev/null +++ b/pipenv/requirements.txt @@ -0,0 +1 @@ +flask===1.1.1 diff --git a/tuples.py b/tuples/tuples.py similarity index 100% rename from tuples.py rename to tuples/tuples.py