News feed python script The task: user-generated news feed:

User select what data type he wants to add

Provide record type required data

Record is published on text file in special format


Types of data:

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

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

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(&quot;all_news.txt&quot;, &quot;a&quot;) 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&quot;{self.title}{(self.line_width - len(self.title)) * '-'}\n&quot;\
               f&quot;{self.text} \n&quot;\
               f&quot;{self.city}, {self.date.strftime('%d/%m/%Y %H:%M:%S')} \n&quot;\
               f&quot;{'-'*self.line_width}\n\n\n&quot;


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&quot;{self.title}{(self.line_width - len(self.title)) * '-'}\n&quot;\
               f&quot;{self.text} \n&quot;\
               f&quot;Actual until: {date(year, month, day).strftime('%d/%m/%Y')}, {days_left} days left \n&quot;\
               f&quot;{'-'*self.line_width}\n\n\n&quot;


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

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


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 == &quot;1&quot;:
        new_news = News(&quot;News&quot;,
                        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 == &quot;2&quot;:
        new_news = Ad(&quot;Private Ad&quot;,
                      input(&quot;Input your text\n&quot;),
                      input('Print endDate of ad in format DD/MM/YEAR\n'), 30)
        new_news.publish_article(new_news.format_text())
    elif user_input == &quot;3&quot;:
        new_news = PersonalNews(input(&quot;Input your title\n&quot;),
                                input(&quot;Input your text\n&quot;), 30)
        new_news.publish_article(new_news.format_text())
    elif user_input == &quot;q&quot;:
        exit(0)
    else:
        print(&quot;Incorrect input. Please enter a number (1, 2, 3) or 'q' for exit&quot;)
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) -&gt; 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&quot;{self.title}{(self.line_width - len(self.title)) * '-'}\n&quot;\
           f&quot;{self.text} \n&quot;\
           f&quot;{self.city}, {self.date.strftime('%d/%m/%Y %H:%M:%S')} \n&quot;\
           f&quot;{'-'*self.line_width}\n\n\n&quot;

to drop the backslashes and use parens instead:
    return (
        f&quot;{self.title}{(self.line_width - len(self.title)) * '-'}\n&quot;
        f&quot;{self.text} \n&quot;
        f&quot;{self.city}, {self.date.strftime('%d/%m/%Y %H:%M:%S')} \n&quot;
        f&quot;{'-'*self.line_width}\n\n\n&quot;
    )

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.