Print a sentence with placeholder and function from an external file. Problem with importing forms, using and retrieving content

Question:

I made a program that prints some text in a sentence with two placeholders. When the user selects a tournament name from the left-hand combobox and a team name from the right-hand combobox, a template string is filled in with those values and written in the bottom text field. It looks like:

I was able to get this working with all the code in a single file. Now I am trying to organize the code into three separate Python files, thus:

  • Main.py: Contains the main code; accesses the template string from Template.py
  • Template.py: Contains the template string that will be filled out; calls the getArticle function from Grammar.py and also gets the team name from Main.py (by checking the combobox contents)
  • Grammar.py: provides getArticle, which uses dictionaries from Main.py to determine the article that should appear before the team name

PROBLEM Now when I start the program, I get the error:

AttributeError: partially initialized module ‘Template’ has no attribute ‘test_template’ (most likely due to a circular import).

I tried fixing this by moving an import into a function to defer it; but then subject = team.get() still does not work in Template.py.

HOW DOES MY CODE WORK? I select the element in the first combobox (for example Serie A), then I select the element of the second combobox (for example Atalanta). Then I click on Print. When I click on Print the purpose is to print test_template = f "Bla bla bla {article} {subject}". Subject is the second combobox (for example Atalanta). Article is selected by means of the GetArticle function and dictionaries. This function is used to understand which article to print in relation to the subject. When I had all the code in one file, it worked fine.

How can I print test_template in Main.py, while altering the code structure as little as possible? I specifically want to keep using three files, with test_template being located in Template.py and getArticle being in Grammar.py.

NOTE 1: Possibly, I don’t need the sentence to be the return of a function, because my code is an example, but I will have to use hundreds of sentences, so I need a lot of variables (such as example test_template in my code). I would like to use test_template1 as I did in my code. If you really need the function, then know that in the future I will have to use many "random" variables (test_template1, test_template2, test_template3, etc.) and so I don’t want to use the return only directly in the return row.

I would need a return of test_template (+ e.g. test_template2, test_template3, etc.) that is compatible with using "random" in Main.py, so for example have in Main: random_template_test = random.choice ([test_template, test_template2 , test_template3]).

NOTE 2: Also I need to pass {article} {subject} without distorting the reason too much (obviously modifying a little, but not too much), because then in the future I should also print other placeholders taking them from Main.py and Grammar.py.

For reference, here is the complete code:

Template.py

import Grammar
import Main

test_template = f"Bla bla bla {article} {subject}"

#Subject is created in the Main.py file
#While Article is created in the Grammar.py file
subject = team.get()
article = getArticle(subject)

Grammar.py

import Main

from Main import teams
from Main import article_words
from Main import nouns

#Subject is created in the Main.py file
def getArticle(subject):
    for key, value in article_words.items():
        if nouns[subject] == value:
            return key

Main.py

from tkinter import ttk
import tkinter as tk
from tkinter import *
import Template

root = tk.Tk()
root.geometry("400x150")
   
tournament=ttk.Combobox(root, width = 18)
tournament.place(x=15, y=15)
tournament['value'] = ["Serie A", "Serie B"]
tournament.set("Tournament")

def on_tournament_selected(event):
    # Clear the entry boxes: aggiunto io
    team.delete(0,'end') 
    
    req_teams = [] # For all the required teams
    sel_tournament = tournament.get() # Get the tournament
    
    # get the names for selected gender
    for _team in teams.items(): # Go through all the teams in the dictionary
        key = _team[0] # Get the key
        value = _team[1] # Get the value 
        if value['Tournament'] == sel_tournament: # If Tournament of the loop-ed team is our selected tourname, then 
            req_teams.append(key)
    
    team.config(values=req_teams) # Change the values of the combobox

tournament.bind('<<ComboboxSelected>>', on_tournament_selected)

#############

team=ttk.Combobox(root, width = 18)
team.place(x=200, y=15)
team.set("Teams")

text = tk.Text(root,width=43,height=2)
text.place(x=15, y=50)

def printTeam():
    #here first there was subject and article, then moved to another external file
    
    def articolo1():
        template1 = Template.test_template
        text.insert(tk.END, template1)

    articolo1()

button2 = Button(root, text="Print", command = printTeam)
button2.pack()
button2.place(x=15, y=100)

#DICT
teams = {
            "Atalanta": {
                "Nome Squadra": "Atalanta",
                "Tournament": "Serie A",
        },


            "Bologna": {
                "Nome Squadra": "Bologna",
                "Tournament": "Serie A",
        }
   }
       
nouns = {

        "Atalanta": {"genere" : "femminile", "unità" : "singolare", "apostrofo" : "si"},
        "Bologna": {"genere" : "maschile", "unità" : "singolare", "apostrofo" : "no"},
        }

article_words = {
    
            "del" : {
            "genere" : "maschile",
            "unità" : "singolare",
            "apostrofo": "no"
            },        
                      
            "dell'" : {
            "genere" : "femminile",
            "unità" : "singolare",
            "apostrofo" : "si"
            },                
        }

root.mainloop()
Asked By: Jas_99

||

Answers:

Move the dictionaries in dicts.py and create a class in template.py to return required template.You can create as many templates as you want in templates.py.

dicts.py

teams = {...}
   
nouns = {...}

article_words = {...}

template.py

from grammer import getArticle
import random

class Template():

    def __init__(self,**kwargs):
        self.__dict__.update(kwargs)

        # must define other variables like article which are used
        # in templates irrespective of the arguments passed

        if self.subject:
            self.article = getArticle(subject=self.subject)

    def return_template(self):
        test_template_list = ["Bla bla bla {subject} {article}", "Again bla bla bla {subject}"]
        test_template = random.choice(test_template_list)

        place_holders = ['{subject}','{article}', ]

        for i in place_holders:
            if i in test_template:
                test_template=test_template.replace(i,(self.__dict__[i.lstrip("{").rstrip("}")]))
        
        return test_template

grammer.py

from dicts import article_words, nouns

def getArticle(subject):
    for key, value in article_words.items():
        if nouns[subject] == value:
            return key

main.py

from tkinter import *
from tkinter import ttk
from template import Template
from dicts import teams

root = Tk()
root.geometry("420x150")

tournament=ttk.Combobox(root, width = 18)
tournament.place(x=15, y=15)
tournament['value'] = ["Serie A", "Serie B"]
tournament.set("Tournament")

def on_tournament_selected(event):
    team.delete(0,'end') 

    req_teams = [] 
    sel_tournament = tournament.get() 

    for key,value in teams.items():
        if value['Tournament'] == sel_tournament:
            req_teams.append(key)

    team.config(values=req_teams)

tournament.bind("<<ComboboxSelected>>", on_tournament_selected)

team=ttk.Combobox(root, width = 18)
team.place(x=215, y=15)
team.set("Teams")

text = Text(root,width=43,height=2)
text.place(x=15, y=50)

def printTeam():
    template1 = Template(subject=team.get()) # pass keyword arguments
    text.insert(END, template1.return_template())

button2 = Button(root, text="Print", command = printTeam)
button2.pack()
button2.place(x=15, y=100)

root.mainloop()

The error was due to circular imports in your files.

Answered By: blaze2004
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.