synchronization inspirations between entries and inspirations list
This commit is contained in:
@ -2,92 +2,110 @@
|
||||
Maintenance of inspirations.md and synchronization with the inspirations in the entries.
|
||||
"""
|
||||
|
||||
import time
|
||||
from utils import constants as c, utils, osg, osg_ui
|
||||
from utils import osg_wikipedia
|
||||
from utils import osg, osg_ui
|
||||
|
||||
valid_duplicates = ('Age of Empires', 'ARMA', 'Catacomb', 'Civilization', 'Company of Heroes', 'Descent', 'Duke Nukem', 'Dungeon Keeper',
|
||||
'Final Fantasy', 'Heroes of Might and Magic', 'Jazz Jackrabbit', 'Marathon', 'Master of Orion', 'Quake',
|
||||
'RollerCoaster Tycoon', 'Star Wars Jedi Knight', 'The Settlers', 'Ultima', 'Ship Simulator')
|
||||
|
||||
def check_for_duplicates():
|
||||
"""
|
||||
class InspirationMaintainer:
|
||||
|
||||
:param inspirations:
|
||||
:return:
|
||||
"""
|
||||
print('\nduplicate check')
|
||||
inspiration_names = [x['name'] for x in inspirations]
|
||||
for index, name in enumerate(inspiration_names):
|
||||
for other_name in inspiration_names[index+1:]:
|
||||
if osg.name_similarity(name, other_name) > 0.8:
|
||||
print(' {} - {} is similar'.format(name, other_name))
|
||||
def __init__(self):
|
||||
self.inspirations = None
|
||||
self.entries = None
|
||||
|
||||
def test():
|
||||
# assemble info
|
||||
t0 = time.process_time()
|
||||
entries = osg.read_entries()
|
||||
print('took {}s'.format(time.process_time()-t0))
|
||||
t0 = time.process_time()
|
||||
# entries = osg.assemble_infos()
|
||||
# osg.write_entries(entries)
|
||||
print('took {}s'.format(time.process_time()-t0))
|
||||
def read_inspirations(self):
|
||||
self.inspirations = osg.read_inspirations()
|
||||
print('{} inspirations read'.format(len(self.inspirations)))
|
||||
|
||||
def write_inspirations(self):
|
||||
if not self.inspirations:
|
||||
print('inspirations not yet loaded')
|
||||
return
|
||||
osg.write_inspirations(self.inspirations)
|
||||
print('inspirations written')
|
||||
|
||||
# assemble inspirations info from entries
|
||||
entries_inspirations = {}
|
||||
for entry in entries:
|
||||
entry_name = entry['name']
|
||||
keywords = entry['keywords']
|
||||
entry_inspirations = [x for x in keywords if x.startswith('inspired by')]
|
||||
if entry_inspirations:
|
||||
entry_inspirations = entry_inspirations[0][len('inspired by'):]
|
||||
entry_inspirations = entry_inspirations.split('+')
|
||||
entry_inspirations = [x.strip() for x in entry_inspirations]
|
||||
for entry_inspiration in entry_inspirations:
|
||||
if entry_inspiration in entries_inspirations:
|
||||
entries_inspirations[entry_inspiration].append(entry_name)
|
||||
def check_for_duplicates(self):
|
||||
if not self.inspirations:
|
||||
print('inspirations not yet loaded')
|
||||
return
|
||||
inspiration_names = list(self.inspirations.keys())
|
||||
for index, name in enumerate(inspiration_names):
|
||||
for other_name in inspiration_names[index + 1:]:
|
||||
if any((name.startswith(x) and other_name.startswith(x) for x in valid_duplicates)):
|
||||
continue
|
||||
if osg.name_similarity(name, other_name) > 0.8:
|
||||
print(' {} - {} is similar'.format(name, other_name))
|
||||
print('duplicates checked')
|
||||
|
||||
def check_for_orphans(self):
|
||||
if not self.inspirations:
|
||||
print('inspirations not yet loaded')
|
||||
return
|
||||
for inspiration in self.inspirations.values():
|
||||
if not inspiration['inspired entries']:
|
||||
print(' {} has no inspired entries'.format(inspiration['name']))
|
||||
print('orphanes checked')
|
||||
|
||||
def check_for_missing_inspirations_in_entries(self):
|
||||
if not self.inspirations:
|
||||
print('inspirations not yet loaded')
|
||||
return
|
||||
if not self.entries:
|
||||
print('entries not yet loaded')
|
||||
return
|
||||
for inspiration in self.inspirations.values():
|
||||
inspiration_name = inspiration['name']
|
||||
for entry_name in inspiration['inspired entries']:
|
||||
x = [x for x in self.entries if x['title'] == entry_name]
|
||||
assert len(x) <= 1
|
||||
if not x:
|
||||
print('Entry "{}" listed in inspiration "{}" but this entry does not exist'.format(entry_name, inspiration_name))
|
||||
else:
|
||||
entries_inspirations[entry_inspiration] = [ entry_name ]
|
||||
print('{} inspirations in the entries'.format(len(entries_inspirations)))
|
||||
entry = x[0]
|
||||
if 'inspirations' not in entry or inspiration_name not in entry['inspirations']:
|
||||
print('Entry "{}" listed in inspiration "{}" but not listed in this entry'.format(entry_name, inspiration_name))
|
||||
print('missed inspirations checked')
|
||||
|
||||
# first check if all inspiration in entries are also in inspirations
|
||||
inspiration_names = [x['name'] for x in inspirations]
|
||||
for inspiration, entries in entries_inspirations.items():
|
||||
if inspiration not in inspiration_names:
|
||||
print('new inspiration {} for games {}'.format(inspiration, ', '.join(entries)))
|
||||
similar_names = [x for x in inspiration_names if osg.name_similarity(inspiration, x) > 0.8]
|
||||
if similar_names:
|
||||
print(' similar names {}'.format(', '.join(similar_names)))
|
||||
def update_inspired_entries(self):
|
||||
if not self.inspirations:
|
||||
print('inspirations not yet loaded')
|
||||
return
|
||||
if not self.entries:
|
||||
print('entries not yet loaded')
|
||||
return
|
||||
# loop over all inspirations and delete inspired entries
|
||||
for inspiration in self.inspirations.values():
|
||||
inspiration['inspired entries'] = []
|
||||
# loop over all entries and add to inspirations of entry
|
||||
for entry in self.entries:
|
||||
entry_name = entry['title']
|
||||
for inspiration in entry.get('inspirations', []):
|
||||
if inspiration in self.inspirations:
|
||||
self.inspirations[inspiration]['inspired entries'].append(entry_name)
|
||||
else:
|
||||
self.inspirations[inspiration] = {'name': inspiration, 'inspired entries': [entry_name]}
|
||||
print('inspired entries updated')
|
||||
|
||||
# now the other way around
|
||||
for index, name in enumerate(inspiration_names):
|
||||
if name not in entries_inspirations:
|
||||
print('potential removed inspiration {} from games {}'.format(name, inspirations[index]['inspired entries']))
|
||||
similar_names = [x for x in entries_inspirations.keys() if osg.name_similarity(name, x) > 0.8]
|
||||
if similar_names:
|
||||
print(' similar names {}'.format(', '.join(similar_names)))
|
||||
def read_entries(self):
|
||||
self.entries = osg.read_entries()
|
||||
print('{} entries read'.format(len(self.entries)))
|
||||
|
||||
|
||||
def read_inspirations():
|
||||
inspirations = osg.read_inspirations_info()
|
||||
print('{} inspirations in the inspirations database'.format(len(inspirations)))
|
||||
|
||||
def write_inspirations():
|
||||
osg.write_inspirations_info(inspirations)
|
||||
print('inspirations written')
|
||||
|
||||
if __name__ == "__main__":
|
||||
inspirations = osg.read_inspirations_info()
|
||||
osg.write_inspirations_info(inspirations)
|
||||
|
||||
inspirations = None
|
||||
entries = None
|
||||
m = InspirationMaintainer()
|
||||
|
||||
actions = {
|
||||
'Read inspirations': read_inspirations,
|
||||
'Write inspirations': write_inspirations,
|
||||
'Check for duplicates': check_for_duplicates,
|
||||
'Read inspirations': m.read_inspirations,
|
||||
'Write inspirations': m.write_inspirations,
|
||||
'Check for duplicates': m.check_for_duplicates,
|
||||
'Check for orphans': m.check_for_orphans,
|
||||
'Check for inspirations not listed': m.check_for_missing_inspirations_in_entries,
|
||||
'Update inspirations from entries': m.update_inspired_entries,
|
||||
'Read entries': m.read_entries
|
||||
}
|
||||
|
||||
|
||||
osg_ui.run_simple_button_app('Maintenance inspirations', actions)
|
||||
|
||||
|
||||
|
@ -476,7 +476,7 @@ def write_developer_info(developers):
|
||||
utils.write_text(developer_file, content)
|
||||
|
||||
|
||||
def read_inspirations_info():
|
||||
def read_inspirations():
|
||||
"""
|
||||
Reads the info list about the games originals/inspirations from inspirations.md using the Lark parser grammar
|
||||
in grammar_listing.lark
|
||||
@ -508,17 +508,23 @@ def read_inspirations_info():
|
||||
duplicate_names = (name for name in names if names.count(name) > 1)
|
||||
duplicate_names = set(duplicate_names) # to avoid duplicates in duplicate_names
|
||||
if duplicate_names:
|
||||
print('Warning: duplicate inspiration names: {}'.format(', '.join(duplicate_names)))
|
||||
raise RuntimeError('Duplicate inspiration names: {}'.format(', '.join(duplicate_names)))
|
||||
|
||||
# convert to dictionary
|
||||
inspirations = {x['name']: x for x in inspirations}
|
||||
|
||||
return inspirations
|
||||
|
||||
|
||||
def write_inspirations_info(inspirations):
|
||||
def write_inspirations(inspirations):
|
||||
"""
|
||||
Given an internal list of inspirations, write it into the inspirations file
|
||||
Given an internal dictionary of inspirations, write it into the inspirations file
|
||||
:param inspirations:
|
||||
:return:
|
||||
"""
|
||||
# convert dictionary to list
|
||||
inspirations = list(inspirations.values())
|
||||
|
||||
# comment
|
||||
content = '{}\n'.format(generic_comment_string)
|
||||
|
||||
@ -544,7 +550,7 @@ def write_inspirations_info(inspirations):
|
||||
field = field.capitalize()
|
||||
# lists get special treatment
|
||||
if isinstance(value, list):
|
||||
value.sort(key=str.casefold)
|
||||
value.sort(key=str.casefold) # sorted alphabetically
|
||||
value = [x if not ',' in x else '"{}"'.format(x) for x in value] # surround those with a comma with quotation marks
|
||||
value = ', '.join(value)
|
||||
content += '- {}: {}\n'.format(field, value)
|
||||
|
@ -2,9 +2,17 @@
|
||||
Simple UI helpers with PyQt
|
||||
"""
|
||||
|
||||
import sys
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
def exception_hook(type, value, traceback):
|
||||
"""
|
||||
Use sys.__excepthook__, the standard hook.
|
||||
"""
|
||||
sys.__excepthook__(type, value, traceback)
|
||||
|
||||
|
||||
def run_simple_button_app(title, actions):
|
||||
"""
|
||||
|
||||
@ -12,6 +20,9 @@ def run_simple_button_app(title, actions):
|
||||
:param actions:
|
||||
:return:
|
||||
"""
|
||||
# fix PyQt5 eating exceptions (see http://stackoverflow.com/q/14493081/1536976)
|
||||
sys.excepthook = exception_hook
|
||||
|
||||
# create app
|
||||
app = QtWidgets.QApplication([])
|
||||
|
||||
|
Reference in New Issue
Block a user