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")
Ben A
10.7k5 gold badges37 silver badges101 bronze badges
asked Feb 12, 2021 at 12:15
\$\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.

answered Feb 13, 2021 at 0:26
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.