├── .github └── FUNDING.yml ├── README.md ├── castle_kilmere.png ├── code_per_day ├── config.yaml ├── day_1.py ├── day_10_and_11.py ├── day_12_to_15.py ├── day_16_to_18.py ├── day_19.py ├── day_2.py ├── day_20.py ├── day_22_to_24.py ├── day_29_to_31.py ├── day_3.py ├── day_34.py ├── day_37.py ├── day_4.py ├── day_43_to_45.py ├── day_46.py ├── day_47_to_48.py ├── day_49_to_50.py ├── day_6.py ├── day_8.py ├── day_9.py └── error.py ├── config.yaml ├── magical_universe.py └── test_code ├── test_abstract_base_class_spell.py ├── test_castle_kilmere_member_class.py ├── test_dark_army_member_class.py ├── test_ghost_class.py ├── test_potion_class.py ├── test_professor_class.py └── test_pupil_class.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: zotroneneis 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Awesome Python Features Explained Using the World of Magic 2 | 3 | 4 | 5 | As outlined in [my blog post](https://alpopkes.com/posts/python/magical_universe/day_1_start/), I decided to take on a new habit using a technique I found on the ['get disciplined' subreddit](https://www.reddit.com/r/getdisciplined/comments/1x99m6/im_a_piece_of_shit_no_more_games_no_more_lies_no/cf9dz72/). 6 | 7 | As one of my new habits I chose: "Code for 15 minutes every day". As part of the habit I've started creating a series of **blog posts** on important and awesome **Python features**, including object oriented programming, properties, function annotations, duck typing, etc. 8 | 9 | Since I was bored by the usual tutorial examples, I looked for a topic that would make it fun to study and implement the concepts. And since I absolutely love Harry Potter, I started creating my own magical universe around the topics. A short introduction into my magical universe - **The Tales of Castle Kilmere** can be found [here](https://alpopkes.com/posts/python/magical_universe/day_1_magical_universe/). So if you like magic and want to improve your Python knowledge and skills, get right into it! 10 | 11 | A logbook of what I worked on each day can be found on my [website](https://alpopkes.com/posts/python/magical_universe/). 12 | 13 | The code runs in **Python 3.6**, the [code on data classes](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_16_to_18.py) requires Python 3.7 (or you pip install data classes for Python 3.6). 14 | 15 | Start date: 07/23/2018 16 | 17 | ## Keynote at PyCon Estonia and EuroPython 18 | 19 | I gave a keynote talk about this project titled "Finding Magic in Python" at PyCon Estonia 2020. So if you are up for some magic and want to see an introduction to some of the topics (like Namedtuples or Abstract Base Classes) check out the [recording on YouTube](https://www.youtube.com/watch?v=Kf92pycivt4). 20 | 21 | I held another talk at EuroPython, check out [the recording here](https://www.youtube.com/watch?v=J4e4YCZ-jiQ). 22 | 23 | ## Running pytest 24 | 25 | In case you get ```ImportError: no module named magical_universe``` when running pytest from within the test_code directory, take a look at [this post](https://stackoverflow.com/questions/10253826/path-issue-with-pytest-importerror-no-module-named-yadayadayada) and try running pytest from the root directory (which is the home directory in my case) using ```python -m pytest magical_universe/test_code/```. 26 | 27 | ## Overview 28 | 29 | | Day | Topics | Blog post with explanations | Code for the day | 30 | | :---: |:--------------: | :--------------------------:| :----------------:| 31 | | 1 | Intro to object oriented programming, classes, inheritance | [Day 1](https://alpopkes.com/posts/python/magical_universe/day_1_first_post_oop/) | [Code day 1](https://github.com/zotroneneis/100_days_of_code/blob/master/code_per_day/day_1.py) | 32 | | 2 | Class methods, instance methods, static methods, using class methods as alternative constructors | [Day 2](https://alpopkes.com/posts/python/magical_universe/day_2_types_of_methods/) | [Code day 2](https://github.com/zotroneneis/100_days_of_code/blob/master/code_per_day/day_2.py) | 33 | | 3 |Type annotations|[Day 3](https://alpopkes.com/posts/python/magical_universe/day_3_type_annotations/) | [Code day 3](https://github.com/zotroneneis/100_days_of_code/blob/master/code_per_day/day_3.py) | 34 | | 4 |To-string conversion, `__repr__, __str__`|[Day 4](https://alpopkes.com/posts/python/magical_universe/day_4_to_string_conversion/) | [Code day 4](https://github.com/zotroneneis/100_days_of_code/blob/master/code_per_day/day_4.py) | 35 | | 5 |Decorators|[Day 5](https://alpopkes.com/posts/python/magical_universe/day_5_decorators/) | No new code added | 36 | | 6 |Properties, `@property` and `property()`, setters, getters|[Day 6](https://alpopkes.com/posts/python/magical_universe/day_6_properties/) | [Code day 6](https://github.com/zotroneneis/100_days_of_code/blob/master/code_per_day/day_6.py) | 37 | | 7 |Underscore patterns for variable naming, `_variable, __variable, __variable__, etc.`|[Day 7](https://alpopkes.com/posts/python/magical_universe/day_7_underscore_patterns/) | No new code added | 38 | | 8 | New methods and classes added to the HP universe |[Day 8](https://alpopkes.com/posts/python/magical_universe/day_8_extending_universe/) | [Code day 8](https://github.com/zotroneneis/100_days_of_code/blob/master/code_per_day/day_8.py) | 39 | | 9 | Duck typing, EAFP principle |[Day 9](https://alpopkes.com/posts/python/magical_universe/day_9_duck_typing/) | [Code day 9](https://github.com/zotroneneis/100_days_of_code/blob/master/code_per_day/day_9.py) | 40 | | 10 & 11| Namedtuples | [Day 10 & 11](https://alpopkes.com/posts/python/magical_universe/day_10_11_namedtuples/) | [Code day 10 & 11](https://github.com/zotroneneis/100_days_of_code/blob/master/code_per_day/day_10_and_11.py)| 41 | | 12 - 15 | Abstract Base Classes | [Day 12 to 15](https://alpopkes.com/posts/python/magical_universe/day_12_to_15_abcs/) | [Code day 12 to 15](https://github.com/zotroneneis/100_days_of_code/blob/master/code_per_day/day_12_to_15.py)| 42 | | 16 - 18 | Data Classes | [Day 16 to 18](https://alpopkes.com/posts/python/magical_universe/day_16_to_18_data_classes/) | [Code day 16 to 18](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_16_to_18.py)| 43 | | 19 | Immutable Data Classes | [Day 19](https://alpopkes.com/posts/python/magical_universe/day_19_immutable_data_classes/) | [Code day 19](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_19.py)| 44 | | 20 | Decorators within a class | [Day 20](https://alpopkes.com/posts/python/magical_universe/day_20_decorators_in_classes/) | [Code day 20](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_20.py)| 45 | | 21 | The mysterious `if __name__ == "__main__"` | [Day 21](https://alpopkes.com/posts/python/magical_universe/day_21_if_main/) | No new code added | 46 | | 22 - 24 | Context managers and the `with` statement| [Day 22 to 24](https://alpopkes.com/posts/python/magical_universe/day_22_to_24_context_managers/) | [Code day 22 to 24](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_22_to_24.py) | 47 | | 25 - 28 | Testing code with pytest| [Day 25 to 28](https://alpopkes.com/posts/python/magical_universe/day_25_to_28_pytest/) | [Code day 25 to 28](https://github.com/zotroneneis/magical_universe/blob/master/test_code/test_hogwarts_member_class.py) | 48 | | 29 - 31 | Iterators, iterables, iteration| [Day 29 to 31](https://alpopkes.com/posts/python/magical_universe/day_29_to_31_iterators/) | [Code day 29 to 31](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_29_to_31.py) | 49 | | 32 | Test code for `Professor` class | No blog post, see [Day 25 to 28](http://alpopkes.com/posts/2018/08/coding-challenge-day-51/) for an introduction to testing| [Code day 32](https://github.com/zotroneneis/magical_universe/blob/master/test_code/test_professor_class.py) | 50 | | 33 | Test code for `Ghost` class | No blog post, see [Day 25 to 28](http://alpopkes.com/posts/2018/08/coding-challenge-day-51/) for an introduction to testing| [Code day 33](https://github.com/zotroneneis/magical_universe/blob/master/test_code/test_ghost_class.py) | 51 | | 34 | Counting objects with `Collections.counter` | [Day 34](https://alpopkes.com/posts/python/magical_universe/day_34_multisets/) | [Day 34](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_34.py) | 52 | | 35 | Test code for `DarkArmyMember` class | No blog post, see [Day 25 to 28](http://alpopkes.com/posts/2018/08/coding-challenge-day-51/) for an introduction to testing| [Code day 35](https://github.com/zotroneneis/magical_universe/blob/master/test_code/test_dark_army_member_class.py) | 53 | | 36 | Test code for `Potion` class | No blog post, see [Day 25 to 28](http://alpopkes.com/posts/2018/08/coding-challenge-day-51/) for an introduction to testing| [Code day 36](https://github.com/zotroneneis/magical_universe/blob/master/test_code/test_potion_class.py) | 54 | | 37 | Extension of Magical Universe with classmethods for `Charm, Hex, Curse`, etc. | [Day 37](https://alpopkes.com/posts/python/magical_universe/day_37_extending_universe/) | [Code day 37](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_37.py) | 55 | | 38 - 39 | Test code for `Spell` class | No blog post, see [Day 25 to 28](http://alpopkes.com/posts/2018/08/coding-challenge-day-51/) for an introduction to testing| [Code day 38 to 39](https://github.com/zotroneneis/magical_universe/blob/master/test_code/test_abstract_base_class_spell.py) | 56 | | 40 - 42 | Test code for `Pupil` class | No blog post, see [Day 25 to 28](http://alpopkes.com/posts/2018/08/coding-challenge-day-51/) for an introduction to testing| [Code day 40 to 42](https://github.com/zotroneneis/magical_universe/blob/master/test_code/test_pupil_class.py) | 57 | | 43 - 45 | Custom exception classes| [Day 43 to 45](https://alpopkes.com/posts/python/magical_universe/day_43_to_45_exception_classes/) | [Code day 43 to 45](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_43_to_45.py) | 58 | | 46 | `functools.wraps` - Avoiding losing metdata when applying decorators| [Day 46](https://alpopkes.com/posts/python/magical_universe/day_46_functools_wraps/) | [Code day 46](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_46.py) | 59 | | 47 - 48 | `collections.defaultdict`| [Day 47 to 48](https://alpopkes.com/posts/python/magical_universe/day_47_to_48_defaultdict/) | [Code day 47 to 48](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_47_to_48.py) | 60 | | 49 - 50 | Working with config files| [Day 49 to 50](https://alpopkes.com/posts/python/magical_universe/day_49_to_50_config_files/) | [Code day 49 to 50](https://github.com/zotroneneis/magical_universe/blob/master/code_per_day/day_49_to_50.py) | 61 | | 51 | Wrap up| [Day 51](https://alpopkes.com/posts/python/magical_universe/2018-09-16-blog-post-day-51/) | No new code added | 62 | 63 | 64 | ## Feedback 65 | 66 | In case you find a mistake in the code or the blog posts, please let me know by opening an issue! 67 | -------------------------------------------------------------------------------- /castle_kilmere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zotroneneis/magical_universe/c5da3367b7854c4cf9625c45e03742dba3a6d63c/castle_kilmere.png -------------------------------------------------------------------------------- /code_per_day/config.yaml: -------------------------------------------------------------------------------- 1 | bromley: 2 | name: 'Bromley Huckabee' 3 | birthyear: 1959 4 | sex: male 5 | 6 | luke: 7 | name: 'Luke Bery' 8 | birthyear: 2008 9 | sex: 'male' 10 | start_year: 2020 11 | pet: ['Cotton', 'owl'] 12 | 13 | lissy: 14 | name: 'Lissy Spinster' 15 | birthyear: 2008 16 | sex: 'female' 17 | start_year: 2020 18 | pet: ['Ramses', 'cat'] 19 | 20 | -------------------------------------------------------------------------------- /code_per_day/day_1.py: -------------------------------------------------------------------------------- 1 | """ 2 | File: day_1.py 3 | Author: Anna-Lena Popkes 4 | Email: popkes@gmx.net 5 | Github: https://github.com/zotflynneneis 6 | Description: all code for day 1 of my new coding habit 7 | Link to blog post with explanations: http://www.alpopkes.com/posts/2018/07/coding-challenge-day-1/ 8 | """ 9 | 10 | class CastleKilmereMember: 11 | """ Creates a member of the Castle Kilmere School of Magic """ 12 | 13 | def __init__(self, name, birthyear, sex): 14 | self.name = name 15 | self.birthyear = birthyear 16 | self.sex = sex 17 | 18 | def says(self, words): 19 | return f"{self.name} says {words}" 20 | 21 | 22 | class Pupil(CastleKilmereMember): 23 | """ Create a Castle Kilmere Pupil """ 24 | def __init__(self, name, birthyear, sex, start_year, pet=None): 25 | super().__init__(name, birthyear, sex) 26 | self.start_year = start_year 27 | 28 | if pet is not None: 29 | self.pet_name, self.pet_type = pet 30 | 31 | self._elms = { 32 | 'Critical Thinking': False, 33 | 'Self-Defense Against Fresh Fruit': False, 34 | 'Broomstick Flying': False, 35 | 'Magical Theory': False, 36 | 'Foreign Magical Systems': False, 37 | 'Charms': False, 38 | 'Defence Against Dark Magic': False, 39 | 'History of Magic': False, 40 | 'Potions': False, 41 | 'Transfiguration': False} 42 | 43 | class Professor(CastleKilmereMember): 44 | """ Creates a Castle Kilmere professor """ 45 | def __init__(self, name, birthyear, sex, subject, department=None): 46 | super().__init__(name, birthyear, sex) 47 | self.subject = subject 48 | self.department = department 49 | 50 | class Ghost(CastleKilmereMember): 51 | """ Creates a Castle Kilmere ghost """ 52 | def __init__(self, name, birthyear, sex, year_of_death): 53 | super().__init__(name, birthyear, sex) 54 | self.year_of_death = year_of_death 55 | 56 | if __name__ == "__main__": 57 | bromley = CastleKilmereMember('Bromley Huckabee', 1959, 'male') 58 | print(bromley.says("Hello!")) 59 | 60 | lissy = Pupil(name='Lissy Spinster', 61 | birthyear=2008, 62 | sex='female', 63 | start_year=2020, 64 | pet=('Ramses', 'cat')) 65 | 66 | print(lissy.says("Hello Luke!")) 67 | -------------------------------------------------------------------------------- /code_per_day/day_10_and_11.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import NamedTuple 3 | 4 | class CastleKilmereMember: 5 | """ Creates a member of the Castle Kilmere School of Magic """ 6 | 7 | def __init__(self, name: str, birthyear: int, sex: str): 8 | self.name = name 9 | self.birthyear = birthyear 10 | self.sex = sex 11 | self._traits = {} 12 | 13 | def says(self, words: str) -> str: 14 | return f"{self.name} says {words}" 15 | 16 | def add_trait(self, trait, value=True): 17 | self._traits[trait] = value 18 | 19 | def print_traits(self): 20 | true_traits = [trait for trait, value in self._traits.items() if value] 21 | false_traits = [trait for trait, value in self._traits.items() if not value] 22 | 23 | if true_traits: 24 | print(f"{self.name} is {', '.join(true_traits)}") 25 | if false_traits: 26 | print(f"{self.name} is not {', '.join(false_traits)}") 27 | if (not true_traits and not false_traits): 28 | print(f"{self.name} does not have traits yet") 29 | 30 | def exhibits_trait(self, trait: str) -> bool: 31 | try: 32 | value = self._traits[trait] 33 | return value 34 | except KeyError as e: 35 | print(f"{self.name} does not have a character trait with the name {e}") 36 | return False 37 | 38 | @property 39 | def age(self) -> int: 40 | now = datetime.datetime.now().year 41 | return now - self.birthyear 42 | 43 | @classmethod 44 | def school_headmistress(cls) -> 'CastleKilmereMember': 45 | return cls('Miranda Mirren', 1963, 'female') 46 | 47 | def __repr__(self) -> str: 48 | return (f"{self.__class__.__name__}(name='{self.name}', " 49 | f"birthyear={self.birthyear}, sex='{self.sex}')") 50 | 51 | 52 | class Professor(CastleKilmereMember): 53 | """ Creates a Castle Kilmere professor """ 54 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 55 | super().__init__(name, birthyear, sex) 56 | self.subject = subject 57 | self.department = department 58 | 59 | @classmethod 60 | def blade(cls): 61 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'Science') 62 | 63 | @classmethod 64 | def briddle(cls): 65 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Law') 66 | 67 | def __repr__(self) -> str: 68 | return (f"{self.__class__.__name__}(name='{self.name}', " 69 | f"birthyear={self.birthyear}, sex='{self.sex}', " 70 | f"subject='{self.subject}', department='{self.department}')") 71 | 72 | 73 | class Ghost(CastleKilmereMember): 74 | """ Creates a Castle Kilmere ghost """ 75 | def __init__(self, name: str, birthyear: int, sex: str, year_of_death: int): 76 | super().__init__(name, birthyear, sex) 77 | self.year_of_death = year_of_death 78 | 79 | @property 80 | def age(self) -> int: 81 | now = datetime.datetime.now().year 82 | return now - self.birthyear 83 | 84 | @classmethod 85 | def mocking_knight(cls): 86 | return cls('The Mocking Knight', 1401, 'male', 1492) 87 | 88 | def __repr__(self) -> str: 89 | return (f"{self.__class__.__name__}(name='{self.name}', " 90 | f"birthyear={self.birthyear}, sex='{self.sex}', " 91 | f"year_of_death={self.year_of_death})") 92 | 93 | class Pupil(CastleKilmereMember): 94 | """ Create a Castle Kilmere Pupil """ 95 | def __init__(self, name: str, birthyear: int, sex: str, start_year: int, pet: tuple = None): 96 | super().__init__(name, birthyear, sex) 97 | self.start_year = start_year 98 | 99 | if pet is not None: 100 | self.pet_name, self.pet_type = pet 101 | 102 | self._elms = { 103 | 'Critical Thinking': False, 104 | 'Self-Defense Against Fresh Fruit': False, 105 | 'Broomstick Flying': False, 106 | 'Magical Theory': False, 107 | 'Foreign Magical Systems': False, 108 | 'Charms': False, 109 | 'Defence Against Dark Magic': False, 110 | 'History of Magic': False, 111 | 'Potions': False, 112 | 'Transfiguration': False} 113 | 114 | self._friends = [] 115 | 116 | @classmethod 117 | def luke(cls): 118 | return cls('Luke Bery', 2008, 'male', 2018, ('Cotton', 'owl')) 119 | 120 | @classmethod 121 | def lissy(cls): 122 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 123 | 124 | @classmethod 125 | def adrien(cls): 126 | return cls('Adrien Fulford', 2008, 'male', 2018, ('Twiggles', 'owl') ) 127 | 128 | @property 129 | def current_year(self) -> int: 130 | now = datetime.datetime.now().year 131 | return (now - self.start_year) + 1 132 | 133 | @property 134 | def elms(self): 135 | return self._elms 136 | 137 | @property 138 | def friends(self): 139 | return f"{self.name}'s current friends are: {[person.name for person in self._friends]}" 140 | 141 | @elms.setter 142 | def elms(self, subject_and_grade): 143 | try: 144 | subject, grade = subject_and_grade 145 | except ValueError: 146 | raise ValueError("Pass and iterable with two items: subject and grade") 147 | 148 | passed = self.passed(grade) 149 | 150 | if passed: 151 | self._elms[subject] = True 152 | else: 153 | print('The exam was not passed so no ELM was awarded!') 154 | 155 | @elms.deleter 156 | def elms(self): 157 | print("Caution, you are deleting this students' ELM's! " 158 | "You should only do that if she/he dropped out of school without passing any exam!") 159 | del self._elms 160 | 161 | 162 | @staticmethod 163 | def passed(grade): 164 | """ 165 | Given a grade, determine if an exam was passed. 166 | """ 167 | 168 | grades = { 169 | 'E': True, 170 | 'Excellent': True, 171 | 'G': True, 172 | 'Good': True, 173 | 'A': True, 174 | 'Acceptable': True, 175 | 'P': False, 176 | 'Poor': False, 177 | 'H': False, 178 | 'Horrible': False, 179 | } 180 | 181 | return grades.get(grade, False) 182 | 183 | def befriend(self, person): 184 | """Adds another person to your list of friends""" 185 | self._friends.append(person) 186 | print(f"{person.name} is now your friend!") 187 | 188 | def __repr__(self) -> str: 189 | return (f"{self.__class__.__name__}(name='{self.name}', " 190 | f"birthyear={self.birthyear}, sex='{self.sex}', " 191 | f"start_year={self.start_year})") 192 | 193 | class DarkArmyMember(NamedTuple): 194 | """ Creates a member of the Dark Army """ 195 | name: str 196 | birthyear: str 197 | 198 | @property 199 | def leader(self): 200 | master_odon = DarkArmyMember('Master Odon', 1971) 201 | return master_odon 202 | 203 | if __name__ == "__main__": 204 | keres = DarkArmyMember('Keres Fulford', 1953) 205 | print('Keres: ', keres) 206 | print('Leader: ', keres.leader) 207 | 208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /code_per_day/day_12_to_15.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import NamedTuple 3 | from abc import ABC, abstractmethod 4 | 5 | class CastleKilmereMember: 6 | """ Creates a member of the Castle Kilmere School of Magic """ 7 | 8 | def __init__(self, name: str, birthyear: int, sex: str): 9 | self.name = name 10 | self.birthyear = birthyear 11 | self.sex = sex 12 | self._traits = {} 13 | 14 | def says(self, words: str) -> str: 15 | return f"{self.name} says {words}" 16 | 17 | def add_trait(self, trait, value=True): 18 | self._traits[trait] = value 19 | 20 | def print_traits(self): 21 | true_traits = [trait for trait, value in self._traits.items() if value] 22 | false_traits = [trait for trait, value in self._traits.items() if not value] 23 | 24 | if true_traits: 25 | print(f"{self.name} is {', '.join(true_traits)}") 26 | if false_traits: 27 | print(f"{self.name} is not {', '.join(false_traits)}") 28 | if (not true_traits and not false_traits): 29 | print(f"{self.name} does not have traits yet") 30 | 31 | def exhibits_trait(self, trait: str) -> bool: 32 | try: 33 | value = self._traits[trait] 34 | return value 35 | except KeyError as e: 36 | print(f"{self.name} does not have a character trait with the name {e}") 37 | return False 38 | 39 | @property 40 | def age(self) -> int: 41 | now = datetime.datetime.now().year 42 | return now - self.birthyear 43 | 44 | @classmethod 45 | def school_headmistress(cls) -> 'CastleKilmereMember': 46 | return cls('Miranda Mirren', 1963, 'female') 47 | 48 | def __repr__(self) -> str: 49 | return (f"{self.__class__.__name__}(name='{self.name}', " 50 | f"birthyear={self.birthyear}, sex='{self.sex}')") 51 | 52 | 53 | class Professor(CastleKilmereMember): 54 | """ Creates a Castle Kilmere professor """ 55 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 56 | super().__init__(name, birthyear, sex) 57 | self.subject = subject 58 | self.department = department 59 | 60 | @classmethod 61 | def blade(cls): 62 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'Science') 63 | 64 | @classmethod 65 | def briddle(cls): 66 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Law') 67 | 68 | def __repr__(self) -> str: 69 | return (f"{self.__class__.__name__}(name='{self.name}', " 70 | f"birthyear={self.birthyear}, sex='{self.sex}', " 71 | f"subject='{self.subject}', department='{self.department}')") 72 | 73 | 74 | class Ghost(CastleKilmereMember): 75 | """ Creates a Castle Kilmere ghost """ 76 | def __init__(self, name: str, birthyear: int, sex: str, year_of_death: int): 77 | super().__init__(name, birthyear, sex) 78 | self.year_of_death = year_of_death 79 | 80 | @property 81 | def age(self) -> int: 82 | now = datetime.datetime.now().year 83 | return now - self.birthyear 84 | 85 | def __repr__(self) -> str: 86 | return (f"{self.__class__.__name__}(name='{self.name}', " 87 | f"birthyear={self.birthyear}, sex='{self.sex}', " 88 | f"year_of_death={self.year_of_death})") 89 | 90 | @classmethod 91 | def mocking_knight(cls): 92 | return cls('The Mocking Knight', 1401, 'male', 1492) 93 | 94 | 95 | class Pupil(CastleKilmereMember): 96 | """ Create a Castle Kilmere Pupil """ 97 | def __init__(self, name: str, birthyear: int, sex: str, start_year: int, pet: tuple = None): 98 | super().__init__(name, birthyear, sex) 99 | self.start_year = start_year 100 | self.known_spells = set() 101 | 102 | if pet is not None: 103 | self.pet_name, self.pet_type = pet 104 | 105 | self._elms = { 106 | 'Critical Thinking': False, 107 | 'Self-Defense Against Fresh Fruit': False, 108 | 'Broomstick Flying': False, 109 | 'Magical Theory': False, 110 | 'Foreign Magical Systems': False, 111 | 'Charms': False, 112 | 'Defence Against Dark Magic': False, 113 | 'History of Magic': False, 114 | 'Potions': False, 115 | 'Transfiguration': False} 116 | 117 | self._friends = [] 118 | 119 | @classmethod 120 | def luke(cls): 121 | return cls('Luke Bery', 2008, 'male', 2018, ('Cotton', 'owl')) 122 | 123 | @classmethod 124 | def lissy(cls): 125 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 126 | 127 | @classmethod 128 | def adrien(cls): 129 | return cls('Adrien Fulford', 2008, 'male', 2018, ('Twiggles', 'owl') ) 130 | 131 | @property 132 | def current_year(self) -> int: 133 | now = datetime.datetime.now().year 134 | return (now - self.start_year) + 1 135 | 136 | @property 137 | def elms(self): 138 | return self._elms 139 | 140 | @property 141 | def friends(self): 142 | return f"{self.name}'s current friends are: {[person.name for person in self._friends]}" 143 | 144 | @elms.setter 145 | def elms(self, subject_and_grade): 146 | try: 147 | subject, grade = subject_and_grade 148 | except ValueError: 149 | raise ValueError("Pass and iterable with two items: subject and grade") 150 | 151 | passed = self.passed(grade) 152 | 153 | if passed: 154 | self._elms[subject] = True 155 | else: 156 | print('The exam was not passed so no ELM was awarded!') 157 | 158 | @elms.deleter 159 | def elms(self): 160 | print("Caution, you are deleting this students' ELM's! " 161 | "You should only do that if she/he dropped out of school without passing any exam!") 162 | del self._elms 163 | 164 | 165 | @staticmethod 166 | def passed(grade): 167 | """ 168 | Given a grade, determine if an exam was passed. 169 | """ 170 | grades = { 171 | 'E': True, 172 | 'Excellent': True, 173 | 'G': True, 174 | 'Good': True, 175 | 'A': True, 176 | 'Acceptable': True, 177 | 'P': False, 178 | 'Poor': False, 179 | 'H': False, 180 | 'Horrible': False, 181 | } 182 | 183 | return grades.get(grade, False) 184 | 185 | def befriend(self, person): 186 | """Adds another person to your list of friends""" 187 | self._friends.append(person) 188 | print(f"{person.name} is now your friend!") 189 | 190 | def __repr__(self) -> str: 191 | return (f"{self.__class__.__name__}(name='{self.name}', " 192 | f"birthyear={self.birthyear}, sex='{self.sex}', " 193 | f"start_year={self.start_year})") 194 | 195 | def learn_spell(self, spell): 196 | """ Allows a pupil to learn a spell, given that he/she is old enough """ 197 | if spell.min_year is not None: 198 | if self.current_year >= spell.min_year: 199 | print(f"{self.name} now knows spell {spell.name}") 200 | self.known_spells.add(spell) 201 | 202 | elif self.exhibits_trait('highly intelligent'): 203 | print(f"{self.name} now knows spell {spell.name}") 204 | self.known_spells.add(spell) 205 | 206 | elif self.current_year < spell.min_year: 207 | print(f"{self.name} is too young to study this spell!") 208 | 209 | elif spell.__class__.__name__ in ['Hex', 'Curse']: 210 | # Only evil pupils would study hexes and curses 211 | if self.exhibits_trait('evil'): 212 | print(f"{self.name} now knows spell {spell.name}") 213 | self.known_spells.add(spell) 214 | 215 | else: 216 | print(f"How dare you study a hex or curse?!") 217 | 218 | else: 219 | print(f"{self.name} now knows spell {spell.name}") 220 | self.known_spells.add(spell) 221 | 222 | def cast_spell(self, spell): 223 | """ Allows a pupil to cast a spell """ 224 | if spell.__class__.__name__ == 'Curse': 225 | print("This is dark magic - stay away from performing curses!") 226 | 227 | elif spell.__class__.__name__ == 'Hex': 228 | if not self.exhibits_trait('evil'): 229 | print(f"You shouldn't cast a hex, that's mean!") 230 | 231 | elif spell in self.known_spells: 232 | print(f"{self.name}: {spell.incantation}!") 233 | 234 | elif spell.name not in self.known_spells: 235 | print(f"You can't cast the {spell.name} spell correctly " 236 | f" - you have to study it first! ") 237 | 238 | 239 | class Spell(ABC): 240 | """Creates a spell""" 241 | def __init__(self, name: str, incantation: str, effect: str, min_year: int = None): 242 | self.name = name 243 | self.incantation = incantation 244 | self.effect = effect 245 | self.min_year = min_year 246 | 247 | @abstractmethod 248 | def cast(self): 249 | pass 250 | 251 | @property 252 | @abstractmethod 253 | def defining_feature(self): 254 | pass 255 | 256 | def __repr__(self): 257 | return f"{self.__class__.__name__}(name='{self.name}', incantation='{self.incantation}', effect='{self.effect}', difficulty='{self.difficulty}', min_year={self.min_year})" 258 | 259 | 260 | class Charm(Spell): 261 | """ Creates a charm - a spell that alters the inherent qualities of an object """ 262 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 263 | super().__init__(name, incantation, effect, min_year) 264 | self.difficulty = difficulty 265 | 266 | @property 267 | def defining_feature(self): 268 | return ("Alteration of the object's inherent qualities, " 269 | "that is, its behaviour and capabilities") 270 | 271 | def cast(self): 272 | print(f"{self.incantation}!") 273 | 274 | @classmethod 275 | def stuporus_ratiato(cls): 276 | return cls('The Stuporus Ratiato charm', 'Stuporus Ratiato', 'Makes objects fly') 277 | 278 | 279 | class Transfiguration(Spell): 280 | """ Creates a transfiguration - a spell that alters the form or appearance of an object """ 281 | def __init__(self, name: str, incantation: str, effect: str): 282 | super().__init__(name, incantation, effect) 283 | 284 | @property 285 | def defining_feature(self): 286 | return "Alteration of the object's form or appearance" 287 | 288 | def cast(self): 289 | pass 290 | 291 | class Jinx(Spell): 292 | """ Creates a jinx - a spell whose effects are irritating but amusing """ 293 | def __init__(self, name: str, incantation: str, effect: str): 294 | super().__init__(name, incantation, effect) 295 | 296 | @property 297 | def defining_feature(self): 298 | return ("Minor darf magic - " 299 | "a spell whose effects are irritating but amusing, " 300 | "almost playful and of minor inconvenience to the target") 301 | 302 | def cast(self): 303 | pass 304 | 305 | class Hex(Spell): 306 | """ Creates a hex - a spell that affects an object in a negative manner """ 307 | def __init__(self, name: str, incantation: str, effect: str): 308 | super().__init__(name, incantation, effect) 309 | 310 | @property 311 | def defining_feature(self): 312 | return ("Medium dark magic - " 313 | "Affects an object in a negative manner. " 314 | "Major inconvenience to the target.") 315 | 316 | def cast(self): 317 | pass 318 | 319 | class Curse(Spell): 320 | """ Creates a curse - a spell that affects an object in a stflynngly negative manner """ 321 | def __init__(self, name: str, incantation: str, effect: str, difficulty): 322 | super().__init__(name, incantation, effect) 323 | 324 | @property 325 | def defining_feature(self): 326 | return ("Worst kind of dark magic - " 327 | "Intended to affect an object in a stflynngly negative manner.") 328 | 329 | def cast(self): 330 | pass 331 | 332 | class CounterSpell(Spell): 333 | """ Creates a counter-spell - a spell that inhibits the effect of another spell """ 334 | def __init__(self, name: str, incantation: str, effect: str): 335 | super().__init__(name, incantation, effect) 336 | 337 | @property 338 | def defining_feature(self): 339 | return ("Inhibites the effects of another spell") 340 | 341 | def cast(self): 342 | pass 343 | 344 | class HealingSpell(Spell): 345 | """ Creates a healing-spell - a spell that improves the condition of a living object """ 346 | def __init__(self, name: str, incantation: str, effect: str): 347 | super().__init__(name, incantation, effect) 348 | 349 | @property 350 | def defining_feature(self): 351 | return "Improves the condition of a living object" 352 | 353 | def cast(self): 354 | pass 355 | 356 | 357 | class DarkArmyMember(NamedTuple): 358 | """ Creates a member of the Dark Army """ 359 | name: str 360 | birthyear: str 361 | 362 | @property 363 | def leader(self): 364 | master_odon = DarkArmyMember('Master Odon', 1971) 365 | return master_odon 366 | 367 | def cast(self, spell): 368 | print(f"{self.name}: {spell.incantation}!") 369 | 370 | if __name__ == "__main__": 371 | 372 | ghost = Ghost.mocking_knight() 373 | print('ghost: ', ghost) 374 | print() 375 | 376 | stuporus = Charm.stuporus_ratiato() 377 | liberula = Charm('The liberula charm', 'Liberula', 'Allows a person to breathe under water', 'difficult', min_year=5) 378 | stickfast = Hex('The stickfast hex', 'Colloshoo', "Makes target's shoes stick to ground") 379 | fiera = Curse('Torture curse', 'Fiera Satanotis', 'Tortures a person, makes person suffer deeply', 'Difficult') 380 | 381 | lissy = Pupil.lissy() 382 | luke = Pupil.luke() 383 | lissy.print_traits() 384 | lissy.add_trait('highly intelligent') 385 | lissy.print_traits() 386 | 387 | adrien = Pupil.adrien() 388 | adrien.print_traits() 389 | adrien.add_trait('evil') 390 | adrien.print_traits() 391 | 392 | print("Lissy knows the following spells: ", lissy.known_spells) 393 | print("Lissy is currently in year: ", lissy.current_year) 394 | lissy.learn_spell(stuporus) 395 | print('=======================================') 396 | 397 | # Test whether lissy can learn a spell he is too young for 398 | luke.learn_spell(liberula) 399 | # Can cassidy study the spell? 400 | lissy.learn_spell(liberula) 401 | print('=======================================') 402 | 403 | # Test whether lissy can study a hex 404 | lissy.learn_spell(stickfast) 405 | print('=======================================') 406 | # Can Adrien perform a hex? 407 | adrien.learn_spell(stickfast) 408 | print('=======================================') 409 | 410 | 411 | # Test whether lissy can study a curse 412 | lissy.learn_spell(fiera) 413 | print('=======================================') 414 | # Can Adrien study a curse? 415 | adrien.learn_spell(fiera) 416 | print('=======================================') 417 | 418 | # Test whether lissy can cast a Charm 419 | lissy.cast_spell(stuporus) 420 | print('=======================================') 421 | 422 | # What about a hex? 423 | lissy.cast_spell(stickfast) 424 | print('=======================================') 425 | 426 | # What about Adrien? 427 | adrien.cast_spell(stickfast) 428 | print('=======================================') 429 | 430 | 431 | 432 | -------------------------------------------------------------------------------- /code_per_day/day_16_to_18.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import NamedTuple 3 | from dataclasses import dataclass 4 | 5 | class CastleKilmereMember: 6 | """ Creates a member of the Castle Kilmere School of Magic """ 7 | def __init__(self, name: str, birthyear: int, sex: str): 8 | self.name = name 9 | self.birthyear = birthyear 10 | self.sex = sex 11 | self._traits = {} 12 | 13 | def says(self, words: str) -> str: 14 | return f"{self.name} says {words}" 15 | 16 | def add_trait(self, trait, value=True): 17 | self._traits[trait] = value 18 | 19 | def print_traits(self): 20 | true_traits = [trait for trait, value in self._traits.items() if value] 21 | false_traits = [trait for trait, value in self._traits.items() if not value] 22 | 23 | if true_traits: 24 | print(f"{self.name} is {', '.join(true_traits)}") 25 | if false_traits: 26 | print(f"{self.name} is not {', '.join(false_traits)}") 27 | if (not true_traits and not false_traits): 28 | print(f"{self.name} does not have traits yet") 29 | 30 | def exhibits_trait(self, trait: str) -> bool: 31 | value = self._traits[trait] 32 | return value 33 | 34 | @property 35 | def age(self): 36 | now = datetime.datetime.now().year 37 | return now - self.birthyear 38 | 39 | @classmethod 40 | def school_headmistress(cls) -> 'CastleKilmereMember': 41 | return cls('Miranda Mirren', 1963, 'female') 42 | 43 | def __repr__(self) -> str: 44 | return (f"{self.__class__.__name__}(name='{self.name}', " 45 | f"birthyear={self.birthyear}, sex='{self.sex}')") 46 | 47 | class Professor(CastleKilmereMember): 48 | """ Creates a Castle Kilmere professor """ 49 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 50 | super().__init__(name, birthyear, sex) 51 | self.subject = subject 52 | self.department = department 53 | 54 | @classmethod 55 | def blade(cls): 56 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'Science') 57 | 58 | @classmethod 59 | def briddle(cls): 60 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Law') 61 | 62 | @classmethod 63 | def radford(cls): 64 | return cls('Rupert Radford', 1958, 'male', 'Illusions 101', 'Creativity and Arts') 65 | 66 | def __repr__(self) -> str: 67 | return (f"{self.__class__.__name__}(name='{self.name}', " 68 | f"birthyear={self.birthyear}, sex='{self.sex}', " 69 | f"subject='{self.subject}', department='{self.department}')") 70 | 71 | 72 | class Ghost(CastleKilmereMember): 73 | """ Creates a Castle Kilmere ghost """ 74 | def __init__(self, name:str, birthyear:int, sex:str, year_of_death:int): 75 | super().__init__(name, birthyear, sex) 76 | self.year_of_death = year_of_death 77 | 78 | @property 79 | def age(self) -> int: 80 | now = datetime.datetime.now().year 81 | return now - self.birthyear 82 | 83 | def __repr__(self) -> str: 84 | return (f"{self.__class__.__name__}(name='{self.name}', " 85 | f"birthyear={self.birthyear}, sex='{self.sex}', " 86 | f"year_of_death={self.year_of_death})") 87 | 88 | @classmethod 89 | def mocking_knight(cls): 90 | return cls('The Mocking Knight', 1401, 'male', 1492) 91 | 92 | @classmethod 93 | def gray_groom(cls): 94 | return cls('The Gray Groom', 1000, 'male', 1050) 95 | 96 | @classmethod 97 | def scary_scoundrel(cls): 98 | return cls('Scary Scoundrel', 983, 'male', 1010) 99 | 100 | @classmethod 101 | def old_lady(cls): 102 | return cls('The Old Lady', 983, 'male', 996) 103 | 104 | 105 | @dataclass 106 | class Department: 107 | """ Creates a Castle Kilmere Department """ 108 | name: str 109 | head: Professor 110 | ghost: Ghost 111 | founded_in: int = 991 112 | 113 | def current_age(self): 114 | now = datetime.datetime.now().year 115 | return (now - self.founded_in) + 1 116 | 117 | 118 | if __name__ == "__main__": 119 | mocking_knight = Ghost.mocking_knight() 120 | gray_groom = Ghost.gray_groom() 121 | scary_scoundrel = Ghost.scary_scoundrel() 122 | old_lady = Ghost.old_lady() 123 | 124 | briddle = Professor.briddle() 125 | blade = Professor.blade() 126 | radford = Professor.radford() 127 | print('Age of Professor Radford: ', radford.age) 128 | 129 | 130 | law_department = Department('Law', 131 | briddle, 132 | mocking_knight) 133 | print('law_department: ', law_department) 134 | 135 | science_department = Department('Science', blade, scary_scoundrel) 136 | print('science_department: ', science_department) 137 | 138 | arts_department = Department('Creativity and Arts', radford, old_lady) 139 | print('arts_department: ', arts_department) 140 | 141 | 142 | -------------------------------------------------------------------------------- /code_per_day/day_19.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import NamedTuple 3 | from abc import ABC, abstractmethod 4 | from dataclasses import dataclass 5 | 6 | class CastleKilmereMember: 7 | """ Creates a member of the Castle Kilmere School of Magic """ 8 | def __init__(self, name: str, birthyear: int, sex: str): 9 | self.name = name 10 | self.birthyear = birthyear 11 | self.sex = sex 12 | self._traits = {} 13 | 14 | def says(self, words: str) -> str: 15 | return f"{self.name} says {words}" 16 | 17 | def add_trait(self, trait, value=True): 18 | self._traits[trait] = value 19 | 20 | def print_traits(self): 21 | true_traits = [trait for trait, value in self._traits.items() if value] 22 | false_traits = [trait for trait, value in self._traits.items() if not value] 23 | 24 | if true_traits: 25 | print(f"{self.name} is {', '.join(true_traits)}") 26 | if false_traits: 27 | print(f"{self.name} is not {', '.join(false_traits)}") 28 | if (not true_traits and not false_traits): 29 | print(f"{self.name} does not have traits yet") 30 | 31 | def exhibits_trait(self, trait: str) -> bool: 32 | value = self._traits[trait] 33 | return value 34 | 35 | @property 36 | def age(self): 37 | now = datetime.datetime.now().year 38 | return now - self.birthyear 39 | 40 | @classmethod 41 | def school_headmistress(cls) -> 'CastleKilmereMember': 42 | return cls('Miranda Mirren', 1963, 'female') 43 | 44 | def __repr__(self) -> str: 45 | return (f"{self.__class__.__name__}(name='{self.name}', " 46 | f"birthyear={self.birthyear}, sex='{self.sex}')") 47 | 48 | class Professor(CastleKilmereMember): 49 | """ Creates a Castle Kilmere professor """ 50 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 51 | super().__init__(name, birthyear, sex) 52 | self.subject = subject 53 | self.department = department 54 | 55 | @classmethod 56 | def blade(cls): 57 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'Science') 58 | 59 | @classmethod 60 | def briddle(cls): 61 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Law') 62 | 63 | @classmethod 64 | def radford(cls): 65 | return cls('Rupert Radford', 1958, 'male', 'Illusions 101', 'Creativity and Arts') 66 | 67 | @classmethod 68 | def giddings(cls): 69 | return cls('Gabriel Giddings', 1974, 'male', 'Broomstick Making', 'Engineering') 70 | 71 | def __repr__(self) -> str: 72 | return (f"{self.__class__.__name__}(name='{self.name}', " 73 | f"birthyear={self.birthyear}, sex='{self.sex}', " 74 | f"subject='{self.subject}', department='{self.department}')") 75 | 76 | 77 | class Ghost(CastleKilmereMember): 78 | """ Creates a Castle Kilmere ghost """ 79 | def __init__(self, name: str, birthyear: int, sex: str, year_of_death: int): 80 | super().__init__(name, birthyear, sex) 81 | 82 | self.year_of_death = year_of_death 83 | 84 | @property 85 | def age(self) -> int: 86 | now = datetime.datetime.now().year 87 | return now - self.birthyear 88 | 89 | def __repr__(self) -> str: 90 | return (f"{self.__class__.__name__}(name='{self.name}', " 91 | f"birthyear={self.birthyear}, sex='{self.sex}', " 92 | f"year_of_death={self.year_of_death})") 93 | 94 | @classmethod 95 | def mocking_knight(cls): 96 | return cls('The Mocking Knight', 1401, 'male', 1492) 97 | 98 | @classmethod 99 | def gray_groom(cls): 100 | return cls('The Gray Groom', 1000, 'male', 1050) 101 | 102 | @classmethod 103 | def scary_scoundrel(cls): 104 | return cls('Scary Scoundrel', 983, 'male', 1010) 105 | 106 | @classmethod 107 | def old_lady(cls): 108 | return cls('The Old Lady', 983, 'male', 996) 109 | 110 | 111 | class Pupil(CastleKilmereMember): 112 | """ Create a Castle Kilmere Pupil """ 113 | def __init__(self, name: str, birthyear: int, sex: str, start_year: int, pet: tuple = None): 114 | super().__init__(name, birthyear, sex) 115 | self.start_year = start_year 116 | self.known_spells = set() 117 | 118 | if pet is not None: 119 | self.pet_name, self.pet_type = pet 120 | 121 | self._elms = { 122 | 'Critical Thinking': False, 123 | 'Self-Defense Against Fresh Fruit': False, 124 | 'Broomstick Flying': False, 125 | 'Magical Theory': False, 126 | 'Foreign Magical Systems': False, 127 | 'Charms': False, 128 | 'Defence Against Dark Magic': False, 129 | 'History of Magic': False, 130 | 'Potions': False, 131 | 'Transfiguration': False} 132 | 133 | self._friends = [] 134 | 135 | @classmethod 136 | def luke(cls): 137 | return cls('Luke Bery', 2008, 'male', 2018, ('Cotton', 'owl')) 138 | 139 | @classmethod 140 | def lissy(cls): 141 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 142 | 143 | @classmethod 144 | def adrien(cls): 145 | return cls('Adrien Fulford', 2008, 'male', 2018, ('Unnamed', 'owl') ) 146 | 147 | @property 148 | def current_year(self): 149 | now = datetime.datetime.now().year 150 | return (now - self.start_year) + 1 151 | 152 | @property 153 | def elms(self): 154 | return self._elms 155 | 156 | @property 157 | def friends(self): 158 | return f"{self.name}'s current friends are: {[person.name for person in self._friends]}" 159 | 160 | @elms.setter 161 | def elms(self, subject_and_grade): 162 | try: 163 | subject, grade = subject_and_grade 164 | except ValueError: 165 | raise ValueError("Pass and iterable with two items: subject and grade") 166 | 167 | passed = self.passed(grade) 168 | 169 | if passed: 170 | self._elms[subject] = True 171 | else: 172 | print('The exam was not passed so no ELM was awarded!') 173 | 174 | @elms.deleter 175 | def elms(self): 176 | print("Caution, you are deleting this students' ELM's! " 177 | "You should only do that if she/he dropped out of school without passing any exam!") 178 | del self._elms 179 | 180 | 181 | @staticmethod 182 | def passed(grade): 183 | """ Given a grade, determine if an exam was passed. """ 184 | grades = { 185 | 'E': True, 186 | 'Excellent': True, 187 | 'G': True, 188 | 'Good': True, 189 | 'A': True, 190 | 'Acceptable': True, 191 | 'P': False, 192 | 'Poor': False, 193 | 'H': False, 194 | 'Horrible': False, 195 | } 196 | 197 | return grades.get(grade, False) 198 | 199 | def befriend(self, person): 200 | """Adds another person to your list of friends""" 201 | if (person.__class__.__name__ != 'CastleKilmereMember' 202 | and self.house != 'Slyterhin' 203 | and person.house == 'House of Ambition'): 204 | print("Are you sure you want to be friends with someone from House of Ambition?") 205 | 206 | self._friends.append(person) 207 | print(f"{person.name} is now your friend!") 208 | 209 | def __repr__(self) -> str: 210 | return (f"{self.__class__.__name__}(name='{self.name}', " 211 | f"birthyear={self.birthyear}, sex='{self.sex}', " 212 | f"start_year={self.start_year})") 213 | 214 | def learn_spell(self, spell): 215 | """ Allows a pupil to learn a spell, given that he/she is old enough """ 216 | if spell.min_year is not None: 217 | if self.current_year >= spell.min_year: 218 | print(f"{self.name} now knows spell {spell.name}") 219 | self.known_spells.add(spell) 220 | 221 | elif self.exhibits_trait('highly intelligent'): 222 | print(f"{self.name} now knows spell {spell.name}") 223 | self.known_spells.add(spell) 224 | 225 | elif self.current_year < spell.min_year: 226 | print(f"{self.name} is too young to study this spell!") 227 | 228 | elif spell.__class__.__name__ in ['Hex', 'Curse']: 229 | # Only House of Ambition's would study hexes and curses 230 | if self.house == 'House of Ambition': 231 | print(f"{self.name} now knows spell {spell.name}") 232 | self.known_spells.add(spell) 233 | 234 | else: 235 | print(f"How dare you study a hex or curse?!") 236 | 237 | def cast_spell(self, spell): 238 | """ Allows a pupil to cast a spell """ 239 | if spell.__class__.__name__ == 'Curse': 240 | print("This is dark magic - stay away from performing curses!") 241 | 242 | elif spell.__class__.__name__ == 'Hex': 243 | if self.house == 'House of Ambition': 244 | print(f"{self.name}: {spell.incantation}!") 245 | else: 246 | print(f"You shouldn't cast a hex, that's mean!") 247 | 248 | elif spell in self.known_spells: 249 | print(f"{self.name}: {spell.incantation}!") 250 | 251 | elif spell.name not in self.known_spells: 252 | print(f"You can't cast the {spell.name} spell correctly " 253 | f" - you have to study it first! ") 254 | 255 | 256 | class Spell(ABC): 257 | """Creates a spell""" 258 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 259 | self.name = name 260 | self.incantation = incantation 261 | self.effect = effect 262 | self.difficulty = difficulty 263 | self.min_year = min_yea 264 | 265 | @abstractmethod 266 | def cast(self): 267 | pass 268 | 269 | @property 270 | @abstractmethod 271 | def defining_feature(self): 272 | pass 273 | 274 | def __repr__(self): 275 | return f"{self.__class__.__name__}(name='{self.name}', incantation='{self.incantation}', effect='{self.effect}', difficulty='{self.difficulty}', min_year={self.min_year})" 276 | 277 | 278 | class Charm(Spell): 279 | """ Creates a charm - a spell that alters the inherent qualities of an object """ 280 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = 'Simple', min_year: int = 1): 281 | super().__init__(name, incantation, effect, difficulty, min_year) 282 | 283 | @property 284 | def defining_feature(self): 285 | return ("Alteration of the object's inherent qualities, " 286 | "that is, its behaviour and capabilities") 287 | 288 | def cast(self): 289 | print(f"{self.incantation}!") 290 | 291 | @classmethod 292 | def stuporus_ratiato(cls) -> 'Charm': 293 | return cls('The Stuporus Ratiato charm', 'Stuporus Ratiato', 'Makes objects fly') 294 | 295 | 296 | class Transfiguration(Spell): 297 | """ Creates a transfiguration - a spell that alters the form or appearance of an object """ 298 | def __init__(self, name: str, incantation: str, effect: str): 299 | super().__init__(name, incantation, effect) 300 | 301 | @property 302 | def defining_feature(self): 303 | return "Alteration of the object's form or appearance" 304 | 305 | def cast(self): 306 | pass 307 | 308 | class Jinx(Spell): 309 | """ Creates a jinx - a spell whose effects are irritating but amusing """ 310 | def __init__(self, name: str, incantation: str, effect: str): 311 | super().__init__(name, incantation, effect) 312 | 313 | @property 314 | def defining_feature(self): 315 | return ("Minor darf magic - " 316 | "a spell whose effects are irritating but amusing, " 317 | "almost playful and of minor inconvenience to the target") 318 | 319 | def cast(self): 320 | pass 321 | 322 | class Hex(Spell): 323 | """ Creates a hex - a spell that affects an object in a negative manner """ 324 | def __init__(self, name: str, incantation: str, effect: str, min_year: int = 5): 325 | super().__init__(name, incantation, effect, min_year) 326 | 327 | @property 328 | def defining_feature(self): 329 | return ("Medium dark magic - " 330 | "Affects an object in a negative manner. " 331 | "Major inconvenience to the target.") 332 | 333 | def cast(self): 334 | pass 335 | 336 | class Curse(Spell): 337 | """ Creates a curse - a spell that affects an object in a stflynngly negative manner """ 338 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Difficult"): 339 | super().__init__(name, incantation, effect) 340 | 341 | @property 342 | def defining_feature(self): 343 | return ("Worst kind of dark magic - " 344 | "Intended to affect an object in a stflynngly negative manner.") 345 | 346 | def cast(self): 347 | pass 348 | 349 | class CounterSpell(Spell): 350 | """ Creates a counter-spell - a spell that inhibits the effect of another spell """ 351 | def __init__(self, name: str, incantation: str, effect: str): 352 | super().__init__(name, incantation, effect) 353 | 354 | @property 355 | def defining_feature(self): 356 | return ("Inhibits the effects of another spell") 357 | 358 | def cast(self): 359 | pass 360 | 361 | class HealingSpell(Spell): 362 | """ Creates a healing-spell - a spell that improves the condition of a living object """ 363 | def __init__(self, name: str, incantation: str, effect: str): 364 | super().__init__(name, incantation, effect) 365 | 366 | @property 367 | def defining_feature(self): 368 | return "Improves the condition of a living object" 369 | 370 | def cast(self): 371 | pass 372 | 373 | 374 | @dataclass(frozen=True) 375 | class DarkArmyMember(): 376 | """ Creates a member of the dark army """ 377 | name: str 378 | birthyear: str 379 | 380 | @property 381 | def leader(self): 382 | master_odon = DarkArmyMember('Master Odon', 1971) 383 | return master_odon 384 | 385 | def cast(self, spell): 386 | print(f"{self.name}: {spell.incantation}!") 387 | 388 | 389 | @dataclass 390 | class Department: 391 | """ Creates a Castle Kilmere Department """ 392 | name: str 393 | head: Professor 394 | ghost: Ghost 395 | founded_in: int = 991 396 | 397 | def current_age(self): 398 | now = datetime.datetime.now().year 399 | return (now - self.founded_in) + 1 400 | 401 | 402 | if __name__ == "__main__": 403 | now = 1993 404 | 405 | keres = DarkArmyMember('Keres Fulford', 1953) 406 | print('keres: ', keres) 407 | # keres.name = 'Mortimer' # This should raise an error! 408 | 409 | 410 | 411 | 412 | 413 | -------------------------------------------------------------------------------- /code_per_day/day_2.py: -------------------------------------------------------------------------------- 1 | """ 2 | File: day_2.py 3 | Author: Anna-Lena Popkes 4 | Email: popkes@gmx.net 5 | Github: https://github.com/zotroneneis 6 | Description: all code for day 2 of my new coding habit 7 | Link to blog post with explanations: http://www.alpopkes.com/posts/2018/07/coding-challenge-day-2/ 8 | """ 9 | 10 | class CastleKilmereMember: 11 | """Creates a member of the Castle Kilmere School of Magic""" 12 | def __init__(self, name, birthyear, sex): 13 | self.name = name 14 | self.birthyear = birthyear 15 | self.sex = sex 16 | 17 | def says(self, words): 18 | return f"{self.name} says {words}" 19 | 20 | @classmethod 21 | def school_headmistress(cls) -> 'CastleKilmereMember': 22 | return cls('Miranda Mirren', 1963, 'female') 23 | 24 | 25 | class Pupil(CastleKilmereMember): 26 | """ Create a Castle Kilmere Pupil """ 27 | def __init__(self, name, birthyear, sex, start_year, pet=None): 28 | super().__init__(name, birthyear, sex) 29 | self.start_year = start_year 30 | 31 | if pet is not None: 32 | self.pet_name, self.pet_type = pet 33 | 34 | self._elms = { 35 | 'Critical Thinking': False, 36 | 'Self-Defense Against Fresh Fruit': False, 37 | 'Broomstick Flying': False, 38 | 'Magical Theory': False, 39 | 'Foreign Magical Systems': False, 40 | 'Charms': False, 41 | 'Defence Against Dark Magic': False, 42 | 'History of Magic': False, 43 | 'Potions': False, 44 | 'Transfiguration': False} 45 | 46 | @classmethod 47 | def luke(cls): 48 | return cls('Luke Bery', 2008, 'male', 2018, ('Cotton', 'owl')) 49 | 50 | @classmethod 51 | def lissy(cls): 52 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 53 | 54 | @classmethod 55 | def adrien(cls): 56 | return cls('Adrien Fulford', 2008, 'male', 2018, ('Unnamed', 'owl') ) 57 | 58 | 59 | class Professor(CastleKilmereMember): 60 | """ Creates a Castle Kilmere professor """ 61 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 62 | super().__init__(name, birthyear, sex) 63 | self.subject = subject 64 | self.department = department 65 | 66 | @classmethod 67 | def blade(cls): 68 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'Science') 69 | 70 | @classmethod 71 | def briddle(cls): 72 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Law') 73 | 74 | class Ghost(CastleKilmereMember): 75 | """ Creates a Castle Kilmere ghost """ 76 | def __init__(self, name, birthyear, sex, year_of_death): 77 | super().__init__(name, birthyear, sex) 78 | self.year_of_death = year_of_death 79 | 80 | 81 | if __name__ == "__main__": 82 | bromley = CastleKilmereMember(name='Bromley Huckabee', birthyear=1959, sex='male') 83 | lissy = Pupil(name='Lissy Spinster', birthyear=2008, sex='female', start_year=2018) 84 | headmistress = CastleKilmereMember.school_headmistress() 85 | print('headmistress: ', headmistress) 86 | 87 | blade = Professor.blade() 88 | print('blade: ', blade) 89 | lissy = Pupil.lissy() 90 | print('lissy: ', lissy) 91 | luke = Pupil.luke() 92 | print('luke: ', luke) 93 | -------------------------------------------------------------------------------- /code_per_day/day_20.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import NamedTuple 3 | from abc import ABCMeta, abstractmethod 4 | 5 | class CastleKilmereMember: 6 | """ Creates a member of the Castle Kilmere School of Magic """ 7 | 8 | def __init__(self, name: str, birthyear: int, sex: str): 9 | self.name = name 10 | self.birthyear = birthyear 11 | self.sex = sex 12 | self._traits = {} 13 | 14 | def whisper(function): 15 | def wrapper(self, *args): 16 | original_output = function(self, *args) 17 | first_part, words = original_output.split(' says: ') 18 | words = words.replace('!', '.') 19 | new_output = f"{first_part} whispers: {words}.." 20 | return new_output 21 | return wrapper 22 | 23 | @whisper 24 | def says(self, words: str) -> str: 25 | return f"{self.name} says: {words}" 26 | 27 | def __repr__(self) -> str: 28 | return (f"{self.__class__.__name__}(name='{self.name}', " 29 | f"birthyear={self.birthyear}, sex='{self.sex}')") 30 | 31 | 32 | class Pupil(CastleKilmereMember): 33 | """ Create a Castle Kilmere Pupil """ 34 | def __init__(self, name: str, birthyear: int, sex: str, start_year: int, pet: tuple = None): 35 | super().__init__(name, birthyear, sex) 36 | self.start_year = start_year 37 | self.known_spells = set() 38 | 39 | if pet is not None: 40 | self.pet_name, self.pet_type = pet 41 | 42 | self._elms = { 43 | 'Critical Thinking': False, 44 | 'Self-Defense Against Fresh Fruit': False, 45 | 'Broomstick Flying': False, 46 | 'Magical Theory': False, 47 | 'Foreign Magical Systems': False, 48 | 'Charms': False, 49 | 'Defence Against Dark Magic': False, 50 | 'History of Magic': False, 51 | 'Potions': False, 52 | 'Transfiguration': False} 53 | 54 | @classmethod 55 | def lissy(cls): 56 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 57 | 58 | if __name__ == "__main__": 59 | lissy = Pupil.lissy() 60 | print(lissy.says("Be careful Luke!")) 61 | 62 | -------------------------------------------------------------------------------- /code_per_day/day_22_to_24.py: -------------------------------------------------------------------------------- 1 | class CastleKilmereMember: 2 | """ Creates a member of the Castle Kilmere School of Magic """ 3 | def __init__(self, name: str, birthyear: int, sex: str): 4 | self.name = name 5 | self.birthyear = birthyear 6 | self.sex = sex 7 | self._traits = {} 8 | 9 | def write_letter(self, recipient, content): 10 | letter_name = f"dear_{recipient}.txt" 11 | with Letter(letter_name) as l: 12 | l.write(content) 13 | 14 | 15 | class Pupil(CastleKilmereMember): 16 | """ Create a Castle Kilmere Pupil """ 17 | def __init__(self, name: str, birthyear: int, sex: str, start_year: int, pet: tuple = None): 18 | super().__init__(name, birthyear, sex) 19 | self.start_year = start_year 20 | self.known_spells = set() 21 | 22 | if pet is not None: 23 | self.pet_name, self.pet_type = pet 24 | 25 | self._elms = { 26 | 'Critical Thinking': False, 27 | 'Self-Defense Against Fresh Fruit': False, 28 | 'Broomstick Flying': False, 29 | 'Magical Theory': False, 30 | 'Foreign Magical Systems': False, 31 | 'Charms': False, 32 | 'Defence Against Dark Magic': False, 33 | 'History of Magic': False, 34 | 'Potions': False, 35 | 'Transfiguration': False} 36 | 37 | self._friends = [] 38 | 39 | @classmethod 40 | def lissy(cls): 41 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 42 | 43 | 44 | class Letter: 45 | total_number_of_letters = 0 46 | 47 | def __init__(self, letter_name): 48 | self.letter_name = letter_name 49 | 50 | def __enter__(self): 51 | self.letter = open(self.letter_name, 'w') 52 | self.__class__.total_number_of_letters += 1 53 | return self.letter 54 | 55 | def __exit__(self, exc_type, exc_value, traceback): 56 | if self.letter: 57 | self.letter.close() 58 | 59 | 60 | if __name__ == "__main__": 61 | lissy = Pupil.lissy() 62 | letter_content = "Hi Bromley! \nCan Luke and I stop by for a tea this afternoon? \nLissy" 63 | lissy.write_letter('Bromley', letter_content) 64 | print(f"Total number of letter creates so far: {Letter.total_number_of_letters}") 65 | 66 | -------------------------------------------------------------------------------- /code_per_day/day_29_to_31.py: -------------------------------------------------------------------------------- 1 | class Potion: 2 | """ Creates a potion """ 3 | def __init__(self, ingredients): 4 | self.ingredients = ingredients 5 | self.counter = -1 6 | 7 | def __iter__(self): 8 | return self 9 | 10 | def __next__(self): 11 | self.counter += 1 12 | 13 | if self.counter == len(self.ingredients): 14 | raise StopIteration 15 | 16 | return self.ingredients[self.counter] 17 | 18 | 19 | if __name__ == "__main__": 20 | 21 | flask_of_remembrance = Potion(['raven eggshells', 'tincture of thyme', 'unicorn tears', 22 | 'dried onions', 'powdered ginger root']) 23 | 24 | vial_of_anger = Potion(['dried dragon skin', 'leeches', 'shredded elephant tusk', 25 | 'horned flies', 'earthworm juice']) 26 | 27 | for ingredient in flask_of_remembrance: 28 | print(ingredient) 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /code_per_day/day_3.py: -------------------------------------------------------------------------------- 1 | """ 2 | File: day_3.py 3 | Author: Anna-Lena Popkes 4 | Email: popkes@gmx.net 5 | Github: https://github.com/zotroneneis 6 | Description: all code for day 3 of my new coding habit 7 | Link to blog post with explanations: http://www.alpopkes.com/posts/2018/07/coding-challenge-day-3/ 8 | """ 9 | 10 | class CastleKilmereMember: 11 | """ Creates a member of the Castle Kilmere School of Magic """ 12 | def __init__(self, name:str, birthyear:int, sex:str): 13 | self.name = name 14 | self.birthyear = birthyear 15 | self.sex = sex 16 | 17 | def says(self, words): 18 | return f"{self.name} says {words}" 19 | 20 | @classmethod 21 | def school_headmistress(cls) -> 'CastleKilmereMember': 22 | return cls('Miranda Mirren', 1963, 'female') 23 | 24 | class Pupil(CastleKilmereMember): 25 | """ Create a Castle Kilmere Pupil """ 26 | def __init__(self, name, birthyear, sex, start_year, pet=None): 27 | super().__init__(name, birthyear, sex) 28 | self.start_year = start_year 29 | 30 | if pet is not None: 31 | self.pet_name, self.pet_type = pet 32 | 33 | self._elms = { 34 | 'Critical Thinking': False, 35 | 'Self-Defense Against Fresh Fruit': False, 36 | 'Broomstick Flying': False, 37 | 'Magical Theory': False, 38 | 'Foreign Magical Systems': False, 39 | 'Charms': False, 40 | 'Defence Against Dark Magic': False, 41 | 'History of Magic': False, 42 | 'Potions': False, 43 | 'Transfiguration': False} 44 | 45 | @classmethod 46 | def luke(cls): 47 | return cls('Luke Bery', 2008, 'male', 2018, ('Cotton', 'owl')) 48 | 49 | @classmethod 50 | def lissy(cls): 51 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 52 | 53 | @classmethod 54 | def adrien(cls): 55 | return cls('Adrien Fulford', 2008, 'male', 2018, ('Unnamed', 'owl') ) 56 | 57 | class Professor(CastleKilmereMember): 58 | """ Creates a Castle Kilmere professor """ 59 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 60 | super().__init__(name, birthyear, sex) 61 | self.subject = subject 62 | self.department = department 63 | 64 | @classmethod 65 | def blade(cls): 66 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'House of Ambition') 67 | 68 | @classmethod 69 | def briddle(cls): 70 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Law') 71 | 72 | 73 | class Ghost(CastleKilmereMember): 74 | """ Creates a Castle Kilmere ghost """ 75 | def __init__(self, name: str, birthyear: int, sex: str, year_of_death: int): 76 | super().__init__(name, birthyear, sex) 77 | self.year_of_death = year_of_death 78 | 79 | 80 | if __name__ == "__main__": 81 | bromley = CastleKilmereMember(name='Bromley Huckabee', birthyear=1959, sex='male') 82 | lissy = Pupil(name='Lissy Spinster', birthyear=2008, sex='female', start_year=2018) 83 | 84 | blade = Professor.blade() 85 | print('blade: ', blade) 86 | lissy = Pupil.lissy() 87 | print('lissy: ', lissy) 88 | -------------------------------------------------------------------------------- /code_per_day/day_34.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | from magical_universe import Potion 3 | 4 | # Step 1: Create the potions 5 | flask_of_remembrance = Potion(['raven eggshells', 'tincture of thyme', 'unicorn tears', 6 | 'dried onions', 'powdered ginger root']) 7 | 8 | vial_of_anger = Potion(['dried dragon skin', 'leeches', 'shredded elephant tusk', 9 | 'horned flies', 'earthworm juice', 'dried onions']) 10 | 11 | ancient_wisdom = Potion(['tincture of thyme', 'leeches', 'drakus flower', 'lavender sprig', 12 | 'earthworm juice', 'cactus juice', 'dried onions']) 13 | 14 | brew_of_lies = Potion(['horned flies', 'leeches', 'drakus flower', 'horned flies', 15 | 'unicorn tears', 'cactus juice']) 16 | 17 | # Step 2: Create list of all potions 18 | all_potions = [flask_of_remembrance, vial_of_anger, ancient_wisdom, brew_of_lies] 19 | 20 | # Step 3: Create the shopping list! 21 | shopping_list = Counter() 22 | 23 | for potion in all_potions: 24 | for ingredient in potion: 25 | shopping_list[ingredient] += 1 26 | 27 | print(f"Final shopping list: {shopping_list}") 28 | 29 | -------------------------------------------------------------------------------- /code_per_day/day_37.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import NamedTuple 3 | from abc import ABC, abstractmethod 4 | from dataclasses import dataclass 5 | 6 | class Spell(ABC): 7 | """Creates a spell""" 8 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 9 | self.name = name 10 | self.incantation = incantation 11 | self.effect = effect 12 | self.difficulty = difficulty 13 | self.min_year = min_year 14 | 15 | @abstractmethod 16 | def cast(self): 17 | pass 18 | 19 | @property 20 | @abstractmethod 21 | def defining_feature(self): 22 | pass 23 | 24 | def __repr__(self): 25 | return f"{self.__class__.__name__}(name='{self.name}', incantation='{self.incantation}', effect='{self.effect}', difficulty='{self.difficulty}', min_year={self.min_year})" 26 | 27 | 28 | class Charm(Spell): 29 | """ 30 | Creates a charm - 31 | a spell that alters the inherent qualities of an object 32 | """ 33 | def __init__(self, name: str, incantation: str, effect: str, 34 | difficulty: str = "Simple", min_year: int = 1): 35 | super().__init__(name, incantation, effect, difficulty, min_year) 36 | 37 | @property 38 | def defining_feature(self): 39 | return ("Alteration of the object's inherent qualities, " 40 | "that is, its behaviour and capabilities") 41 | 42 | def cast(self): 43 | return(f"{self.incantation}!") 44 | 45 | @classmethod 46 | def stuporus_ratiato(cls) -> 'Charm': 47 | return cls('The Stuporus Ratiato charm', 'Stuporus Ratiato', 'Makes objects fly') 48 | 49 | @classmethod 50 | def liberula(cls) -> 'Charm': 51 | return cls('The Liberula charm', 'Liberula', 'Allows a person to breath under water', 'Difficult', 5) 52 | 53 | 54 | class Transfiguration(Spell): 55 | """ 56 | Creates a transfiguration - 57 | a spell that alters the form or appearance of an object 58 | """ 59 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str, min_year: int): 60 | super().__init__(name, incantation, effect, difficulty, min_year) 61 | 62 | @property 63 | def defining_feature(self): 64 | return "Alteration of the object's form or appearance" 65 | 66 | @classmethod 67 | def alteraror_canieo(cls): 68 | return cls('The Alteraro Canieo transfiguration', 'Alteraro Canieo', 'Turns an object into a can', 'Simple', 2) 69 | 70 | def cast(self): 71 | return(f"{self.incantation}!") 72 | 73 | class Jinx(Spell): 74 | """ 75 | Creates a jinx - 76 | a spell whose effects are irritating but amusing 77 | """ 78 | def __init__(self, name: str, incantation: str, effect: str, 79 | difficulty: str, min_year: int = None): 80 | 81 | super().__init__(name, incantation, effect, difficulty, min_year) 82 | 83 | @property 84 | def defining_feature(self): 85 | return ("Minor darf magic - " 86 | "a spell whose effects are irritating but amusing, " 87 | "almost playful and of minor inconvenience to the target") 88 | 89 | @classmethod 90 | def inceptotis(cls): 91 | return cls('The Inceptotis jinx', 'Inceptotis', 'Makes a person talk baby talk', 'simple') 92 | 93 | def cast(self): 94 | return(f"{self.incantation}!") 95 | 96 | class Hex(Spell): 97 | """ 98 | Creates a hex - 99 | a spell that affects an object in a negative manner 100 | """ 101 | def __init__(self, name: str, incantation: str, effect: str, 102 | difficulty: str, min_year: int = 5): 103 | 104 | super().__init__(name, incantation, effect, difficulty, min_year) 105 | 106 | @property 107 | def defining_feature(self): 108 | return ("Medium dark magic - " 109 | "Affects an object in a negative manner. " 110 | "Major inconvenience to the target.") 111 | 112 | @classmethod 113 | def rectaro(cls): 114 | return cls('The Rectaro hex', 'Rectaro', 'Exchanges a persons arms and legs', 'difficult') 115 | 116 | def cast(self): 117 | return(f"{self.incantation}!") 118 | 119 | 120 | class Curse(Spell): 121 | """ 122 | Creates a curse - 123 | a spell that affects an object in a stflynngly negative manner 124 | """ 125 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Difficult", min_year: int = 6): 126 | 127 | super().__init__(name, incantation, effect, difficulty, min_year) 128 | 129 | @property 130 | def defining_feature(self): 131 | return ("Worst kind of dark magic - " 132 | "Intended to affect an object in a strongly negative manner.") 133 | 134 | @classmethod 135 | def fiera_satanotis(cls): 136 | return cls('Torture spell', 'Fiera Satanotis', 137 | 'Tortures a person, makes person suffer deeply', 'difficult') 138 | 139 | def cast(self): 140 | return(f"{self.incantation}!") 141 | 142 | class CounterSpell(Spell): 143 | """ 144 | Creates a counter-spell - 145 | a spell that inhibits the effect of another spell 146 | """ 147 | def __init__(self, name: str, incantation: str, effect: str, 148 | difficulty: str, min_year: int = None): 149 | 150 | super().__init__(name, incantation, effect, difficulty, min_year) 151 | 152 | @property 153 | def defining_feature(self): 154 | return ("Inhibites the effects of another spell") 155 | 156 | @classmethod 157 | def mufindo_immolim(cls): 158 | return cls('Mufindo Immolim', 'Mufindo Immolim', 159 | 'Counteracts the immobilisation spell that prevents a person from moving', 'simple') 160 | 161 | def cast(self): 162 | return(f"{self.incantation}!") 163 | 164 | class HealingSpell(Spell): 165 | """ 166 | Creates a healing-spell - 167 | a spell that improves the condition of a living object 168 | """ 169 | def __init__(self, name: str, incantation: str, effect: str, 170 | difficulty: str, min_year: int = None): 171 | 172 | super().__init__(name, incantation, effect, difficulty, min_year) 173 | 174 | @property 175 | def defining_feature(self): 176 | return "Improves the condition of a living object" 177 | 178 | @classmethod 179 | def porim_perfite(cls): 180 | return cls('Wound healing spell', 'Porim Perfite', 181 | 'Heals all kinds of wounds, even bad ones', 'difficult') 182 | 183 | def cast(self): 184 | return(f"{self.incantation}!") 185 | 186 | 187 | if __name__ == "__main__": 188 | 189 | charm = Charm.liberula() 190 | print('charm: ', charm) 191 | 192 | transfiguration = Transfiguration.alteraror_canieo() 193 | print(transfiguration.cast()) 194 | 195 | jinx = Jinx.inceptotis() 196 | print('jinx: ', jinx) 197 | 198 | hex_ = Hex.rectaro() 199 | print(hex_.cast()) 200 | 201 | curse = Curse.fiera_satanotis() 202 | print('curse: ', curse) 203 | 204 | healing_spell = HealingSpell.porim_perfite() 205 | print(healing_spell.cast()) 206 | 207 | counter_spell = CounterSpell.mufindo_immolim() 208 | print(counter_spell.cast()) 209 | -------------------------------------------------------------------------------- /code_per_day/day_4.py: -------------------------------------------------------------------------------- 1 | """ 2 | File: day_4.py 3 | Author: Anna-Lena Popkes 4 | Email: popkes@gmx.net 5 | Github: https://github.com/zotroneneis 6 | Description: all code for day 4 of my new coding habit 7 | Link to blog post with explanations: http://www.alpopkes.com/posts/2018/07/coding-challenge-day-4/ 8 | """ 9 | 10 | class CastleKilmereMember: 11 | """ Creates a member of the Castle Kilmere School of Magic """ 12 | def __init__(self, name: str, birthyear: int, sex: str): 13 | self.name = name 14 | self.birthyear = birthyear 15 | self.sex = sex 16 | 17 | def says(self, words: str) -> str: 18 | return f"{self.name} says {words}" 19 | 20 | @classmethod 21 | def school_headmistress(cls) -> 'CastleKilmereMember': 22 | return cls('Miranda Mirren', 1963, 'female') 23 | 24 | def __repr__(self) -> str: 25 | return (f"{self.__class__.__name__}(name='{self.name}', " 26 | f"birthyear={self.birthyear}, sex='{self.sex}')") 27 | 28 | class Pupil(CastleKilmereMember): 29 | """ Create a Castle Kilmere Pupil """ 30 | def __init__(self, name: str, birthyear: int, sex: str, start_year: int, pet=None): 31 | super().__init__(name, birthyear, sex) 32 | self.start_year = start_year 33 | 34 | if pet is not None: 35 | self.pet_name, self.pet_type = pet 36 | 37 | self._elms = { 38 | 'Critical Thinking': False, 39 | 'Self-Defense Against Fresh Fruit': False, 40 | 'Broomstick Flying': False, 41 | 'Magical Theory': False, 42 | 'Foreign Magical Systems': False, 43 | 'Charms': False, 44 | 'Defence Against Dark Magic': False, 45 | 'History of Magic': False, 46 | 'Potions': False, 47 | 'Transfiguration': False} 48 | 49 | @classmethod 50 | def luke(cls) -> 'Pupil': 51 | return cls('Luke Bery', 2008, 'male', 2018, ('Cotton', 'owl')) 52 | 53 | @classmethod 54 | def lissy(cls) -> 'Pupil': 55 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 56 | 57 | @classmethod 58 | def adrien(cls) -> 'Pupil': 59 | return cls('Adrien Fulford', 2008, 'male', 2018, ('Unnamed', 'owl') ) 60 | 61 | def __repr__(self) -> str: 62 | return (f"{self.__class__.__name__}(name='{self.name}', " 63 | f"birthyear={self.birthyear}, sex='{self.sex}', " 64 | f"start_year={self.start_year})") 65 | 66 | class Professor(CastleKilmereMember): 67 | """ Creates a Castle Kilmere professor """ 68 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 69 | super().__init__(name, birthyear, sex) 70 | self.subject = subject 71 | self.department = department 72 | 73 | @classmethod 74 | def blade(cls): 75 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'Science') 76 | 77 | @classmethod 78 | def briddle(cls): 79 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Law') 80 | 81 | def __repr__(self) -> str: 82 | return (f"{self.__class__.__name__}(name='{self.name}', " 83 | f"birthyear={self.birthyear}, sex='{self.sex}', " 84 | f"subject='{self.subject}', department='{self.department}')") 85 | 86 | class Ghost(CastleKilmereMember): 87 | """ Creates a Castle Kilmere ghost """ 88 | def __init__(self, name: str, birthyear: int, sex: str, year_of_death: int): 89 | super().__init__(name, birthyear, sex) 90 | self.year_of_death = year_of_death 91 | 92 | def __repr__(self) -> str: 93 | return (f"{self.__class__.__name__}(name='{self.name}', " 94 | f"birthyear={self.birthyear}, sex='{self.sex}', " 95 | f"year_of_death={self.year_of_death})") 96 | 97 | if __name__ == "__main__": 98 | bromley = CastleKilmereMember(name='Bromley Huckabee', birthyear=1959, sex='male') 99 | print('bromley: ', bromley) 100 | lissy = Pupil(name='Lissy Spinster', birthyear=2008, sex='female', start_year=2018) 101 | print('lissy: ', lissy) 102 | blade = Professor.blade() 103 | print('blade: ', blade) 104 | -------------------------------------------------------------------------------- /code_per_day/day_43_to_45.py: -------------------------------------------------------------------------------- 1 | import error 2 | import datetime 3 | 4 | class CastleKilmereMember: 5 | """ Creates a member of the Castle Kilmere School of Magic """ 6 | def __init__(self, name: str, birthyear: int, sex: str): 7 | self.name = name 8 | self.birthyear = birthyear 9 | if type(birthyear) is not int: 10 | raise error.InvalidBirthyearError("The birthyear is not a valid integer. " \ 11 | "Try something like 1991") 12 | 13 | self.sex = sex 14 | self._traits = {} 15 | 16 | def add_trait(self, trait: str, value=True): 17 | self._traits[trait] = value 18 | 19 | def exhibits_trait(self, trait: str) -> bool: 20 | try: 21 | value = self._traits[trait] 22 | return value 23 | except KeyError as e: 24 | print(f"{self.name} does not have a character trait with the name {e}") 25 | return False 26 | 27 | if __name__ == "__main__": 28 | 29 | # This laine raises an "InvalidBirthyearError" 30 | bromley = CastleKilmereMember('Bromley Huckabee', 1959, 'male') 31 | print('bromley: ', bromley) 32 | 33 | # This line raises an "InvalidBirthyearError" 34 | bromley = CastleKilmereMember('Bromley Huckabee', '1959', 'male') 35 | 36 | bromley.add_trait('tidy-minded') 37 | bromley.add_trait('kind') 38 | 39 | bromley.exhibits_trait('kind') 40 | 41 | # This line raises an "TraitDoesNotExistError" 42 | bromley.exhibits_trait('mean') 43 | 44 | -------------------------------------------------------------------------------- /code_per_day/day_46.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | class CastleKilmereMember: 4 | """ Creates a member of the Castle Kilmere School of Magic """ 5 | def __init__(self, name: str, birthyear: int, sex: str): 6 | self.name = name 7 | self.birthyear = birthyear 8 | self.sex = sex 9 | self._traits = {} 10 | 11 | def whisper(function): 12 | @functools.wraps(function) 13 | def wrapper(self, *args): 14 | ''' Whispering decorator ''' 15 | original_output = function(self, *args) 16 | first_part, words = original_output.split(' says: ') 17 | words = words.replace('!', '.') 18 | new_output = f"{first_part} whispers: {words}.." 19 | return new_output 20 | return wrapper 21 | 22 | @whisper 23 | def says(self, words): 24 | '''Allows a Castle Kilmere Member to talk''' 25 | return f"{self.name} says: {words}" 26 | 27 | 28 | if __name__ == "__main__": 29 | bromley = CastleKilmereMember('Bromley Huckabee', 1959, 'male') 30 | 31 | print(bromley.says.__name__) 32 | print(bromley.says.__doc__) 33 | -------------------------------------------------------------------------------- /code_per_day/day_47_to_48.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | class CastleKilmereMember: 4 | """ Creates a member of the Castle Kilmere School of Magic """ 5 | def __init__(self, name: str, birthyear: int, sex: str): 6 | self.name = name 7 | self.birthyear = birthyear 8 | self.sex = sex 9 | self._traits = defaultdict(lambda: False) 10 | 11 | def add_trait(self, trait, value=True): 12 | self._traits[trait] = value 13 | 14 | def exhibits_trait(self, trait: str) -> bool: 15 | value = self._traits[trait] 16 | return value 17 | 18 | def print_traits(self): 19 | true_traits = [trait for trait, value in self._traits.items() if value] 20 | false_traits = [trait for trait, value in self._traits.items() if not value] 21 | 22 | if true_traits: 23 | print(f"{self.name} is {', '.join(true_traits)}") 24 | if false_traits: 25 | print(f"{self.name} is not {', '.join(false_traits)}") 26 | if (not true_traits and not false_traits): 27 | print(f"{self.name} does not have traits yet") 28 | 29 | if __name__ == "__main__": 30 | 31 | bromley = CastleKilmereMember('Bromley Huckabee', 1959, 'male') 32 | 33 | bromley.add_trait('tidy-minded') 34 | bromley.add_trait('kind') 35 | 36 | bromley.exhibits_trait('kind') 37 | bromley.exhibits_trait('mean') 38 | 39 | bromley.print_traits() 40 | 41 | -------------------------------------------------------------------------------- /code_per_day/day_49_to_50.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('../') 3 | 4 | import yaml 5 | from magical_universe import CastleKilmereMember, Pupil 6 | 7 | if __name__ == "__main__": 8 | 9 | with open('config.yaml', 'r') as c: 10 | config = yaml.load(c) 11 | 12 | bromley = CastleKilmereMember(**config['bromley']) 13 | print('bromley: ', bromley) 14 | 15 | lissy = Pupil(**config['lissy']) 16 | print('lissy: ', lissy) 17 | 18 | luke = Pupil(**config['luke']) 19 | print('luke: ', luke) 20 | -------------------------------------------------------------------------------- /code_per_day/day_6.py: -------------------------------------------------------------------------------- 1 | """ 2 | File: day_6.py 3 | Author: Anna-Lena Popkes 4 | Email: popkes@gmx.net 5 | Github: https://github.com/zotroneneis 6 | Description: all code for day 6 of my new coding habit 7 | Link to blog post with explanations: http://www.alpopkes.com/posts/2018/07/coding-challenge-day-6/ 8 | """ 9 | 10 | import datetime 11 | 12 | class CastleKilmereMember: 13 | """ Creates a member of the Castle Kilmere School of Magic """ 14 | def __init__(self, name: str, birthyear: int, sex: str): 15 | self.name = name 16 | self.birthyear = birthyear 17 | self.sex = sex 18 | 19 | def says(self, words: str) -> str: 20 | return f"{self.name} says {words}" 21 | 22 | @property 23 | def age(self) -> int: 24 | now = datetime.datetime.now().year 25 | return now - self.birthyear 26 | 27 | @classmethod 28 | def school_headmistress(cls) -> 'CastleKilmereMember': 29 | return cls('Miranda Mirren', 1963, 'female') 30 | 31 | def __repr__(self) -> str: 32 | return (f"{self.__class__.__name__}(name='{self.name}', " 33 | f"birthyear={self.birthyear}, sex='{self.sex}')") 34 | 35 | 36 | class Professor(CastleKilmereMember): 37 | """ Creates a Castle Kilmere professor """ 38 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 39 | super().__init__(name, birthyear, sex) 40 | self.subject = subject 41 | self.department = department 42 | 43 | @classmethod 44 | def blade(cls) -> 'Professor': 45 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'Science') 46 | 47 | @classmethod 48 | def briddle(cls) -> 'Professor': 49 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Law') 50 | 51 | def __repr__(self) -> str: 52 | return (f"{self.__class__.__name__}(name='{self.name}', " 53 | f"birthyear={self.birthyear}, sex='{self.sex}', " 54 | f"subject='{self.subject}', department='{self.department}')") 55 | 56 | 57 | class Ghost(CastleKilmereMember): 58 | """ Creates a Castle Kilmere ghost """ 59 | def __init__(self, name: str, birthyear: int, sex: str, year_of_death: int): 60 | super().__init__(name, birthyear, sex) 61 | self.year_of_death = year_of_death 62 | 63 | @property 64 | def age(self) -> int: 65 | now = datetime.datetime.now().year 66 | return now - self.birthyear 67 | 68 | def __repr__(self) -> str: 69 | return (f"{self.__class__.__name__}(name='{self.name}', " 70 | f"birthyear={self.birthyear}, sex='{self.sex}', " 71 | f"year_of_death={self.year_of_death})") 72 | 73 | 74 | class Pupil(CastleKilmereMember): 75 | """ Create a Castle Kilmere Pupil """ 76 | def __init__(self, name: str, birthyear: int, sex: str, start_year: int, pet: tuple = None): 77 | super().__init__(name, birthyear, sex) 78 | self.start_year = start_year 79 | 80 | if pet is not None: 81 | self.pet_name, self.pet_type = pet 82 | 83 | self._elms = { 84 | 'Critical Thinking': False, 85 | 'Self-Defense Against Fresh Fruit': False, 86 | 'Broomstick Flying': False, 87 | 'Magical Theory': False, 88 | 'Foreign Magical Systems': False, 89 | 'Charms': False, 90 | 'Defence Against Dark Magic': False, 91 | 'History of Magic': False, 92 | 'Potions': False, 93 | 'Transfiguration': False} 94 | 95 | @classmethod 96 | def luke(cls): 97 | return cls('Luke Bery', 2008, 'male', 2018, ('Cotton', 'owl')) 98 | 99 | @classmethod 100 | def lissy(cls): 101 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 102 | 103 | @classmethod 104 | def adrien(cls): 105 | return cls('Adrien Fulford', 2008, 'male', 2018, ('Twiggles', 'owl') ) 106 | 107 | @property 108 | def current_year(self): 109 | now = datetime.datetime.now().year 110 | return (now - self.start_year) + 1 111 | 112 | @property 113 | def elms(self): 114 | return self._elms 115 | 116 | @elms.setter 117 | def elms(self, subject_and_grade): 118 | try: 119 | subject, grade = subject_and_grade 120 | except ValueError: 121 | raise ValueError("Pass and iterable with two items: subject and grade") 122 | 123 | passed = self.passed(grade) 124 | 125 | if passed: 126 | self._elms[subject] = True 127 | else: 128 | print('The exam was not passed so no ELM was awarded!') 129 | 130 | @elms.deleter 131 | def elms(self): 132 | print("Caution, you are deleting this students' ELM's! " 133 | "You should only do that if she/he dropped out of school without passing any exam!") 134 | del self._elms 135 | 136 | 137 | @staticmethod 138 | def passed(grade) -> bool: 139 | """ Given a grade, determine if an exam was passed. """ 140 | grades = { 141 | 'E': True, 142 | 'Excellent': True, 143 | 'G': True, 144 | 'Good': True, 145 | 'A': True, 146 | 'Acceptable': True, 147 | 'P': False, 148 | 'Poor': False, 149 | 'H': False, 150 | 'Horrible': False, 151 | } 152 | 153 | return grades.get(grade, False) 154 | 155 | def __repr__(self) -> str: 156 | return (f"{self.__class__.__name__}(name='{self.name}', " 157 | f"birthyear={self.birthyear}, sex='{self.sex}', " 158 | f"start_year={self.start_year})") 159 | 160 | if __name__ == "__main__": 161 | bromley = CastleKilmereMember(name='Bromley Huckabee', birthyear=1959, sex='male') 162 | lissy = Pupil(name='Lissy Spinster', birthyear=2008, sex='female', start_year=2018) 163 | print('Lissy: ', lissy) 164 | print('Current age of Lissy: ', lissy.age) 165 | print("Lissy's elms: ", lissy.elms) 166 | lissy.elms = ('Potions', 'P') 167 | print("Lissy's elms: ", lissy.elms) 168 | 169 | 170 | -------------------------------------------------------------------------------- /code_per_day/day_8.py: -------------------------------------------------------------------------------- 1 | """ 2 | File: day_8.py 3 | Author: Anna-Lena Popkes 4 | Email: popkes@gmx.net 5 | Github: https://github.com/zotroneneis 6 | Description: all code for day 8 of my new coding habit 7 | Link to blog post with explanations: http://www.alpopkes.com/posts/2018/07/coding-challenge-day-8/ 8 | """ 9 | import datetime 10 | from abc import ABC, abstractmethod 11 | 12 | class CastleKilmereMember: 13 | """ Creates a member of the Castle Kilmere School of Magic """ 14 | def __init__(self, name: str, birthyear: int, sex: str): 15 | self.name = name 16 | self.birthyear = birthyear 17 | self.sex = sex 18 | 19 | def says(self, words: str) -> str: 20 | return f"{self.name} says {words}" 21 | 22 | @property 23 | def age(self) -> int: 24 | now = datetime.datetime.now().year 25 | return now - self.birthyear 26 | 27 | @classmethod 28 | def school_headmistress(cls) -> 'CastleKilmereMember': 29 | return cls('Miranda Mirren', 1963, 'female') 30 | 31 | def __repr__(self) -> str: 32 | return (f"{self.__class__.__name__}(name='{self.name}', " 33 | f"birthyear={self.birthyear}, sex='{self.sex}')") 34 | 35 | 36 | class Professor(CastleKilmereMember): 37 | """ Creates a Castle Kilmere professor """ 38 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 39 | super().__init__(name, birthyear, sex) 40 | self.subject = subject 41 | self.department = department 42 | 43 | @classmethod 44 | def blade(cls) -> 'Professor': 45 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'Science') 46 | 47 | @classmethod 48 | def briddle(cls) -> 'Professor': 49 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Law') 50 | 51 | 52 | def __repr__(self) -> str: 53 | return (f"{self.__class__.__name__}(name='{self.name}', " 54 | f"birthyear={self.birthyear}, sex='{self.sex}', " 55 | f"subject='{self.subject}', department='{self.department}')") 56 | 57 | 58 | class Ghost(CastleKilmereMember): 59 | """ Creates a Castle Kilmere ghost """ 60 | def __init__(self, name: str, birthyear: int, sex: str, year_of_death: int): 61 | super().__init__(name, birthyear, sex) 62 | self.year_of_death = year_of_death 63 | 64 | @property 65 | def age(self): 66 | now = datetime.datetime.now().year 67 | return now - self.birthyear 68 | 69 | def __repr__(self) -> str: 70 | return (f"{self.__class__.__name__}(name='{self.name}', " 71 | f"birthyear={self.birthyear}, sex='{self.sex}', " 72 | f"year_of_death={self.year_of_death})") 73 | 74 | @classmethod 75 | def mocking_knight(cls): 76 | return cls('The Mocking Knight', 1401, 'male', 1492) 77 | 78 | 79 | class Pupil(CastleKilmereMember): 80 | """ Create a Castle Kilmere Pupil """ 81 | def __init__(self, name: str, birthyear: int, sex: str, start_year: int, pet: tuple = None): 82 | super().__init__(name, birthyear, sex) 83 | self.start_year = start_year 84 | 85 | if pet is not None: 86 | self.pet_name, self.pet_type = pet 87 | 88 | self._elms = { 89 | 'Critical Thinking': False, 90 | 'Self-Defense Against Fresh Fruit': False, 91 | 'Broomstick Flying': False, 92 | 'Magical Theory': False, 93 | 'Foreign Magical Systems': False, 94 | 'Charms': False, 95 | 'Defence Against Dark Magic': False, 96 | 'History of Magic': False, 97 | 'Potions': False, 98 | 'Transfiguration': False} 99 | 100 | self._friends = [] 101 | 102 | @classmethod 103 | def luke(cls) -> 'Pupil': 104 | return cls('Luke Bery', 2008, 'male', 2018, ('Cotton', 'owl')) 105 | 106 | @classmethod 107 | def lissy(cls) -> 'Pupil': 108 | return cls('Lissy Spinster', 2008, 'female', 2018, ('Ramses', 'cat')) 109 | 110 | @classmethod 111 | def adrien(cls) -> 'Pupil': 112 | return cls('Adrien Fulford', 2008, 'male', 2018, ('Unnamed', 'owl') ) 113 | 114 | @property 115 | def current_year(self) -> int: 116 | now = datetime.datetime.now().year 117 | return now - self.start_year 118 | 119 | @property 120 | def elms(self): 121 | return self._elms 122 | 123 | @property 124 | def friends(self): 125 | return f"{self.name}'s current friends are: {[person.name for person in self._friends]}" 126 | 127 | @elms.setter 128 | def elms(self, subject_and_grade): 129 | 130 | try: 131 | subject, grade = subject_and_grade 132 | except ValueError: 133 | raise ValueError("Pass and iterable with two items: subject and grade") 134 | 135 | passed = self.passed(grade) 136 | 137 | if passed: 138 | self._elms[subject] = True 139 | else: 140 | print('The exam was not passed so no ELM was awarded!') 141 | 142 | @elms.deleter 143 | def elms(self): 144 | print("Caution, you are deleting this students' ELM's! " 145 | "You should only do that if she/he dropped out of school without passing any exam!") 146 | del self._elms 147 | 148 | 149 | @staticmethod 150 | def passed(grade): 151 | """ 152 | Given a grade, determine if an exam was passed. 153 | """ 154 | grades = { 155 | 'E': True, 156 | 'Excellent': True, 157 | 'G': True, 158 | 'Good': True, 159 | 'A': True, 160 | 'Acceptable': True, 161 | 'P': False, 162 | 'Poor': False, 163 | 'H': False, 164 | 'Horrible': False, 165 | } 166 | 167 | return grades.get(grade, False) 168 | 169 | def befriend(self, person): 170 | """Adds another person to your list of friends""" 171 | self._friends.append(person) 172 | print(f"{person.name} is now your friend!") 173 | 174 | def __repr__(self) -> str: 175 | return (f"{self.__class__.__name__}(name='{self.name}', " 176 | f"birthyear={self.birthyear}, sex='{self.sex}', " 177 | f"start_year={self.start_year})") 178 | 179 | class Spell(ABC): 180 | def __init__(self, name: str, incantation: str, effect: str): 181 | self.name = name 182 | self.incantation = incantation 183 | self.effect = effect 184 | 185 | @abstractmethod 186 | def cast(self): 187 | pass 188 | 189 | @property 190 | @abstractmethod 191 | def defining_feature(self): 192 | pass 193 | 194 | 195 | class Charm(Spell): 196 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 197 | super().__init__(name, incantation, effect) 198 | self.difficulty = difficulty 199 | self.min_year = min_year 200 | 201 | @property 202 | def defining_feature(self) -> str: 203 | return ("Alteration of the object's inherent qualities, that is, its behaviour and capabilities") 204 | 205 | def cast(self): 206 | print(f"{self.incantation}!") 207 | 208 | @classmethod 209 | def stuporus_ratiato(cls): 210 | return cls('The Stuporus Ratiato spell', 'Stuporus Ratiato', 'Makes objects fly') 211 | 212 | def __repr__(self): 213 | return f"{self.__class__.__name__}({self.incantation}, {self.difficulty}, {self.effect})" 214 | 215 | if __name__ == "__main__": 216 | bromley = CastleKilmereMember(name='Bromley Huckabee', birthyear=1959, sex='male') 217 | lissy = Pupil(name='Lissy Spinster', birthyear=2008, sex='female', start_year=2018) 218 | luke = Pupil.luke() 219 | adrien = Pupil.adrien() 220 | 221 | lissy.befriend(bromley) 222 | lissy.befriend(luke) 223 | lissy.befriend(adrien) 224 | print(lissy.friends) 225 | print() 226 | 227 | stuporus = Charm.stuporus_ratiato() 228 | stuporus.cast() 229 | 230 | 231 | 232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /code_per_day/day_9.py: -------------------------------------------------------------------------------- 1 | """ 2 | File: day_1.py 3 | Author: Anna-Lena Popkes 4 | Email: popkes@gmx.net 5 | Github: https://github.com/zotflynneneis 6 | Description: all code for day 1 of my new coding habit 7 | Link to blog post with explanations: http://www.alpopkes.com/posts/2018/07/coding-challenge-day-9/ 8 | """ 9 | import datetime 10 | 11 | class CastleKilmereMember: 12 | """ Creates a member of the Castle Kilmere School of Magic """ 13 | 14 | def __init__(self, name: str, birthyear: int, sex: str): 15 | self.name = name 16 | self.birthyear = birthyear 17 | self.sex = sex 18 | self._traits = {} 19 | 20 | def says(self, words: str) -> str: 21 | return f"{self.name} says {words}" 22 | 23 | def add_trait(self, trait: str, value=True): 24 | self._traits[trait] = value 25 | 26 | def print_traits(self): 27 | true_traits = [trait for trait, value in self._traits.items() if value] 28 | false_traits = [trait for trait, value in self._traits.items() if not value] 29 | 30 | if true_traits: 31 | print(f"{self.name} is {', '.join(true_traits)}") 32 | if false_traits: 33 | print(f"{self.name} is not {', '.join(false_traits)}") 34 | if (not true_traits and not false_traits): 35 | print(f"{self.name} does not have traits yet") 36 | 37 | def exhibits_trait(self, trait: str) -> bool: 38 | try: 39 | value = self._traits[trait] 40 | return value 41 | except KeyError as e: 42 | print(f"{self.name} does not have a character trait with the name {e}") 43 | return False 44 | 45 | @property 46 | def age(self) -> int: 47 | now = datetime.datetime.now().year 48 | return now - self.birthyear 49 | 50 | @classmethod 51 | def school_headmistress(cls) -> 'CastleKilmereMember': 52 | return cls('Miranda Mirren', 1963, 'female') 53 | 54 | def __repr__(self) -> str: 55 | return (f"{self.__class__.__name__}(name='{self.name}', " 56 | f"birthyear={self.birthyear}, sex='{self.sex}')") 57 | 58 | 59 | if __name__ == "__main__": 60 | bromley = CastleKilmereMember(name='Bromley Huckabee', birthyear=1959, sex='male') 61 | bromley.add_trait("kind") 62 | bromley.add_trait("tidy-minded") 63 | bromley.add_trait("impatient", value=False) 64 | 65 | bromley.print_traits() 66 | print() 67 | 68 | bromley.exhibits_trait("kind") 69 | bromley.exhibits_trait("funny") 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /code_per_day/error.py: -------------------------------------------------------------------------------- 1 | class BaseError(Exception): 2 | """Base class for exceptions in this module""" 3 | pass 4 | 5 | class InvalidBirthyearError(BaseError): 6 | """Raised when the birthyear argument is not a valid integer like 1991""" 7 | pass 8 | 9 | class TraitDoesNotExistError(BaseError): 10 | pass 11 | -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | bromley: 2 | name: 'Bromley Huckabee' 3 | birthyear: 1959 4 | sex: 'male' 5 | 6 | luke: 7 | name: 'Luke Bery' 8 | birthyear: 2008 9 | sex: 'male' 10 | start_year: 2020 11 | pet: ['Cotton', 'owl'] 12 | 13 | lissy: 14 | name: 'Lissy Spinster' 15 | birthyear: 2008 16 | sex: 'female' 17 | start_year: 2020 18 | pet: ['Ramses', 'cat'] 19 | 20 | -------------------------------------------------------------------------------- /magical_universe.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import functools 3 | 4 | from typing import NamedTuple 5 | from abc import ABC, abstractmethod 6 | from dataclasses import dataclass 7 | from collections import defaultdict 8 | 9 | class CastleKilmereMember: 10 | """Creates a member of the Castle Kilmere School of Magic""" 11 | def __init__(self, name: str, birthyear: int, sex: str): 12 | self.name = name 13 | self.birthyear = birthyear 14 | self.sex = sex 15 | self._traits = defaultdict(lambda: False) 16 | 17 | def write_letter(self, recipient, content): 18 | letter_name = f"dear_{recipient}.txt" 19 | with Letter(letter_name) as l: 20 | l.write(content) 21 | 22 | def whisper(function): 23 | @functools.wraps(function) 24 | def wrapper(self, *args): 25 | ''' Whispering decorator ''' 26 | original_output = function(self, *args) 27 | first_part, words = original_output.split(' says: ') 28 | words = words.replace('!', '.') 29 | new_output = f"{first_part} whispers: {words}.." 30 | return new_output 31 | return wrapper 32 | 33 | def says(self, words: str) -> str: 34 | '''Allows a Castle Kilmere Member to talk''' 35 | return f"{self.name} says: {words}" 36 | 37 | def add_trait(self, trait, value=True): 38 | self._traits[trait] = value 39 | 40 | def print_traits(self): 41 | true_traits = [trait for trait, value in self._traits.items() if value] 42 | false_traits = [trait for trait, value in self._traits.items() if not value] 43 | 44 | if true_traits: 45 | print(f"{self.name} is {', '.join(true_traits)}.") 46 | if false_traits: 47 | print(f"{self.name} is not {', '.join(false_traits)}.") 48 | if (not true_traits and not false_traits): 49 | print(f"{self.name} does not have traits yet.") 50 | 51 | def exhibits_trait(self, trait: str) -> bool: 52 | value = self._traits[trait] 53 | return value 54 | 55 | @property 56 | def age(self) -> int: 57 | now = datetime.datetime.now().year 58 | return now - self.birthyear 59 | 60 | @classmethod 61 | def school_headmistress(cls) -> 'CastleKilmereMember': 62 | return cls('Miranda Mirren', 1963, 'female') 63 | 64 | def __repr__(self) -> str: 65 | return (f"{self.__class__.__name__}(name='{self.name}', " 66 | f"birthyear={self.birthyear}, sex='{self.sex}')") 67 | 68 | class Professor(CastleKilmereMember): 69 | """ Creates a Castle Kilmere professor """ 70 | def __init__(self, name: str, birthyear: int, sex: str, subject: str, department: str = None): 71 | super().__init__(name, birthyear, sex) 72 | self.subject = subject 73 | self.department = department 74 | 75 | @classmethod 76 | def blade(cls): 77 | return cls('Blade Bardock', 1988, 'male', 'Potions', 'Department of Science') 78 | 79 | @classmethod 80 | def briddle(cls): 81 | return cls('Birdie Briddle', 1931, 'female', 'Foreign Magical Systems', 'Department of Law') 82 | 83 | @classmethod 84 | def radford(cls): 85 | return cls('Rupert Radford', 1958, 'male', 'Illusions 101', 'Department of Creativity and Arts') 86 | 87 | @classmethod 88 | def giddings(cls): 89 | return cls('Gabriel Giddings', 1974, 'male', 'Broomstick Making', 'Department of Engineering') 90 | 91 | def __repr__(self) -> str: 92 | return (f"{self.__class__.__name__}(name='{self.name}', birthyear={self.birthyear}, sex='{self.sex}', subject='{self.subject}', department='{self.department}')") 93 | 94 | 95 | class Ghost(CastleKilmereMember): 96 | """ Creates a Castle Kilmere ghost """ 97 | def __init__(self, name: str, birthyear: int, sex: str, year_of_death: int): 98 | super().__init__(name, birthyear, sex) 99 | 100 | self.year_of_death = year_of_death 101 | 102 | @property 103 | def age(self) -> int: 104 | now = datetime.datetime.now().year 105 | return now - self.birthyear 106 | 107 | def __repr__(self) -> str: 108 | return (f"{self.__class__.__name__}(name='{self.name}', " 109 | f"birthyear={self.birthyear}, sex='{self.sex}', " 110 | f"year_of_death={self.year_of_death})") 111 | 112 | @classmethod 113 | def mocking_knight(cls): 114 | return cls('The Mocking Knight', 1401, 'male', 1492) 115 | 116 | @classmethod 117 | def gray_groom(cls): 118 | return cls('The Gray Groom', 1000, 'male', 1050) 119 | 120 | @classmethod 121 | def scary_scoundrel(cls): 122 | return cls('Scary Scoundrel', 983, 'male', 1010) 123 | 124 | @classmethod 125 | def old_lady(cls): 126 | return cls('The Old Lady', 983, 'male', 996) 127 | 128 | @classmethod 129 | def boneless_barde(cls): 130 | return cls("The Boneless Bard", 1211, 'male', 1288) 131 | 132 | 133 | class Pupil(CastleKilmereMember): 134 | """ Create a Castle Kilmere Pupil """ 135 | 136 | def __init__(self, name: str, birthyear: int, sex: str, start_year: int, pet: tuple = None): 137 | super().__init__(name, birthyear, sex) 138 | self.start_year = start_year 139 | self.known_spells = set() 140 | 141 | if pet is not None: 142 | self.pet_name, self.pet_type = pet 143 | 144 | self._elms = { 145 | 'Critical Thinking': False, 146 | 'Self-Defense Against Fresh Fruit': False, 147 | 'Broomstick Flying': False, 148 | 'Magical Theory': False, 149 | 'Foreign Magical Systems': False, 150 | 'Charms': False, 151 | 'Defence Against Dark Magic': False, 152 | 'History of Magic': False, 153 | 'Potions': False, 154 | 'Transfiguration': False} 155 | 156 | self._friends = [] 157 | 158 | @classmethod 159 | def luke(cls): 160 | return cls('Luke Bery', 2008, 'male', 2020, ('Cotton', 'owl')) 161 | 162 | @classmethod 163 | def lissy(cls): 164 | return cls('Lissy Spinster', 2008, 'female', 2020, ('Ramses', 'cat')) 165 | 166 | @classmethod 167 | def adrien(cls): 168 | return cls('Adrien Fulford', 2008, 'male', 2020, ('Unnamed', 'owl') ) 169 | 170 | @property 171 | def current_year(self) -> int: 172 | now = datetime.datetime.now().year 173 | return (now - self.start_year) + 1 174 | 175 | @property 176 | def elms(self): 177 | return self._elms 178 | 179 | @property 180 | def friends(self): 181 | return f"{self.name}'s current friends are: {[person.name for person in self._friends]}" 182 | 183 | @elms.setter 184 | def elms(self, subject_and_grade): 185 | try: 186 | subject, grade = subject_and_grade 187 | except ValueError: 188 | raise ValueError("Pass and iterable with two items: subject and grade") 189 | 190 | passed = self.passed(grade) 191 | 192 | if passed: 193 | self._elms[subject] = True 194 | else: 195 | print('The exam was not passed so no ELM was awarded!') 196 | 197 | @elms.deleter 198 | def elms(self): 199 | print("Caution, you are deleting this students' ELM's! " 200 | "You should only do that if she/he dropped out of school without passing any exam!") 201 | del self._elms 202 | 203 | 204 | @staticmethod 205 | def passed(grade): 206 | """ Given a grade, determine if an exam was passed. """ 207 | grades = { 208 | 'E': True, 209 | 'Excellent': True, 210 | 'G': True, 211 | 'Good': True, 212 | 'A': True, 213 | 'Acceptable': True, 214 | 'P': False, 215 | 'Poor': False, 216 | 'H': False, 217 | 'Horrible': False, 218 | } 219 | 220 | return grades.get(grade, False) 221 | 222 | def befriend(self, person): 223 | """Adds another person to your list of friends""" 224 | self._friends.append(person) 225 | print(f"{person.name} is now your friend!") 226 | 227 | def __repr__(self) -> str: 228 | return (f"{self.__class__.__name__}(name='{self.name}', " 229 | f"birthyear={self.birthyear}, sex='{self.sex}', " 230 | f"start_year={self.start_year})") 231 | 232 | def learn_spell(self, spell: 'Spell'): 233 | """ Allows a pupil to learn a spell, given that he/she is old enough """ 234 | if spell.min_year is not None: 235 | if self.current_year >= spell.min_year: 236 | print(f"{self.name} now knows '{spell.name}'") 237 | self.known_spells.add(spell) 238 | 239 | elif self.exhibits_trait('highly intelligent'): 240 | print(f"{self.name} now knows '{spell.name}'") 241 | self.known_spells.add(spell) 242 | 243 | elif self.current_year < spell.min_year: 244 | print(f"{self.name} is too young to study this spell!") 245 | 246 | elif spell.__class__.__name__ in ['Hex', 'Curse']: 247 | # Only evil pupils would study hexes and curses 248 | if self.exhibits_trait('evil'): 249 | print(f"{self.name} now knows '{spell.name}'") 250 | self.known_spells.add(spell) 251 | 252 | else: 253 | print(f"How dare you study a hex or curse?!") 254 | 255 | def cast_spell(self, spell: 'Spell'): 256 | """ Allows a pupil to cast a spell """ 257 | if spell.__class__.__name__ == 'Curse': 258 | print("This is dark magic - stay away from performing curses!") 259 | 260 | elif spell.__class__.__name__ == 'Hex': 261 | if not self.exhibits_trait('evil'): 262 | print(f"You shouldn't cast a hex, that's mean!") 263 | 264 | elif spell in self.known_spells: 265 | return f"{self.name}: {spell.incantation}!" 266 | 267 | elif spell.name not in self.known_spells: 268 | print(f"You can't cast the {spell.name} spell correctly " 269 | f" - you have to study it first! ") 270 | 271 | 272 | class Spell(ABC): 273 | """Creates a spell""" 274 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 275 | self.name = name 276 | self.incantation = incantation 277 | self.effect = effect 278 | self.difficulty = difficulty 279 | self.min_year = min_year 280 | 281 | @abstractmethod 282 | def cast(self): 283 | pass 284 | 285 | @property 286 | @abstractmethod 287 | def defining_feature(self): 288 | pass 289 | 290 | def __repr__(self): 291 | return f"{self.__class__.__name__}(name='{self.name}', incantation='{self.incantation}', effect='{self.effect}', difficulty='{self.difficulty}', min_year={self.min_year})" 292 | 293 | 294 | class Charm(Spell): 295 | """Creates a charm - a spell that alters the inherent qualities of an object""" 296 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 297 | super().__init__(name, incantation, effect, difficulty, min_year) 298 | 299 | @property 300 | def defining_feature(self) -> str: 301 | return ("Alteration of the object's inherent qualities, " 302 | "that is, its behaviour and capabilities") 303 | 304 | def cast(self) -> str: 305 | return(f"{self.incantation}!") 306 | 307 | @classmethod 308 | def stuporus_ratiato(cls) -> 'Charm': 309 | return cls('The Stuporus Ratiato charm', 'Stuporus Ratiato', 'Makes objects fly') 310 | 311 | @classmethod 312 | def liberula(cls) -> 'Charm': 313 | return cls('The Liberula charm', 'Liberula', 'Allows a person to breath under water', 'Difficult', 5) 314 | 315 | 316 | class Transfiguration(Spell): 317 | """Creates a transfiguration - a spell that alters the form or appearance of an object""" 318 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 319 | super().__init__(name, incantation, effect, difficulty, min_year) 320 | 321 | @property 322 | def defining_feature(self) -> str: 323 | return "Alteration of the object's form or appearance" 324 | 325 | @classmethod 326 | def alteraror_canieo(cls) -> 'Transfiguration': 327 | return cls('The Alteraro Canieo transfiguration', 'Alteraro Canieo', 'Turns an object into a can', 'Simple', 2) 328 | 329 | def cast(self) -> str: 330 | return(f"{self.incantation}!") 331 | 332 | class Jinx(Spell): 333 | """Creates a jinx - a spell whose effects are irritating but amusing""" 334 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 335 | super().__init__(name, incantation, effect, difficulty, min_year) 336 | 337 | @property 338 | def defining_feature(self) -> str: 339 | return ("Minor darf magic - " 340 | "a spell whose effects are irritating but amusing, " 341 | "almost playful and of minor inconvenience to the target") 342 | 343 | @classmethod 344 | def inceptotis(cls) -> 'Jinx': 345 | return cls('The Inceptotis jinx', 'Inceptotis', 'Makes a person talk baby talk', 'Simple') 346 | 347 | def cast(self) -> str: 348 | return(f"{self.incantation}!") 349 | 350 | class Hex(Spell): 351 | """Creates a hex - a spell that affects an object in a negative manner""" 352 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Medium", min_year: int = None): 353 | super().__init__(name, incantation, effect, difficulty, min_year) 354 | 355 | @property 356 | def defining_feature(self) -> str: 357 | return ("Medium dark magic - " 358 | "Affects an object in a negative manner. " 359 | "Major inconvenience to the target.") 360 | 361 | @classmethod 362 | def rectaro(cls) -> 'Hex': 363 | return cls('The Rectaro hex', 'Rectaro', 'Exchanges a persons arms and legs', 'Difficult') 364 | 365 | def cast(self) -> str: 366 | return(f"{self.incantation}!") 367 | 368 | class Curse(Spell): 369 | """Creates a curse - a spell that affects an object in a stflynngly negative manner""" 370 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Difficult", min_year: int = 6): 371 | super().__init__(name, incantation, effect, difficulty, min_year) 372 | 373 | @property 374 | def defining_feature(self) -> str: 375 | return ("Worst kind of dark magic - " 376 | "Intended to affect an object in a strongly negative manner.") 377 | 378 | @classmethod 379 | def fiera_satanotis(cls) -> 'Curse': 380 | return cls('Torture curse', 'Fiera Satanotis', 381 | 'Tortures a person, makes person suffer deeply', 'Difficult') 382 | 383 | def cast(self) -> str: 384 | return(f"{self.incantation}!") 385 | 386 | class CounterSpell(Spell): 387 | """Creates a counter-spell - a spell that inhibits the effect of another spell""" 388 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 389 | super().__init__(name, incantation, effect, difficulty, min_year) 390 | 391 | @property 392 | def defining_feature(self) -> str: 393 | return ("Inhibites the effects of another spell") 394 | 395 | @classmethod 396 | def mufindo_immolim(cls) -> 'CounterSpell': 397 | return cls('The Mufindo Immolim counter spell', 'Mufindo Immolim', 398 | 'Counteracts the immobilisation spell that prevents a person from moving') 399 | 400 | def cast(self) -> str: 401 | return(f"{self.incantation}!") 402 | 403 | class HealingSpell(Spell): 404 | """Creates a healing-spell - a spell that improves the condition of a living object""" 405 | def __init__(self, name: str, incantation: str, effect: str, difficulty: str = "Simple", min_year: int = 1): 406 | super().__init__(name, incantation, effect, difficulty, min_year) 407 | 408 | @property 409 | def defining_feature(self) -> str: 410 | return "Improves the condition of a living object" 411 | 412 | @classmethod 413 | def porim_perfite(cls) -> 'HealingSpell': 414 | return cls('Wound healing spell', 'Porim Perfite', 415 | 'Heals all kinds of wounds, even bad ones', 'Difficult', 5) 416 | 417 | def cast(self) -> str: 418 | return(f"{self.incantation}!") 419 | 420 | 421 | @dataclass(frozen=True) 422 | class DarkArmyMember(): 423 | """ Creates a member of the Dark Army""" 424 | name: str 425 | birthyear: int 426 | 427 | @property 428 | def leader(self) -> 'DarkArmyMember': 429 | master_odon = DarkArmyMember('Master Odon', 1971) 430 | return master_odon 431 | 432 | def cast_spell(self, spell) -> str: 433 | return(f"{self.name}: {spell.incantation}!") 434 | 435 | 436 | @dataclass 437 | class Department: 438 | """ Creates a Castle Kilmere Department """ 439 | name: str 440 | head: Professor 441 | founded_in: int = 991 442 | 443 | def current_age(self): 444 | now = datetime.datetime.now().year 445 | return (now - self.founded_in) + 1 446 | 447 | 448 | class Letter: 449 | total_number_of_letters = 0 450 | 451 | def __init__(self, letter_name): 452 | self.letter_name = letter_name 453 | 454 | def __enter__(self): 455 | self.letter = open(self.letter_name, 'w') 456 | self.__class__.total_number_of_letters += 1 457 | return self.letter 458 | 459 | def __exit__(self, exc_type, exc_value, traceback): 460 | if self.letter: 461 | self.letter.close() 462 | 463 | class Potion: 464 | """ Creates a potion """ 465 | def __init__(self, ingredients): 466 | self.ingredients = ingredients 467 | self.counter = -1 468 | 469 | def __iter__(self): 470 | return self 471 | 472 | def __next__(self): 473 | self.counter += 1 474 | 475 | if self.counter == len(self.ingredients): 476 | raise StopIteration 477 | 478 | return self.ingredients[self.counter] 479 | 480 | 481 | if __name__ == "__main__": 482 | bromley = CastleKilmereMember('Bromley Huckabee', 1959, 'male') 483 | 484 | # print(bromley.says.__name__) 485 | # print(bromley.says.__doc__) 486 | 487 | # bromley.add_trait('tidy-minded') 488 | # bromley.add_trait('kind') 489 | 490 | # bromley.exhibits_trait('kind') 491 | # bromley.exhibits_trait('mean') 492 | 493 | # bromley.print_traits() 494 | 495 | print(bromley == eval(repr(bromley))) 496 | 497 | # briddle = Professor.briddle() 498 | # print(briddle == eval(repr(briddle))) 499 | 500 | -------------------------------------------------------------------------------- /test_code/test_abstract_base_class_spell.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from magical_universe import Spell, Charm, Transfiguration, Hex, Curse, Jinx, HealingSpell, CounterSpell 3 | 4 | @pytest.fixture 5 | def stuporus_ratiato(): 6 | return Charm.stuporus_ratiato() 7 | 8 | @pytest.fixture 9 | def alteraror_canieo(): 10 | return Transfiguration.alteraror_canieo() 11 | 12 | @pytest.fixture 13 | def rectaro(): 14 | return Hex.rectaro() 15 | 16 | @pytest.fixture 17 | def fiera_satanotis(): 18 | return Curse.fiera_satanotis() 19 | 20 | @pytest.fixture 21 | def inceptotis(): 22 | return Jinx.inceptotis() 23 | 24 | @pytest.fixture 25 | def porim_perfite(): 26 | return HealingSpell.porim_perfite() 27 | 28 | @pytest.fixture 29 | def mufindo_immolim(): 30 | return CounterSpell.mufindo_immolim() 31 | 32 | def test_instantiating_base_class_raises_exception(): 33 | with pytest.raises(TypeError): 34 | spell = Spell() 35 | 36 | def test_correctness_of_charm_attributes(stuporus_ratiato): 37 | assert stuporus_ratiato.name == 'The Stuporus Ratiato charm' 38 | assert stuporus_ratiato.incantation == 'Stuporus Ratiato' 39 | assert stuporus_ratiato.effect == 'Makes objects fly' 40 | assert stuporus_ratiato.min_year == 1 41 | assert stuporus_ratiato.difficulty == 'Simple' 42 | 43 | def test_cast_charm(stuporus_ratiato): 44 | assert stuporus_ratiato.cast() == 'Stuporus Ratiato!' 45 | 46 | def test_repr_output_charm(capfd, stuporus_ratiato): 47 | print(stuporus_ratiato) 48 | stdout, err = capfd.readouterr() 49 | stdout = stdout.strip() 50 | assert stdout == "Charm(name='The Stuporus Ratiato charm', incantation='Stuporus Ratiato', effect='Makes objects fly', difficulty='Simple', min_year=1)" 51 | 52 | def test_charm_defining_feature(stuporus_ratiato): 53 | assert stuporus_ratiato.defining_feature == "Alteration of the object's inherent qualities, " \ 54 | "that is, its behaviour and capabilities" 55 | 56 | 57 | def test_correctness_of_transfiguration_attributes(alteraror_canieo): 58 | assert alteraror_canieo.name == 'The Alteraro Canieo transfiguration' 59 | assert alteraror_canieo.incantation == 'Alteraro Canieo' 60 | assert alteraror_canieo.effect == 'Turns an object into a can' 61 | assert alteraror_canieo.difficulty == 'Simple' 62 | assert alteraror_canieo.min_year == 2 63 | 64 | def test_cast_transfiguration(alteraror_canieo): 65 | assert alteraror_canieo.cast() == 'Alteraro Canieo!' 66 | 67 | def test_repr_output_transfiguration(capfd, alteraror_canieo): 68 | print(alteraror_canieo) 69 | stdout, err = capfd.readouterr() 70 | stdout = stdout.strip() 71 | assert stdout == "Transfiguration(name='The Alteraro Canieo transfiguration', incantation='Alteraro Canieo', effect='Turns an object into a can', difficulty='Simple', min_year=2)" 72 | 73 | def test_transfiguration_defining_feature(alteraror_canieo): 74 | assert alteraror_canieo.defining_feature == "Alteration of the object's form or appearance" 75 | 76 | def test_correctness_of_jinx_attributes(inceptotis): 77 | assert inceptotis.name == 'The Inceptotis jinx' 78 | assert inceptotis.incantation == 'Inceptotis' 79 | assert inceptotis.effect == 'Makes a person talk baby talk' 80 | assert inceptotis.difficulty == 'Simple' 81 | 82 | def test_cast_jinx(inceptotis): 83 | assert inceptotis.cast() == 'Inceptotis!' 84 | 85 | def test_repr_output_jinx(capfd, inceptotis): 86 | print(inceptotis) 87 | stdout, err = capfd.readouterr() 88 | stdout = stdout.strip() 89 | assert stdout == "Jinx(name='The Inceptotis jinx', incantation='Inceptotis', effect='Makes a person talk baby talk', difficulty='Simple', min_year=1)" 90 | 91 | def test_jinx_defining_feature(inceptotis): 92 | assert inceptotis.defining_feature == "Minor darf magic - " \ 93 | "a spell whose effects are irritating but amusing, " \ 94 | "almost playful and of minor inconvenience to the target" 95 | 96 | def test_correctness_of_hex_attributes(rectaro): 97 | assert rectaro.name == 'The Rectaro hex' 98 | assert rectaro.incantation == 'Rectaro' 99 | assert rectaro.effect == 'Exchanges a persons arms and legs' 100 | assert rectaro.difficulty == 'Difficult' 101 | 102 | def test_cast_hex(rectaro): 103 | assert rectaro.cast() == 'Rectaro!' 104 | 105 | def test_repr_output_hex(capfd, rectaro): 106 | print(rectaro) 107 | stdout, err = capfd.readouterr() 108 | stdout = stdout.strip() 109 | assert stdout == "Hex(name='The Rectaro hex', incantation='Rectaro', effect='Exchanges a persons arms and legs', difficulty='Difficult', min_year=None)" 110 | 111 | def test_hex_defining_feature(rectaro): 112 | assert rectaro.defining_feature == "Medium dark magic - " \ 113 | "Affects an object in a negative manner. " \ 114 | "Major inconvenience to the target." 115 | 116 | def test_correctness_of_curse_attributes(fiera_satanotis): 117 | assert fiera_satanotis.name == 'Torture curse' 118 | assert fiera_satanotis.incantation == 'Fiera Satanotis' 119 | assert fiera_satanotis.effect == 'Tortures a person, makes person suffer deeply' 120 | assert fiera_satanotis.difficulty == 'Difficult' 121 | assert fiera_satanotis.min_year == 6 122 | 123 | def test_cast_curse(fiera_satanotis): 124 | assert fiera_satanotis.cast() == 'Fiera Satanotis!' 125 | 126 | def test_repr_output_curse(capfd, fiera_satanotis): 127 | print(fiera_satanotis) 128 | stdout, err = capfd.readouterr() 129 | stdout = stdout.strip() 130 | assert stdout == "Curse(name='Torture curse', incantation='Fiera Satanotis', effect='Tortures a person, makes person suffer deeply', difficulty='Difficult', min_year=6)" 131 | 132 | def test_curse_defining_feature(fiera_satanotis): 133 | assert fiera_satanotis.defining_feature == "Worst kind of dark magic - " \ 134 | "Intended to affect an object in a strongly negative manner." 135 | 136 | def test_correctness_of_counter_spell_attributes(mufindo_immolim): 137 | assert mufindo_immolim.name == 'The Mufindo Immolim counter spell' 138 | assert mufindo_immolim.incantation == 'Mufindo Immolim' 139 | assert mufindo_immolim.effect == 'Counteracts the immobilisation spell that prevents a person from moving' 140 | assert mufindo_immolim.difficulty == 'Simple' 141 | 142 | def test_cast_counter_spell(mufindo_immolim): 143 | assert mufindo_immolim.cast() == 'Mufindo Immolim!' 144 | 145 | def test_repr_output_counter_spell(capfd, mufindo_immolim): 146 | print(mufindo_immolim) 147 | stdout, err = capfd.readouterr() 148 | stdout = stdout.strip() 149 | assert stdout == "CounterSpell(name='The Mufindo Immolim counter spell', incantation='Mufindo Immolim', effect='Counteracts the immobilisation spell that prevents a person from moving', difficulty='Simple', min_year=1)" 150 | 151 | def test_counter_spell_defining_feature(mufindo_immolim): 152 | assert mufindo_immolim.defining_feature == "Inhibites the effects of another spell" 153 | 154 | def test_correctness_of_healing_spell_attributes(porim_perfite): 155 | assert porim_perfite.name == 'Wound healing spell' 156 | assert porim_perfite.incantation == 'Porim Perfite' 157 | assert porim_perfite.effect == "Heals all kinds of wounds, even bad ones" 158 | assert porim_perfite.difficulty == 'Difficult' 159 | assert porim_perfite.min_year == 5 160 | 161 | def test_cast_healing_spell(porim_perfite): 162 | assert porim_perfite.cast() == 'Porim Perfite!' 163 | 164 | def test_repr_output_healing_spell(capfd, porim_perfite): 165 | print(porim_perfite) 166 | stdout, err = capfd.readouterr() 167 | stdout = stdout.strip() 168 | assert stdout == "HealingSpell(name='Wound healing spell', incantation='Porim Perfite', effect='Heals all kinds of wounds, even bad ones', difficulty='Difficult', min_year=5)" 169 | 170 | def test_healing_spell_defining_feature(porim_perfite): 171 | assert porim_perfite.defining_feature == "Improves the condition of a living object" 172 | 173 | -------------------------------------------------------------------------------- /test_code/test_castle_kilmere_member_class.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from magical_universe import CastleKilmereMember 3 | import datetime 4 | 5 | now = datetime.datetime.now().year 6 | 7 | @pytest.fixture 8 | def bromley(): 9 | bromley = CastleKilmereMember('Bromley Huckabee', 1956, 'male') 10 | return bromley 11 | 12 | @pytest.fixture 13 | def bromley_with_traits(): 14 | bromley = CastleKilmereMember('Bromley Huckabee', 1956, 'male') 15 | bromley.add_trait('kind') 16 | bromley.add_trait('wild') 17 | bromley.add_trait('mean', False) 18 | return bromley 19 | 20 | def test_correctness_of_attributes_(bromley): 21 | assert bromley.name == 'Bromley Huckabee' 22 | assert bromley.birthyear == 1956 23 | assert bromley.sex == 'male' 24 | 25 | def test_add_positive_traits(bromley): 26 | bromley.add_trait('kind') 27 | bromley.add_trait('wild') 28 | assert bromley._traits == {'kind': True, 'wild': True} 29 | 30 | def test_add_negative_trait(bromley): 31 | bromley.add_trait('mean', False) 32 | assert bromley._traits == {'mean': False} 33 | 34 | def test_exhibit_traits(bromley_with_traits): 35 | assert bromley_with_traits.exhibits_trait('kind') == True 36 | assert bromley_with_traits.exhibits_trait('mean') == False 37 | assert bromley_with_traits.exhibits_trait('smart') == False 38 | 39 | def test_print_traits(capfd, bromley_with_traits): 40 | bromley_with_traits.print_traits() 41 | stdout, err = capfd.readouterr() 42 | stdout = stdout.strip() 43 | assert stdout == 'Bromley Huckabee is kind, wild.\nBromley Huckabee is not mean.' 44 | 45 | def test_init_raises_exception_with_missing_arguments(): 46 | with pytest.raises(TypeError): 47 | bromley = CastleKilmereMember() 48 | 49 | def test_says(bromley): 50 | assert bromley.says("Hi Lissy!") == "Bromley Huckabee says: Hi Lissy!" 51 | 52 | def test_name_property(bromley): 53 | assert bromley.name == 'Bromley Huckabee' 54 | 55 | def test_age_property(bromley): 56 | assert bromley.age == (now - bromley.birthyear) 57 | 58 | def test_repr_output(capfd, bromley): 59 | print(bromley) 60 | stdout, err = capfd.readouterr() 61 | stdout = stdout.strip() 62 | assert stdout == "CastleKilmereMember(name='Bromley Huckabee', birthyear=1956, sex='male')" 63 | 64 | -------------------------------------------------------------------------------- /test_code/test_dark_army_member_class.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from magical_universe import DarkArmyMember, Charm 3 | 4 | @pytest.fixture 5 | def keres_fulford(): 6 | keres_fulford = DarkArmyMember("Keres Fulford", 1953) 7 | return keres_fulford 8 | 9 | @pytest.fixture 10 | def master_odon(): 11 | master_odon = DarkArmyMember('Master Odon', 1971) 12 | return master_odon 13 | 14 | @pytest.fixture 15 | def stuporus_ratiato(): 16 | return Charm.stuporus_ratiato() 17 | 18 | def test_correctness_of_attributes(keres_fulford): 19 | assert keres_fulford.name == "Keres Fulford" 20 | assert keres_fulford.birthyear == 1953 21 | 22 | def test_leader_property(keres_fulford, master_odon): 23 | assert keres_fulford.leader == master_odon 24 | 25 | def test_repr_output(capfd, keres_fulford): 26 | print(keres_fulford) 27 | stdout, err = capfd.readouterr() 28 | stdout = stdout.strip() 29 | assert stdout == "DarkArmyMember(name='Keres Fulford', birthyear=1953)" 30 | 31 | def test_cast_spell(keres_fulford, stuporus_ratiato): 32 | assert keres_fulford.cast_spell(stuporus_ratiato) == "Keres Fulford: Stuporus Ratiato!" 33 | -------------------------------------------------------------------------------- /test_code/test_ghost_class.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from magical_universe import Ghost 3 | import datetime 4 | 5 | now = datetime.datetime.now().year 6 | 7 | @pytest.fixture 8 | def mocking_knight(): 9 | return Ghost.mocking_knight() 10 | 11 | def test_correctness_of_attributes_(mocking_knight): 12 | assert mocking_knight.name == "The Mocking Knight" 13 | assert mocking_knight.year_of_death == 1492 14 | 15 | def test_age_property(mocking_knight): 16 | assert mocking_knight.age == (now - mocking_knight.birthyear) 17 | 18 | def test_repr_output(capfd, mocking_knight): 19 | print(mocking_knight) 20 | stdout, err = capfd.readouterr() 21 | stdout = stdout.strip() 22 | assert stdout == "Ghost(name='The Mocking Knight', birthyear=1401, sex='male', year_of_death=1492)" 23 | -------------------------------------------------------------------------------- /test_code/test_potion_class.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from magical_universe import Potion 3 | 4 | @pytest.fixture 5 | def flask_of_remembrance(): 6 | return Potion(['raven eggshells', 'tincture of thyme', 'unicorn tears', 7 | 'dried onions', 'powdered ginger root']) 8 | @pytest.fixture 9 | def vial_of_anger(): 10 | return Potion(['dried dragon skin', 'leeches', 'shredded elephant tusk', 11 | 'horned flies', 'earthworm juice']) 12 | 13 | def test_iterator_behavior(flask_of_remembrance): 14 | all_ingredients = [ingredient for ingredient in flask_of_remembrance] 15 | assert all_ingredients == ['raven eggshells', 'tincture of thyme', 'unicorn tears', 16 | 'dried onions', 'powdered ginger root'] 17 | 18 | 19 | -------------------------------------------------------------------------------- /test_code/test_professor_class.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import datetime 3 | from magical_universe import Professor 4 | 5 | now = datetime.datetime.now().year 6 | 7 | @pytest.fixture 8 | def briddle(): 9 | return Professor.briddle() 10 | 11 | def test_correctness_of_attributes_(briddle): 12 | assert briddle.name == "Birdie Briddle" 13 | assert briddle.subject == "Foreign Magical Systems" 14 | assert briddle.department == "Department of Law" 15 | 16 | def test_repr_output(capfd, briddle): 17 | print(briddle) 18 | stdout, err = capfd.readouterr() 19 | stdout = stdout.strip() 20 | assert stdout == "Professor(name='Birdie Briddle', birthyear=1931, sex='female', subject='Foreign Magical Systems', department='Department of Law')" 21 | -------------------------------------------------------------------------------- /test_code/test_pupil_class.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import datetime 3 | from magical_universe import Pupil, Charm, Transfiguration, Hex, Curse, Jinx, HealingSpell, CounterSpell 4 | 5 | now = datetime.datetime.now().year 6 | 7 | @pytest.fixture 8 | def stuporus_ratiato(): 9 | return Charm.stuporus_ratiato() 10 | 11 | @pytest.fixture 12 | def liberula(): 13 | return Charm.liberula() 14 | 15 | @pytest.fixture 16 | def alteraror_canieo(): 17 | return Transfiguration.alteraror_canieo() 18 | 19 | @pytest.fixture 20 | def rectaro(): 21 | return Hex.rectaro() 22 | 23 | @pytest.fixture 24 | def fiera_satanotis(): 25 | return Curse.fiera_satanotis() 26 | 27 | @pytest.fixture 28 | def inceptotis(): 29 | return Jinx.inceptotis() 30 | 31 | @pytest.fixture 32 | def porim_perfite(): 33 | return HealingSpell.porim_perfite() 34 | 35 | @pytest.fixture 36 | def mufindo_immolim(): 37 | return CounterSpell.mufindo_immolim() 38 | 39 | @pytest.fixture 40 | def luke(): 41 | return Pupil.luke() 42 | 43 | @pytest.fixture 44 | def lissy(): 45 | lissy = Pupil.lissy() 46 | lissy.add_trait('highly intelligent') 47 | return lissy 48 | 49 | @pytest.fixture 50 | def adrien(): 51 | return Pupil.adrien() 52 | 53 | @pytest.fixture 54 | def luke_with_friends(): 55 | luke = Pupil.luke() 56 | lissy = Pupil.lissy() 57 | luke.befriend(lissy) 58 | return luke 59 | 60 | def test_correctness_of_attributes_(luke): 61 | assert luke.name == "Luke Bery" 62 | assert luke.start_year == 2020 63 | assert luke.pet_name == 'Cotton' 64 | assert luke.pet_type == 'owl' 65 | 66 | def test_current_year_property(luke): 67 | assert luke.current_year == (now - luke.start_year + 1) 68 | 69 | def test_elms_property(luke): 70 | assert luke._elms == { 71 | 'Critical Thinking': False, 72 | 'Self-Defense Against Fresh Fruit': False, 73 | 'Broomstick Flying': False, 74 | 'Magical Theory': False, 75 | 'Foreign Magical Systems': False, 76 | 'Charms': False, 77 | 'Defence Against Dark Magic': False, 78 | 'History of Magic': False, 79 | 'Potions': False, 80 | 'Transfiguration': False} 81 | 82 | def test_friends_property(luke_with_friends): 83 | assert luke_with_friends.friends == "Luke Bery's current friends are: ['Lissy Spinster']" 84 | 85 | def test_luke_befriend_lissy(capfd, luke, lissy): 86 | luke.befriend(lissy) 87 | stdout, err = capfd.readouterr() 88 | stdout = stdout.strip() 89 | assert stdout == "Lissy Spinster is now your friend!" 90 | 91 | def test_befriend_house_adrien(capfd, luke, adrien): 92 | luke.befriend(adrien) 93 | stdout, err = capfd.readouterr() 94 | stdout = stdout.strip() 95 | assert stdout == "Adrien Fulford is now your friend!" 96 | 97 | def test_delete_elms(capfd, luke): 98 | del luke.elms 99 | stdout, err = capfd.readouterr() 100 | stdout = stdout.strip() 101 | assert stdout == "Caution, you are deleting this students' ELM's! You should only do that if she/he dropped out of school without passing any exam!" 102 | with pytest.raises(AttributeError): 103 | print(luke.elms) 104 | 105 | def test_set_elms_raises_ValueError_with_wrong_input_argument(capfd, luke): 106 | with pytest.raises(ValueError): 107 | luke.elms = 'Transfiguration' 108 | 109 | def test_set_elms_with_passed_grade(capfd, luke): 110 | luke.elms = ("Transfiguration", "G") 111 | assert luke._elms == { 112 | 'Critical Thinking': False, 113 | 'Self-Defense Against Fresh Fruit': False, 114 | 'Broomstick Flying': False, 115 | 'Magical Theory': False, 116 | 'Foreign Magical Systems': False, 117 | 'Charms': False, 118 | 'Defence Against Dark Magic': False, 119 | 'History of Magic': False, 120 | 'Potions': False, 121 | 'Transfiguration': True} 122 | 123 | def test_set_elms_with_not_passed_grade(capfd, luke): 124 | luke.elms = ("Transfiguration", "H") 125 | stdout, err = capfd.readouterr() 126 | stdout = stdout.strip() 127 | assert stdout == 'The exam was not passed so no ELM was awarded!' 128 | assert luke._elms == { 129 | 'Critical Thinking': False, 130 | 'Self-Defense Against Fresh Fruit': False, 131 | 'Broomstick Flying': False, 132 | 'Magical Theory': False, 133 | 'Foreign Magical Systems': False, 134 | 'Charms': False, 135 | 'Defence Against Dark Magic': False, 136 | 'History of Magic': False, 137 | 'Potions': False, 138 | 'Transfiguration': False} 139 | 140 | def test_staticmethod_passed_with_passed_grades(): 141 | assert Pupil.passed('E') == True 142 | assert Pupil.passed('Excellent') == True 143 | assert Pupil.passed('G') == True 144 | assert Pupil.passed('Good') == True 145 | assert Pupil.passed('A') == True 146 | assert Pupil.passed('Acceptable') == True 147 | 148 | def test_staticmethod_passed_with_not_passed_grades(): 149 | assert Pupil.passed('P') == False 150 | assert Pupil.passed('Poor') == False 151 | assert Pupil.passed('H') == False 152 | assert Pupil.passed('Horrible') == False 153 | 154 | def test_staticmethod_passed_default_return_value(): 155 | assert Pupil.passed('D') == False 156 | 157 | def test_repr_output(capfd, luke): 158 | print(luke) 159 | stdout, err = capfd.readouterr() 160 | stdout = stdout.strip() 161 | assert stdout == "Pupil(name='Luke Bery', birthyear=2008, sex='male', start_year=2020)" 162 | 163 | def test_learn_spell_hex_if_not_being_evil(capfd, luke, rectaro): 164 | luke.learn_spell(rectaro) 165 | stdout, err = capfd.readouterr() 166 | stdout = stdout.strip() 167 | assert stdout == 'How dare you study a hex or curse?!' 168 | 169 | def test_learn_spell_charm_if_being_too_young(capfd, luke, liberula): 170 | luke.learn_spell(liberula) 171 | stdout, err = capfd.readouterr() 172 | stdout = stdout.strip() 173 | assert stdout == "Luke Bery is too young to study this spell!" 174 | 175 | def test_learn_spell_charm_if_being_too_young_but_highly_intelligent(capfd, lissy, liberula): 176 | lissy.learn_spell(liberula) 177 | stdout, err = capfd.readouterr() 178 | stdout = stdout.strip() 179 | assert stdout == "Lissy Spinster now knows 'The Liberula charm'" 180 | 181 | def test_learn_spell(capfd, luke, stuporus_ratiato): 182 | luke.learn_spell(stuporus_ratiato) 183 | stdout, err = capfd.readouterr() 184 | stdout = stdout.strip() 185 | assert stdout == "Luke Bery now knows 'The Stuporus Ratiato charm'" 186 | assert stuporus_ratiato in luke.known_spells 187 | 188 | def test_cast_spell_curse(capfd, luke, fiera_satanotis): 189 | luke.cast_spell(fiera_satanotis) 190 | stdout, err = capfd.readouterr() 191 | stdout = stdout.strip() 192 | assert stdout == 'This is dark magic - stay away from performing curses!' 193 | 194 | def test_cast_known_spell(capfd, luke, stuporus_ratiato): 195 | luke.learn_spell(stuporus_ratiato) 196 | assert luke.cast_spell(stuporus_ratiato) == 'Luke Bery: Stuporus Ratiato!' 197 | --------------------------------------------------------------------------------