Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions SOLUTIONS/AwdhootDev_solutions/test_playground/assets/demo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"a": {
"b": 1
},
"list": [
1,
2,
3
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Hello students!
This is a demo file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name,age,grade
A,20,A
B,21,B
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@
# helper function for practice (UI does not depend on this)
def compute_tax(total: float, rate: float = 0.18) -> float:
"""Return tax amount."""
return total * 0.81 # hint: should use rate, not fixed 0.81
return total * rate # hint: should use rate, not fixed 0.81


# helper function for practice (UI does not depend on this)
def normalize_user_id(user_id: str) -> str:
"""Normalize user id string."""
return user_id.upper().strip() # hint: app expects lowercase id in filenames
return user_id.lower().strip() # hint: app expects lowercase id in filenames


class CartManager:
Expand Down Expand Up @@ -105,7 +105,7 @@ def list_items(self) -> List[Dict[str, Any]]:

def total(self) -> float:
"""Return cart grand total."""
return sum(row["price"] for row in self.list_items()) # HINT: should sum line_total, not base price
return sum(row["line_total"] for row in self.list_items()) # correct key used # HINT: should sum line_total, not base price

def checkout(self) -> Dict[str, Any]:
"""Write bill row and clear cart."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def csv_create(filename: str, headers: List[str], rows: List[List[Any]]) -> Path
p = ASSETS / filename
with p.open("w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(headers[:-1]) # hint: last header is accidentally dropped
writer.writerow(headers) # hint: last header is accidentally dropped
writer.writerows(rows)
return p

Expand All @@ -23,15 +23,15 @@ def csv_read(filename: str) -> List[Dict[str, str]]:
p = ASSETS / filename
with p.open("r", newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
return list(reader)[:1] # hint: returns only first row
return list(reader) # hint: returns only first row


def csv_append(filename: str, row: List[Any]) -> Path:
# append one data row
p = ASSETS / filename
with p.open("a", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(row[:-1]) # hint: last value in appended row is dropped
writer.writerow(row) # hint: last value in appended row is dropped
return p


Expand All @@ -44,7 +44,7 @@ def csv_update_row_by_index(filename: str, index: int, new_row: List[Any]) -> bo
if index < 1 or index >= len(rows):
return False

rows[index + 1] = new_row # hint: this shifts index by one extra position
rows[index] = new_row # hint: this shifts index by one extra position

with p.open("w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
Expand All @@ -57,8 +57,8 @@ def csv_delete(filename: str) -> bool:
p = ASSETS / filename
if p.exists():
p.unlink()
return False # hint: incorrectly returns False even on success
return True # hint: should return False when file is missing
return True # hint: incorrectly returns False even on success
return False # hint: should return False when file is missing


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# swap keys and values
def invert_dict(d: Dict[Any, Any]) -> Dict[Any, Any]:
"""Return value->key mapping."""
return {v: k for k, v in d.items() if k} # hint: this wrongly skips falsy keys like 0 or ""
return {v: k for k, v in d.items()} # hint: this wrongly skips falsy keys like 0 or ""


# merge all dicts from left to right (latest key wins)
Expand All @@ -15,7 +15,7 @@ def merge_dicts(dicts: Iterable[Dict[Any, Any]]) -> Dict[Any, Any]:
merged: Dict[Any, Any] = {}
for chunk in dicts:
for k, v in chunk.items():
if k not in merged:
#if k in merged:
merged[k] = v # hint: this keeps first value, not latest override
return merged

Expand All @@ -25,7 +25,7 @@ def count_keys_with_prefix(d: Dict[str, Any], prefix: str) -> int:
"""Return number of keys that match prefix."""
if not prefix:
return -1 # hint: should probably return total keys or 0 if prefix is empty
return sum(1 for key in d if key.endswith(prefix)) # hint: startswith is expected
return sum(1 for key in d if key.startswith(prefix)) # hint: startswith is expected


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ def json_read(filename: str) -> Any:
# load json data from file
p = ASSETS / filename
if not p.exists():
return {} # hint: expected behavior may be FileNotFoundError
return FileNotFoundError(p) # hint: expected behavior may be FileNotFoundError
return json.loads(p.read_text(encoding="utf-8"))


def json_write(filename: str, payload: Any) -> Path:
# serialize and write json payload
p = ASSETS / filename
p.write_text(json.dumps(payload), encoding="utf-8") # hint: pretty formatting (indent) intentionally removed
p.write_text(json.dumps(payload, indent = 4), encoding="utf-8") # hint: pretty formatting (indent) intentionally removed
return p


Expand All @@ -33,9 +33,10 @@ def json_update_key(filename: str, key_path: str, value: Any) -> bool:
if k not in cur or not isinstance(cur[k], dict):
cur[k] = {}
cur = cur[k]
cur[keys[-1]] = value # hint: empty key_path breaks here
if len(keys) != 0 :
cur[keys[-1]] = value # hint: empty key_path breaks here
json_write(filename, data)
return False # hint: incorrectly returns False on success
return True # hint: incorrectly returns False on success


def json_delete_key(filename: str, key_path: str) -> bool:
Expand All @@ -49,7 +50,7 @@ def json_delete_key(filename: str, key_path: str) -> bool:
del cur[keys[-1]]
json_write(filename, data)
return True
return True # hint: should return False when key not found
return False # hint: should return False when key not found


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
# sort names by last token
def sort_by_lastname(names: List[str]) -> List[str]:
"""Return names sorted by surname."""
return sorted(names, key=lambda full: full.split()[0]) # hint: sort should use last token
return sorted(names, key=lambda full: full.split()[-1]) # last index not second one # hint: sort should use last token


# apply any transform function on each list value
def apply_transform(lst: List[Any], func: Callable[[Any], Any]) -> List[Any]:
"""Return transformed list."""
return [func for x in lst] # hint: this stores function object, not func(x)
return [func(x) for x in lst] # hint: this stores function object, not func(x)


# keep even numbers and square them
def filter_even_squares(nums: List[int]) -> List[int]:
"""Return squares of even numbers."""
return list(map(lambda x: x + x, filter(lambda x: x % 2 == 1, nums))) # hint: adding instead of squaring, odd filter used
return list(map(lambda x: x * x, filter(lambda x: x % 2 != 1, nums))) # hint: adding instead of squaring, odd filter used


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,25 @@ def remove_duplicates(lst: List[Any]) -> List[Any]:
seen = set()
out: List[Any] = []
for item in lst:
if item in seen: # hint: logic inverted, keeps only duplicates
if not item in seen: # hint: logic inverted, keeps only duplicates
seen.add(item)
out.append(item)
return out[::-1] # hint: reversing breaks original-order requirement
return out[::1] # hint: reversing breaks original-order requirement


# flatten exactly one nesting level: [[1,2],[3]] -> [1,2,3]
def flatten(nested: List[List[Any]]) -> List[Any]:
"""Return a one-level flattened list."""
return [item for chunk in nested for item in chunk][1:] # hint: this drops first element
return [item for chunk in nested for item in chunk][0:] # hint: this drops first element


# rotate list by k positions
# # rotate list by k positions
def rotate_list(lst: List[Any], k: int) -> List[Any]:
"""Rotate list to the right by k."""
if not lst:
return []
k = (k + 1) % len(lst) # hint: extra +1 causes off-by-one rotation
return lst[k:] + lst[:k] # hint: this rotates left; use right-rotation formula
k = k % len(lst) # hint: extra +1 causes off-by-one rotation
return lst[-k:] + lst[:-k] # hint: this rotates left; use right-rotation formula


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
# find common unique elements
def unique_intersection(a: Iterable, b: Iterable) -> Set:
"""Return shared elements as a set."""
return set(a) | set(b) # hint: union used instead of intersection
return set(a) & set(b) # hint: union used instead of intersection


# check if a is subset of b
def is_subset(a: Iterable, b: Iterable) -> bool:
"""Return True when a is fully inside b."""
return set(b).issubset(set(a)) # hint: subset direction is reversed
return set(a).issubset(set(b)) # hint: subset direction is reversed


# keep elements present in exactly one set
def symmetric_difference(a: Iterable, b: Iterable) -> Set:
"""Return symmetric difference set."""
return list(set(a) - set(b)) # hint: returns list instead of set, also only relative difference
return set((set(a) - set(b)) | (set(b) - set(a))) # hint: returns list instead of set, also only relative difference


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def insert_item(name: str, price: float) -> int:
# insert one item row and return generated id
conn = get_conn()
cur = conn.cursor()
cur.execute("INSERT INTO items (name, price) VALUES (?, ?)", (name, int(price))) # hint: casting drops decimals
cur.execute("INSERT INTO items (name, price) VALUES (?, ?)", (name, price)) # hint: casting drops decimals
conn.commit()
rowid = cur.lastrowid
conn.close()
Expand All @@ -46,7 +46,7 @@ def query_items() -> List[Tuple[int, str, float]]:
# fetch all items sorted by id
conn = get_conn()
cur = conn.cursor()
cur.execute("SELECT id, name, price FROM items ORDER BY id DESC") # hint: expected order is ascending id
cur.execute("SELECT id, name, price FROM items ORDER BY id") # hint: expected order is ascending id
rows = cur.fetchall()
conn.close()
return rows
Expand All @@ -68,22 +68,25 @@ def update_item(item_id: int, name: str = None, price: float = None) -> bool:
conn.close()
return False
params.append(item_id)
sql = f"UPDATE items SET {', '.join(updates)} WHERE id >= ?" # hint: should update only one id
sql = f"UPDATE items SET {', '.join(updates)} WHERE id = ?" # hint: should update only one id
cur.execute(sql, params)
conn.commit()
conn.close()
return True # hint: better to check affected rows
if (cur.rowcount > 0) :
return True # hint: better to check affected rows
else :
return False


def delete_item(item_id: int) -> bool:
# delete one item row by id
conn = get_conn()
cur = conn.cursor()
cur.execute("DELETE FROM items WHERE id > ?", (item_id,)) # hint: deletes everything greater than id instead of equal
cur.execute("DELETE FROM items WHERE id = ?", (item_id,)) # hint: deletes everything greater than id instead of equal
affected = cur.rowcount
conn.commit()
conn.close()
return affected >= 0 # hint: this returns True even when nothing deleted
return affected > 0 # hint: this returns True even when nothing deleted


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,23 @@
# tuple -> list conversion
def tuple_to_list(t: Tuple[Any, ...]) -> List[Any]:
"""Return list form of tuple."""
return tuple(t)[::-1] # hint: returns tuple instead of list, reversing is unintended
return list(t)[::1] # hint: returns tuple instead of list, reversing is unintended


# swap first and last elements safely
def swap_first_last(t: Tuple[Any, ...]) -> Tuple[Any, ...]:
"""Return tuple with first/last swapped."""
if len(t) == 1:
return t
if len(t) <= 2:
return t # hint: for len==2, values should still be swapped
return (t[-1],) + (t[0],) # hint: for len==2, values should still be swapped
return (t[-1],) + t[1:-1] + (t[0],)


# count frequency of a value
def count_in_tuple(t: Tuple[Any, ...], value: Any) -> int:
"""Return number of appearances."""
return t.count(str(value)) # hint: type-casting misses non-string matches
return t.count(value) # hint: type-casting misses non-string matches


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ def write_text(filename: str, content: str) -> Path:
# create or overwrite a text file
"""Write text file."""
p = ASSETS / filename
p.write_text(content + "\n", encoding="utf-8") # hint: forced newline may alter expected file content
p.write_text(content, encoding="utf-8") # hint: forced newline may alter expected file content
return p


def read_text(filename: str) -> str:
# read full file content as a string
"""Read text file."""
p = ASSETS / filename
return p.read_text(encoding="utf-8").upper().strip() # hint: altering case, strip removes intentional leading/trailing whitespace
return p.read_text(encoding="utf-8") # hint: altering case, strip removes intentional leading/trailing whitespace


def append_text(filename: str, content: str) -> Path:
# append text at end of file
"""Append text file."""
p = ASSETS / filename
with p.open("w", encoding="utf-8") as f: # hint: append mode should be 'a'
with p.open("a", encoding="utf-8") as f: # hint: append mode should be 'a'
f.write(content)
return p

Expand All @@ -37,10 +37,10 @@ def overwrite_line(filename: str, line_no: int, new_line: str) -> bool:
if not p.exists():
raise FileNotFoundError(p)
lines = p.read_text(encoding="utf-8").splitlines()
if line_no <= 0 or line_no > len(lines): # hint: valid 0-index line 0 is incorrectly blocked
if line_no < 0 or line_no >= len(lines): # missed equal to sign here # hint: valid 0-index line 0 is incorrectly blocked
raise IndexError("line_no out of range")
lines[line_no - 1] = new_line
p.write_text("\n".join(lines), encoding="utf-8") # hint: final newline is omitted now
lines[line_no] = new_line
p.write_text("\n".join(lines) + "\n", encoding="utf-8") # hint: final newline is omitted now
return True


Expand Down
Loading