Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python SQLAlchemy Basics Working with SQLAlchemy Create and Read Books

Jonathan Grieve
MOD
Jonathan Grieve
Treehouse Moderator 91,253 Points

TypeError: str is not callable

Morning all. :)

Okay, so I'm having a lot of trouble adding a new record to the SQLAlchemy DB.

Admittedly I've made some minor changes to the code, branching out the scope of the project to "Media" rather than just books and added a couple of new fields.

I actually managed it once, adding the data but all the records came up as null. I think that was because I didn't pass anything in to Media() to the choice 1 code block. After I did that, I've been hitting a TypeError exception and nothing I've tried has fixed it.

This particular error seems to be a particular case that I'm calling a string as a function that therefore nothing can be done with it.

app.py
# import models
from models import (Base, session, Media, engine)

# application imports 
import datetime
import csv


# To display the menu options to the console
def menu():
    while True:
        print('''
            \nMEDIA LIBRARY MENU
            \r1) Add Item
            \r2) View All Books
            \r3) Search Media Item
            \r4) Media Item
            \r5) Exit the Application ''') 

        # store a variable for the menu choice
        choice = input('What would you like to do? ')
        if choice in ['1','2','3','4','5']:
            return choice
        else:
            input('''
                    \rError: Please try again with one of the choices above
                    \rA number from 1 to 5.
                    \rPress Enter to Try Again. ''')


# date field data cleaning and type conversion
def clean_date(date_string):

    months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

    # split and convert date format into usable data
    split_date = date_string.split(" ")
    print(split_date)

    try:

        # convert date digits to integer objects
        month = int(months.index(split_date[0]) + 1)
        day = int(split_date[1].split(',')[0])
        year = int(split_date[2])

        print(day)
        print(month)
        print(year)

        return_date = datetime.date(year, month, day)

    except ValueError:
        input("""
        \n*******eError message. invalid date format:    
        \nUse date format: February 22, 2021
        \n*******
        """)
        return

    else: 
        return return_date


# price field - conversion to integer data type
def clean_price(price_str):

    try:        
        price_float = float(price_str)

    except ValueError:
        input("""Error: price format

        \n\nPrice Format Example: $00.00
        """)

    else:

        # print(price)
        return int(price_float * 100)



# import 
def import_csv():
    with open('media_list.csv') as csvfile:
        data = csv.reader(csvfile)

        # display data in the console
        for row in data:
            print(row)

            media_title = row[0]
            media_type = row[1]
            artist = row[2]
            genre = row[3]
            published_date = clean_date(row[4])
            price = clean_price(row[5])


            new_media = Media(
                media_title=media_title,            
                media_type=media_type, 
                artist=artist, 
                genre=genre, 
                published_date=published_date, 
                price=price
            )

            session.add(new_media)
            session.commit()


# To keep the application running until user exit
def app():

    app_running = True

    while app_running:

        choice = menu()

        if choice == '1':

            # add book/media
            title=input('Media Title:  ')
            type=input('Media Type:  ')
            author=input('Media Author: ')
            genre=input('Genre: ')


            date_error = True
            while date_error:
                date = input('Published Date (Exmp) ')
                date = clean_date(date)

                if type(date) == datetime.date:
                    date_error = False 


            price_error = True
            while price_error:
                price = input('Price (Exmp) ')
                price = clean_price(price)

                if type(price) == int:
                    price_error = False


            # add data to db
            new_media_add = Media(
                media_title=title,            
                media_type=type, 
                artist=author, 
                genre=genre, 
                date=date, 
                price=price
            )

            session.add(new_media_add)
            session.commit()


        elif choice == '2':
            # view book 
            pass

        elif choice == '3':
            # view book 
            pass

        elif choice == '4':
            # analyse - media item details
            pass

        else:             
            # default option to exit the application 
            print('\n\nGOODBYE')
            app_running = False


# Create the Database
if __name__  == '__main__':
    Base.metadata.create_all(engine)

    # call app functions
    # clean_date("June 28, 2021")
    # clean_price("33.33")
    # import_csv()
    app()

    for media in session.query(Media):
        print(media)
models.py
## create a database

# Declare the imports
from sqlalchemy import (create_engine, Column, Integer, String, Date)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker


## create a model

# Setup DB for creation
engine = create_engine('sqlite:///media.db', echo=False)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()


# Setup the database schema  media_ title, author, date published, price
class Media(Base):
    __tablename__ = 'media'

    id= Column(Integer, primary_key=True)
    media_title = Column('Media Title', String)
    media_type = Column('Media Type', String)
    artist = Column('Author/Creator', String)
    genre = Column('Genre', String)
    published_date = Column('Published', Date)
    price = Column('Price', Integer)

    # Display string of data in console - formatted string
    def __repr__(self):
        return f'\n\nMedia Title: {self.media_title} \nMedia Type: {self.media_type} \nArtist: {self.artist} \nGenre: {self.genre} \nPublished Date: {self.published_date} \nPrice: {self.price}' 

1 Answer

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,253 Points

Thanks for that but I don't think that's quite the issue. I should have specified the stacktrace

Traceback (most recent call last):
  File "C:\<snip>\python\flask\sqlalchemy\cli_app\app.py", line 190, in <module>
    app()
  File "C:\<snip>python\flask\sqlalchemy\cli_app\app.py", line 137, in app
    if type(date) == datetime.date:
TypeError: 'str' object is not callable

It seems to be an issue with the datetime object

Megan Amendola
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Megan Amendola
Treehouse Teacher

Ah ok I think I see what happened. Inside of your app function towards the top, you created a variable called 'type' which is overriding the python type function so it's no longer a function and is instead a string.

# add book/media
    title=input('Media Title:  ')
    # change the variable name here
    type=input('Media Type:  ')
Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,253 Points

Thanks Megan, that did the trick. 😀

I guess I should have stuck to my guns when I googled the error. What I researched was exactly what was happening. The trouble is it's so much harder to spot when there aren't actually any syntax errors