Skip to content

Review PR#70

Open
ejanikWork wants to merge 23 commits into
gridu:masterfrom
mmrozekGD:master
Open

Review PR#70
ejanikWork wants to merge 23 commits into
gridu:masterfrom
mmrozekGD:master

Conversation

@ejanikWork

@ejanikWork ejanikWork commented Jun 29, 2026

Copy link
Copy Markdown

Do not merge, it's for review only.

General suggestion (optional, good to know):

Minimal copy-paste setup so trailing whitespace, basic PEP8, and formatting get caught before commit. Uses pre-commit (runs checks on git commit) and Ruff (lint + format, replaces flake8/black/isort for most cases).

1. Install

pip install pre-commit ruff

2. Create .pre-commit-config.yaml in repo root

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
        args: [--maxkb=500]

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.11.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

3. Create pyproject.toml in repo root

[tool.ruff]
line-length = 88
target-version = "py311"

[tool.ruff.lint]
select = ["E", "F", "W", "I"]
ignore = ["E501"]

[tool.ruff.format]
quote-style = "double"

4. Enable and run

pre-commit install
pre-commit run --all-files

pre-commit install wires hooks into git. run --all-files checks the whole repo once (first run will report a lot; that is normal).

What this catches

  • Trailing spaces at end of lines
  • Missing newline at end of file
  • PEP8-style issues (naming, unused imports, etc.)
  • Inconsistent formatting (spacing, quotes)

Note to Mateusz

A lot of the review items above (trailing spaces, processCity vs process_city, sum shadowing builtin, stray print() at module level) are exactly what Ruff flags. You do not need to memorize every PEP8 rule; run the hooks, read the message, fix or ask.

Start with pre-commit run --all-files on a clean branch and fix file by file. Do not --no-verify your way through every commit; that defeats the point.

ruff check --fix and ruff format do the same checks outside git if you want to fix before committing:

ruff check practice/ --fix
ruff format practice/

Hooks auto-fix some things (trailing whitespace, formatting). Others you fix by hand (wrong logic, missing mocks in tests). Lint will not catch bugs like the m7 func2 deadlock; tests and actually running the script still matter.

Optional later: add pytest to CI or pre-commit once the suite is green and fast enough. For now lint + format is enough.

return
str_to_write = task[0] + "," + task[1] + "\n"
with open(result_file, "a") as f:
f.write(str_to_write)

@ejanikWork ejanikWork Jun 29, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m7 func2 worker never exits and join() can hang forever

func2 doesn't look right.

Queue.get() blocks when the queue is empty; it does not raise queue.Empty. except task_q.empty is also not a valid exception handler (TypeError if anything else is raised in try). Workers that finish their items will block forever on the next get(). task_done() is never called, so tasks2.join() can wait indefinitely.

Steps to reproduce:

cd practice/m7_concurrency/task1_fibonacci
python template.py

Script hangs after func1 finishes (or during func2). Minimal repro without computing fib:

python3 -c "
from queue import Queue
from threading import Thread
import time

def worker2(task_q, out):
    while True:
        try:
            task = task_q.get()
        except task_q.empty:
            return
        out.append(task)

q = Queue()
for i in range(3):
    q.put((str(i), str(i)))
out = []
threads = [Thread(target=worker2, args=(q, out)) for _ in range(2)]
[t.start() for t in threads]
time.sleep(1)
print('processed', len(out), 'threads still alive', sum(t.is_alive() for t in threads))
"

# Expected if broken: processed 3, threads still alive 2 (process never exits)

f.write(str_to_write)


def func2(result_file: str):

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m7 func2 reads every file in output dir, including result.csv on rerun

Filter to .txt files only (or skip result.csv by name). Right now a second run can treat result.csv as input and corrupt output.

Create 3 classes with interconnection between them (Student, Teacher,
Homework)
Use datetime module for working with date/time
1. Homework takes 2 attributes for __init__: tasks text and number of days to complete

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Homework class does not match the task spec

Spec says deadline should be a timedelta and Homework.init should take text + days. Implementation stores an absolute datetime as deadline and uses a 3-arg constructor. Tests in m3 were written around this shape, so everything passes, but the datetime exercise was skipped.

pytest practice/m3_python_testing/test_task_classes.py -q   # passes
python3 -c "
from practice.m2_python_part_2.task_classes import Homework
from datetime import timedelta, datetime
h = Homework('task', timedelta(days=5), datetime.now())
print(type(h.deadline))   # spec expects timedelta; code path via Teacher gives datetime
"

pass


def print_name_address(args: argparse.Namespace) -> None:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

task_4 CLI does not generate NUMBER dicts

Task says python task_4.py NUMBER --field=provider ... and print NUMBER dicts, one per line. Only one dict is printed. number_of_flags is parsed then explicitly skipped in the function, with a comment that it exists only for the test.

Steps to reproduce:

cd practice/m4_python_part_3
python task_4.py 3 --some_name=name --fake-address=address

Comment on lines +16 to +25
for book in books[:3]:
author_name_list = book["author_name"]
first_publish_year = book["first_publish_year"]
title = book["title"]

print("Book From API:")
print(f"title: {title}")
print(f"Auhtor(s): {", ".join(author_name_list)[:-1]}")
print(f"First publish year: {first_publish_year}")
print()

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

standalone_api author formatting bug + wrong count

README asks for top 5 results; code uses [:3]. ", ".join(author_name_list)[:-1] strips the last character of the whole string, not the last author. For ["Ada", "Bob"] you get "Ada, Bob"[:-1] -> "Ada, Bo". Also no guard if author_name or first_publish_year is missing (common in Open Library).

Steps to reproduce:

python3 -c "
authors = ['Ada Lovelace', 'Bob Smith']
print(', '.join(authors)[:-1])   # prints: Ada Lovelace, Bob Smit
"

python practice/m6_web_scraping/standalone_api.py
# Compare output count (3 books) vs README requirement (5)

Comment thread practice/m6_web_scraping/tests.py Outdated

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m6 tests are not part of the main test run

Pytest discovers test_*.py, not tests.py. pytest practice/ runs 34 tests and skips m6 entirely. Rename to test_scraper.py or similar and add deps (beautifulsoup4, requests) to a requirements.txt so CI/reviewers can run them.

pytest practice/ -q
# 34 passed, m6 not mentioned

pytest practice/m6_web_scraping/ -q
# no tests ran (wrong file name)

pip install beautifulsoup4 requests
pytest practice/m6_web_scraping/tests.py -q
# only then tests are found (if deps installed)

Comment thread practice/m6_web_scraping/tests.py Outdated
Comment on lines +13 to +16
def test_scrap_invalid_catalog_page():
scraper = BookScraper()
with pytest.raises(InvlaidURLScrapingException):
books_raw = scraper.scrap_multiple_catalog_pages(999, 1000)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m6 pagination test hits the real network

This calls the live site twice (pages 999 and 1000) with no mock. Slow, flaky, and not a unit test. Mock requests.get and assert the custom exception on 404.

Steps to reproduce:

pip install beautifulsoup4 requests
pytest practice/m6_web_scraping/tests.py::test_scrap_invalid_catalog_page -v
# Makes real HTTP requests to books.toscrape.com (pages 999 and 1000)

Comment on lines +23 to +24
def scrap_catalog_page(self, page_nr):
url = self.catalog_page_url_templeate.substitute(page_nr=page_nr)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m6 README asks for try/except on HTTP errors; scraper only branches on status codes

README says catch 404, 500, timeouts with try/except so the pipeline does not crash. No timeout= on requests.get, no handling of requests.RequestException, no try/except block. A timeout or connection error will still blow up the whole run.

print(DATA_DIR)


def concat_files(data_dir, res_file):

@ejanikWork ejanikWork Jun 29, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side effects at import time / debug prints left in committed code

Importing or running these modules has side effects (prints, file writes). Debug prints should be under if name == "main": or removed before commit.

Steps to reproduce:

python3 -c "import practice.m2_python_part_2.task_read_write"
# Prints DATA_DIR path and result string; rewrites result.txt

python3 -c "import practice.m2_python_part_2.task_read_write_2"
# Regenerates file1.txt and file2.txt

Comment thread practice/m1_python_part_1/task6.py Outdated
temp_max = max(temp_max,int(line))
return (temp_min,temp_max)

print(get_min_max('practice/1_python_part_1/data6.txt'))

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

task6 still points at old directory name

Dirs were renamed to m1_python_part_1 in commit 64df738. This path is stale and breaks if you run the file as-is.

Steps to reproduce:

cd /path/to/repo/root
python practice/m1_python_part_1/task6.py
# FileNotFoundError: practice/1_python_part_1/data6.txt

Comment thread practice/m1_python_part_1/task3.py Outdated
Comment on lines +19 to +27
res = ''
for line in lines:
tab = line.split()
unique_words = []
for word in tab:
if word not in unique_words:
unique_words.append(word)
if len(unique_words) > word_number:
res+= unique_words[word_number] + ' '

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build_from_unique_words returns trailing space

Docstring example is 'b 2 dog', implementation returns 'b 2 dog ' (trailing space). Doctest would catch this.

python3 -c "
from practice.m1_python_part_1.task3 import build_from_unique_words
r = build_from_unique_words('a b c', '1 1 1 2 3', 'cat dog milk', word_number=1)
print(repr(r))           # 'b 2 dog '
print(repr('b 2 dog'))   # expected
print(r == 'b 2 dog')    # False
"

Comment thread practice/m6_web_scraping/pipeline.py Outdated
print()


# AI MADE

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Remove the marker. If AI helped with formatting, that is fine, but shouldn't really be left after making sure the code is understood and person committing is willing to be responsible for it. As per IBM manual: machine can never be held accountable, so while devs are and should use AI properly as a tool, they should understand how it influences the scope of their work (said responsibility).

RES_FILE = CURR_DIR / "result.xml"


def processCity(data: str) -> str:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: PEP8 and naming (task explicitly asked for it in m2)

processCity / citiesData should be snake_case. standarize -> standardize, acs -> asc. reviewDict -> RATING_MAP or similar. m2 docstring says "PEP8 comply strictly.

also in practice/m6_web_scraping/pipeline.py (lines 15, 18, 31)

import time


class InvlaidURLScrapingException(Exception):

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Typos in public names

Invalid, template, standardize. Typos in exception and attribute names are harder to fix later.

@ejanikWork

Copy link
Copy Markdown
Author

Minor style issues carried across modules

Files: practice/m2_python_part_2/task_input_output.py (line 20), practice/m4_python_part_3/task_3.py (line 17), practice/m2_python_part_2/task_read_write_2.py (line 29)

    sum = 0
def is_http_domain(domain: str) -> bool:
    ...
    pattern = r"^https?://.+\.[a-zA-Z]+/?$"
CURR_DIRR = Path(__file__).parent

Do not shadow sum. Remove stray ... from skeleton. Fix CURR_DIRR typo. Use assert homework.is_active() instead of == True in tests.

@ejanikWork

Copy link
Copy Markdown
Author

after running the repo, file1.txt and file 2.txt shows up in git diff

@ejanikWork

Copy link
Copy Markdown
Author

General issues

# Issue Severity
G2 Logging spec largely unmet. Assignment requires logging for all steps, logging.error before exit, start/finish messages for generation. Code mostly uses print() / print(..., file=sys.stderr). logging.warning is used in two places but logging.basicConfig() is never called, so those warnings may not appear depending on config. High
G3 "No traceback / no raise" rule violated. prepare_output_directory can raise FileExistsError when path_to_save_files points to an existing file. create_file raises OutputDirectoryNotPrepared, which surfaces as a worker traceback under multiprocessing. High
G4 Required multiprocessing module not used. Spec lists multiprocessing as required; implementation uses concurrent.futures.ProcessPoolExecutor. Functionally fine, but not what was asked. Medium

Comment thread capstone/data_generation.py Outdated
Comment on lines +51 to +54
output_files = [
output_dir_path / f"{output_dir_path}" / f"{file_name}_{prefixes[i]}.jsonl"
for i in range(files_to_create)
]

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This accidentally works for absolute paths (pathlib discards the left side when the next segment is absolute), but for relative paths you get a doubled directory, e.g. ./outout/out/data_1.jsonl. That can make create_file fail or write files somewhere unexpected. Tests only use resolved absolute paths, so this bug is hidden.

try

output_files = [
    output_dir_path / f"{file_name}_{prefixes[i]}.jsonl"
    for i in range(files_to_create)
]

del_count += 1
print(f"INFO: Deleted {del_count} files from {output_dir_path}")
else:
output_dir_path.mkdir(parents=True, exist_ok=True)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no check when path exists but is not a directory (this + capstone/arguments_cleaning.py:108-113

As per spec: "If path exist and it is not a directory - exit with error log." If /tmp/foo.txt already exists as a file, mkdir raises FileExistsError and the user sees a full traceback — opposite of the assignment rules.

Console utilities should fail gracefully with a clear message and sys.exit(1).

Comment on lines +100 to +102
if not output_path.parent.exists():
raise OutputDirectoryNotPrepared(
"You probably forgot to run prepare_output_directory function before creating files"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

raise in worker process

Spec explicitly says not to use raise for errors that should exit the utility. In multiprocessing this prints a traceback from the worker and is only caught generically in perform_file_generation — the main process still exits 0.

Log the error, return a failure indicator, and have the orchestrator call sys.exit(1) if any worker fails — or validate paths before spawning workers so this branch is unreachable.

Comment thread capstone/data_generation.py Outdated
Comment on lines +146 to +147
except Exception as e:
print(f"ERROR: Worker crashed with error: {e}", file=sys.stderr)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worker failure does not exit with error code

Worker crash is printed but the program continues and exits successfully. Spec: errors → logging.error → exit.

more like

logging.error("Worker crashed: %s", e)
sys.exit(1)

Comment thread capstone/model.py Outdated
data_schema: Dict[str, str]
data_lines: int = Field(ge=0)
clear_path: bool = False
multiprocessing: int = Field(g=0)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo Field(g=0) instead of Field(ge=1)

g is not a valid Pydantic constraint (pytest emits PydanticDeprecatedSince20 warning; the g is ignored). Validation only happens in @field_validator("multiprocessing"), so behavior works today, but the model declaration is misleading and will break on Pydantic v3.

Comment thread capstone/data_generation.py Outdated
if item.is_file() and item.name.startswith(file_name):
item.unlink()
del_count += 1
print(f"INFO: Deleted {del_count} files from {output_dir_path}")

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logging use print, not logging

Assignment wants logging for all steps. INFO: string prefix mimics logging but bypasses the required module.

Configure once at startup (logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")) and replace print("INFO: ...") / stderr prints for errors with logging.info / logging.error.

In general also the convention is that if we are working with multiple modules/files, logging is much better for tracing wth is happening.

Additionally: check out loguru (overkill for this project but extremely cool logging setup module )

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also in a lot of other places errors and infos use print, not logging.error, please take a look to use logging rather than print

Comment thread capstone/data_generation.py Outdated
case "uuid":
prefixes = [str(uuid.uuid4()) for _ in range(files_to_create)]
output_files = [
output_dir_path / f"{output_dir_path}" / f"{file_name}_{prefixes[i]}.jsonl"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single-file naming does not match spec

Spec: one file → file_name.json (no prefix). Implementation always uses file_name_{prefix}.jsonl, so files_count=1 produces export_1.jsonl instead of export.jsonl.

Verified manually: --files_count 1 --file_name singlesingle_1.jsonl.

should be if-else

Comment thread capstone/data_generation.py Outdated
import sys
import time
import uuid
from concurrent.futures import ProcessPoolExecutor, as_completed

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required libraries list includes multiprocessing. ProcessPoolExecutor is a valid modern choice but graders may check imports.

as per spec I'd try to follow it closely as it might be what the professor would be looking for

Comment thread capstone/arguments_cleaning.py
Comment thread capstone/default.ini


# Console Worker (not worker anymore but lets keep it that way)
def print_schema_to_console(data_schema: Dict[str, str], num_of_lines: int) -> str:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no test for files_count == 0 (console output mode). Spec requires this behavior explicitly. Implementation exists (print_schema_to_console) but isn't tested.

Manual run works; automated coverage would catch regressions

Comment thread capstone/test_app.py
]


def test_perform_file_generation(temp_output_dir, clean_args_factory):

@ejanikWork ejanikWork Jul 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checks file count, not data_lines per file. Spec: "each file must have a number of lines == data_lines".

Comment thread capstone/main.py Outdated

orchestrate_data_generation(clean_args=args_clean)

# TODO somehow make it work with provided dataschemas

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably stale todo

Comment thread capstone/arguments_cleaning.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants