3
\$\begingroup\$

The task: user-generated news feed:

  1. User select what data type he wants to add

  2. Provide record type required data

  3. Record is published on text file in special format

Types of data:

  1. News – text and city as input. Date is calculated during publishing.

  2. Private ad – text and expiration date as input. Day left is calculated during publishing.

  3. Your unique one with unique publish rules.

Expected result:

News -------------------------
Something happened
London, 03/01/2021 13.45
------------------------------


News -------------------------
Something other happened
Minsk, 24/01/2021 20.33
------------------------------


Private Ad ------------------
I want to sell a bike
Actual until: 01/03/2021, 21 days left
------------------------------


Joke of the day ------------
Did you hear about the claustrophobic astronaut?
He just needed a little space
Funny meter – three of ten
------------------------------


My code:

from datetime import datetime, date
from sys import exit


class Article:
    def __init__(self, title, text, line_width):
        self.title = title
        self.text = text
        self.line_width = line_width

    @staticmethod
    def publish_article(formatted_text):
        with open("all_news.txt", "a") as file:
            file.write(formatted_text)


class News(Article):
    def __init__(self, title, text, city, date, line_width):
        Article.__init__(self, title, text, line_width)
        self.city = city
        self.date = date

    def format_text(self):
        return f"{self.title}{(self.line_width - len(self.title)) * '-'}\n"\
               f"{self.text} \n"\
               f"{self.city}, {self.date.strftime('%d/%m/%Y %H:%M:%S')} \n"\
               f"{'-'*self.line_width}\n\n\n"


class Ad(Article):
    def __init__(self, title, text, end_date, line_width):
        Article.__init__(self, title, text, line_width)
        self.end_date = end_date

    def format_text(self):
        day, month, year = map(int, self.end_date.split('/'))
        days_left = (date(year, month, day) - date.today()).days
        return f"{self.title}{(self.line_width - len(self.title)) * '-'}\n"\
               f"{self.text} \n"\
               f"Actual until: {date(year, month, day).strftime('%d/%m/%Y')}, {days_left} days left \n"\
               f"{'-'*self.line_width}\n\n\n"


class PersonalNews(Article):
    def __init__(self, title, text, line_width):
        Article.__init__(self, title, text, line_width)

    def format_text(self):
        return f"{self.title}{(self.line_width - len(self.title)) * '-'}\n"\
               f"{self.text} \n"\
               f"{'-'*self.line_width}\n\n\n"


while True:
    user_input = input('Enter a number: '
                       '1 - Publish news;\n'
                       '2 - Publish ad; \n'
                       '3 - Publish personal news\n'
                       'q - Exit\n')
    if user_input == "1":
        new_news = News("News",
                        input('Print your text\n'),
                        input('Print city for the news\n'), datetime.now(), 30)
        new_news.publish_article(new_news.format_text())
    elif user_input == "2":
        new_news = Ad("Private Ad",
                      input("Input your text\n"),
                      input('Print endDate of ad in format DD/MM/YEAR\n'), 30)
        new_news.publish_article(new_news.format_text())
    elif user_input == "3":
        new_news = PersonalNews(input("Input your title\n"),
                                input("Input your text\n"), 30)
        new_news.publish_article(new_news.format_text())
    elif user_input == "q":
        exit(0)
    else:
        print("Incorrect input. Please enter a number (1, 2, 3) or 'q' for exit")
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Shadowing

Your date parameter to the constructor of News is poorly-named, because it shadows the built-in date that you've imported from datetime.

Super

Your call to Article.__init__() should use super() instead.

Data classes

Article can just be a @dataclass with its explicit __init__ removed.

Static methods

publish_article doesn't make sense as a static method. In your invocations, you're always calling format_text() on a child instance, then passing that to a static method on the parent. Instead:

  • Define format_text(self) -> str: raise NotImplementedError() on Article to declare it abstract
  • Change publish_article(self) to simply file.write(self.format_text())

Backslash continuation

Change this:

    return f"{self.title}{(self.line_width - len(self.title)) * '-'}\n"\
           f"{self.text} \n"\
           f"{self.city}, {self.date.strftime('%d/%m/%Y %H:%M:%S')} \n"\
           f"{'-'*self.line_width}\n\n\n"

to drop the backslashes and use parens instead:

    return (
        f"{self.title}{(self.line_width - len(self.title)) * '-'}\n"
        f"{self.text} \n"
        f"{self.city}, {self.date.strftime('%d/%m/%Y %H:%M:%S')} \n"
        f"{'-'*self.line_width}\n\n\n"
    )

Date parsing

This is evil:

    day, month, year = map(int, self.end_date.split('/'))

Instead, you should be using an actual parsing method out datetime to get you a date instance; then referring to its members. Since you're looking for DD/MM/YEAR, this will be:

end_date = datetime.strptime(self.end_date, '%d/%m/%Y').date()
# Use end_date.day, end_date.month, end_date.year

That said, if you're at all able, drop that date format like a sack of rotten potatoes. YYYY-mm-dd is sortable and unambiguous.

\$\endgroup\$
0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.