Search code examples
pythondictionaryyield

Storing the values produced by a generator for multiple uses


I am developing a program that will check the user's hard drives for games and display a list of all the games installed on the computer with the relative names and paths.

I achieved this by creating a database in JSON that contains for each game the name and the paths(The program runs on linux and windows so there are 4 values in database: name, windows_path, windows_steam_path, linux_path, linux_steam_path) *Steam paths are to check if the game uses steam cloud

"name",
    "Windows_path",
    "Windows_steam_path",
    "Linux_path",
    "Linux_sync_path"

I also needed a "Template" for each game so I created a class for them

class Game():
    def __init__(self, game_name, game_path, sync_path):
        self.name = game_name
        self.path = game_path
        self.sync_path = sync_path
    def to_dict(self):
        self.name
        self.path
        self.sync_path
        return {"name": self.name, "path": self.path, "sync_path": self.sync_path}

And I also needed an user interface Eel - https://github.com/ChrisKnott/Eel

Eel hosts a local webserver so I'll use HTML files to display content

<nav class="navbar navbar-expand-lg navbar-light bg-dark" Style="display:block; height:50px">
  <a href="../index.html" class="btn btn-info float-left">Home</a>
  <a href="userGuide.html" class="btn btn-info float-right">User Guide</a>
</nav>

<div id="game_database" class="row"></div>

Now I get the data from the database like so

save_database = json.load(open("database.json"))

def load_game(db_item):
    current_os = platform.system()
    path = ""
    sync_path = ""
    [name, win_path, win_sync, lin_path, lin_sync] = db_item
    if current_os == "Windows":
        sync_path = win_sync
        path = win_path
        print(path, sync_path)
    else:
        sync_path = lin_sync
        path = lin_path
        print(path, sync_path)
    print(Game(name, os.path.expanduser(path), os.path.expanduser(sync_path)))
    return Game(name, os.path.expanduser(path), os.path.expanduser(sync_path))

save_database = map(load_game, save_database)

And pass the data into a dictionary

def get_all_in_database():
for game in save_database:
    game_dict = game.to_dict()
    yield game_dict

And then I used lodash to create a template and javascript and jquery to modify the html and call the python functions (I am not posting that code here since this is already pretty big question)

When I go to my desired page it calls the javascript function that calls all the other functions and sends the data through the templates, etc. Everything works fine, but only once.

It should display the games if I refresh the page or call the function again but it doesn't; all it gives me is an empty list [] since when I expose the function to javascript I list(it))

[{'name': 'Portal 2', 'path': 'NFL', 'sync_path': '~./steam/steam/userdata/XXXXX/game/remote/'}]
Listing games
[]

I searched around and asked some friends and, found out that yield is a generator and only iterates through the values once and it's non-reusable so I guess it has to do with that but I also want to be able to generate the values on the fly and "keep" them for later use so I'm currently kind of lost on how to proceed due to my limited knowledge of python and programming in general


Solution

  • So thanks to a friend of mine I found the answer to my own question (Applause to fabiosantoscode - https://github.com/fabiosantoscode)

    As you can see when I import the database from json on the end I do

    save_database = map(load_game, save_database)
    

    And map is a generator soooo if i would have just

    save_database = list(map(load_game, save_database))
    

    I wouldn't have had to bang my head on the walls for 3 consecutive days lol

    thanks to everyone for the attention!!