diff --git a/src/gourmand/Undo.py b/src/gourmand/Undo.py index f0c81b23..a9b4fa7a 100644 --- a/src/gourmand/Undo.py +++ b/src/gourmand/Undo.py @@ -67,10 +67,7 @@ def __init__(self, self.reundo_name = reundo_name self.is_undo = is_undo self.widget = widget - if self.get_reapply_action_args: - self.reapplyable = True - else: - self.reapplyable = False + self.reapplyable = bool(self.get_reapply_action_args) self.action_args = action_args def perform (self): @@ -120,8 +117,8 @@ def __init__ (self, set_text_action, history, initial_text="",text="",txt_id=Non def determine_mode(self, current: Optional[str] = "", initial: Optional[str] = "") -> UndoMode: - current = current if current else self.text - initial = initial if initial else self.initial_text + current = current or self.text + initial = initial or self.initial_text if len(current) > len(initial): return UndoMode.ADD @@ -150,7 +147,7 @@ def find_change (self, text2=None, initial_text=None): else: return [len(initial_text),len(text2)-len(initial_text)] - def add_text (self, new_text): + def add_text(self, new_text): mode=self.determine_mode(new_text,self.text) contmode = self.determine_mode(new_text,self.text) if (mode == contmode == self.mode): @@ -159,10 +156,11 @@ def add_text (self, new_text): # there are multiple places where "Too many changes" # could crop up as an error. cindex,clen = self.find_change(new_text) - if ((cindex==self.cindex) or - (self.mode == UndoMode.ADD and cindex == self.cindex) or - (self.mode == UndoMode.DELETE and cindex == self.cindex-clen) - ): + if ( + cindex == self.cindex + or self.mode == UndoMode.DELETE + and cindex == self.cindex - clen + ): if self.mode == UndoMode.ADD: changed_text = new_text[cindex:cindex+(self.clen+clen)] else: changed_text='' @@ -339,7 +337,7 @@ def set (self, val): def get (self): return getattr(self.w,self.get_method)() - def changecb (self,*args): + def changecb(self,*args): if self.im_doing_the_setting: # If we are doing the setting, presumably this is from one # of the Undo objects we created, in which case we don't @@ -348,16 +346,15 @@ def changecb (self,*args): old_val = self.last_value new_val = self.get() if old_val==new_val: return # Ignore redundant changes... - if new_val != old_val: - # We don't perform because we're being called after the action has happened. - # We simply append ourselves to the history list. - u = UndoableObject(lambda *args: self.set(new_val), - lambda *args: self.set(old_val), - self.history, - widget=self.w - ) - self.history.append(u) - self.last_value=new_val + # We don't perform because we're being called after the action has happened. + # We simply append ourselves to the history list. + u = UndoableObject(lambda *args: self.set(new_val), + lambda *args: self.set(old_val), + self.history, + widget=self.w + ) + self.history.append(u) + self.last_value=new_val class UndoableTextView (UndoableTextContainer): def __init__ (self, textview, history): @@ -423,12 +420,12 @@ def undo (self, *args): action.inverse() for h in self.action_hooks: h(self,action,'undo') - def redo (self, *args): + def redo(self, *args): if len(self) == 0: return False index = -1 try: while not self[index].is_undo: - index = index - 1 + index -= 1 except IndexError: debug('All %s available actions are is_undo=False'%len(self),0) print('There is nothing to redo!') @@ -453,7 +450,7 @@ def set_sensitive (self, w: Gtk.Action, is_sensitive: bool): return w.set_sensitive(is_sensitive) - def gui_update (self): + def gui_update(self): debug('gui_update',0) if len(self) >= 1: undoables = [x.is_undo for x in self] @@ -472,11 +469,13 @@ def gui_update (self): if self[-1].reapplyable: debug('Sensitizing "reapply" widgets',0) self.set_sensitive(self.reapply_widget,True) - if self[-1].reapply_name: - if type(self.reapply_widget)==Gtk.MenuItem: - alabel = self.reapply_widget.get_children()[0] - alabel.set_text_with_mnemonic(self[-1].reapply_name) - alabel.set_use_markup(True) + if ( + self[-1].reapply_name + and type(self.reapply_widget) == Gtk.MenuItem + ): + alabel = self.reapply_widget.get_children()[0] + alabel.set_text_with_mnemonic(self[-1].reapply_name) + alabel.set_use_markup(True) else: debug('Nothing to undo, desensitizing widgets',0) self.set_sensitive(self.redo_widget,False) @@ -564,15 +563,14 @@ def reapply (self,*args,**kwargs): return self.get_history().reapply(*args,**kwa def get_all_histories (self): return list(self.histories.values()) - def get_history (self): + def get_history(self): hid=self.get_current_id() - if hid in self.histories: - #debug('Returning history %s for id %s'%([repr(i) for i in self.histories[hid]],hid),0) - return self.histories[hid] - else: + if hid not in self.histories: #debug('Creating new history for id %s'%hid,0) self.histories[hid]=self.make_history() - return self.histories[hid] + + #debug('Returning history %s for id %s'%([repr(i) for i in self.histories[hid]],hid),0) + return self.histories[hid] def make_history (self): uhl = UndoHistoryList(self.undo_widget,self.redo_widget,None,None) diff --git a/src/gourmand/backends/db.py b/src/gourmand/backends/db.py index fcff9e7d..52e00229 100644 --- a/src/gourmand/backends/db.py +++ b/src/gourmand/backends/db.py @@ -86,23 +86,22 @@ def make_simple_select_arg (criteria,*tables): else: return [] -def make_order_by (sort_by, table, count_by=None, join_tables=[]): +def make_order_by(sort_by, table, count_by=None, join_tables=[]): ret = [] for col,direction in sort_by: if col=='count' and not hasattr(table.c,'count'): col = sqlalchemy.func.count(getattr(table.c,count_by)) - else: - if hasattr(table.c,col): - col = getattr(table.c,col) - elif join_tables: - broken = True - for t in join_tables: - if hasattr(t.c,col): - broken = False - col = getattr(t.c,col) - break - if broken: - raise ValueError("No such column for tables %s %s: %s"%(table, join_tables, col)) + elif hasattr(table.c,col): + col = getattr(table.c,col) + elif join_tables: + broken = True + for t in join_tables: + if hasattr(t.c,col): + broken = False + col = getattr(t.c,col) + break + if broken: + raise ValueError("No such column for tables %s %s: %s"%(table, join_tables, col)) if isinstance(col.type, Text): # Sort nulls last rather than first using case statement... col = case([(col == None, '"%s"'%'z'*20), @@ -124,10 +123,9 @@ def db_url(filename: Optional[str]=None, custom_url: Optional[str]=None) -> str: if custom_url is not None: return custom_url - else: - if filename is None: - filename = gglobals.gourmanddir / 'recipes.db' - return 'sqlite:///' + str(filename) + if filename is None: + filename = gglobals.gourmanddir / 'recipes.db' + return 'sqlite:///' + str(filename) class RecData (Pluggable): @@ -475,24 +473,30 @@ def update_version_info(self, version_string: str): stored_info = self.fetch_one(self.info_table) - if not stored_info or not (stored_info.version_super or stored_info.version_major): + if not stored_info: # Default info -- the last version before we added the # version tracker... default_info = {'version_super': 0, 'version_major': 11, 'version_minor': 0} - if not stored_info: - if not self.new_db: - self.do_add(self.info_table, - default_info) - else: - self.do_add(self.info_table, - {'version_super': current_super, - 'version_major': current_major, - 'version_minor': current_minor}) + if not self.new_db: + self.do_add(self.info_table, + default_info) else: - self.do_modify(self.info_table, stored_info, - default_info, id_col=None) + self.do_add(self.info_table, + {'version_super': current_super, + 'version_major': current_major, + 'version_minor': current_minor}) + stored_info = self.fetch_one(self.info_table) + + elif not (stored_info.version_super or stored_info.version_major): + # Default info -- the last version before we added the + # version tracker... + default_info = {'version_super': 0, + 'version_major': 11, + 'version_minor': 0} + self.do_modify(self.info_table, stored_info, + default_info, id_col=None) stored_info = self.fetch_one(self.info_table) # Code for updates between versions... @@ -613,11 +617,11 @@ def update_version_info(self, version_string: str): } for col in URL_SOURCES ]) + url = None for r in recs: rec_url = '' for src in URL_SOURCES: blob = getattr(r,src) - url = None if blob: m = re.search(r'\w+://[^ ]*',blob) if m: @@ -734,9 +738,9 @@ def fetch_one (self, table, **criteria): """Fetch one item from table and arguments""" return table.select(*make_simple_select_arg(criteria,table)).execute().fetchone() - def fetch_count (self, table, column, sort_by=[],**criteria): + def fetch_count(self, table, column, sort_by=[],**criteria): """Return a counted view of the table, with the count stored in the property 'count'""" - result = sqlalchemy.select( + return sqlalchemy.select( [sqlalchemy.func.count(getattr(table.c,column)).label('count'), getattr(table.c,column)], *make_simple_select_arg(criteria,table), @@ -744,7 +748,6 @@ def fetch_count (self, table, column, sort_by=[],**criteria): 'order_by':make_order_by(sort_by,table,count_by=column), } ).execute().fetchall() - return result def fetch_len (self, table, **criteria): """Return the number of rows in table that match criteria @@ -783,19 +786,18 @@ def search_nutrition (self, words, group=None): where_statement) return self.nutrition_table.select(where_statement).execute().fetchall() - def __get_joins (self, searches): + def __get_joins(self, searches): joins = [] for s in searches: if isinstance(s, tuple): joins.append(self.__get_joins(s[0])) - else: - if s['column'] == 'category': - if self.categories_table not in joins: - joins.append(self.categories_table,self.categories_table.c.id, - self.recipe_table.c.id) - elif s['column'] == 'ingredient': - if self.ingredients_table not in joins: - joins.append(self.ingredients_table) + elif s['column'] == 'category': + if self.categories_table not in joins: + joins.append(self.categories_table,self.categories_table.c.id, + self.recipe_table.c.id) + elif s['column'] == 'ingredient': + if self.ingredients_table not in joins: + joins.append(self.ingredients_table) return joins def get_criteria (self,crit): @@ -849,7 +851,7 @@ def get_criteria (self,crit): return retval - def search_recipes (self, searches, sort_by=[]): + def search_recipes(self, searches, sort_by=[]): """Search recipes for columns of values. "category" and "ingredient" are handled magically @@ -858,7 +860,7 @@ def search_recipes (self, searches, sort_by=[]): """ if 'rating' in [t[0] for t in sort_by]: i = [t[0] for t in sort_by].index('rating') - d = (sort_by[i][1]==1 and -1 or 1) + d = -1 if sort_by[i][1]==1 else 1 sort_by[i] = ('rating',d) criteria = self.get_criteria((searches,'and')) debug('backends.db.search_recipes - search criteria are %s'%searches,2) @@ -874,11 +876,10 @@ def search_recipes (self, searches, sort_by=[]): order_by=make_order_by(sort_by,self.recipe_table,), ).execute().fetchall() - def get_unique_values (self, colname,table=None,**criteria): + def get_unique_values(self, colname,table=None,**criteria): """Get list of unique values for column in table.""" if table is None: table=self.recipe_table - if criteria: criteria = make_simple_select_arg(criteria,table)[0] - else: criteria=None + criteria = make_simple_select_arg(criteria,table)[0] if criteria else None if colname=='category' and table==self.recipe_table: print('WARNING: you are using a hack to access category values.') table = self.categories_table @@ -894,27 +895,8 @@ def get_ingkeys_with_count(self, search: Optional[Mapping[str, Any]] = None) -> if search is None: search = {} - if search: - col = getattr(self.ingredients_table.c,search['column']) - operator = search.get('operator','LIKE') - if operator=='LIKE': - criteria = col.like(search['search']) - elif operator=='REGEXP': - criteria = col.op('REGEXP')(search['search']) - elif operator == 'CONTAINS': - criteria = col.contains(search['search']) - else: - criteria = (col == search['search']) - result = sqlalchemy.select( - [sqlalchemy.func.count(self.ingredients_table.c.ingkey).label('count'), - self.ingredients_table.c.ingkey], - criteria, - **{'group_by':'ingkey', - 'order_by':make_order_by([],self.ingredients_table,count_by='ingkey'), - } - ).execute().fetchall() - else: # return all ingredient keys with counts - result = sqlalchemy.select( + if not search: # return all ingredient keys with counts + return sqlalchemy.select( [sqlalchemy.func.count(self.ingredients_table.c.ingkey).label('count'), self.ingredients_table.c.ingkey], **{'group_by':'ingkey', @@ -922,26 +904,49 @@ def get_ingkeys_with_count(self, search: Optional[Mapping[str, Any]] = None) -> } ).execute().fetchall() - return result + col = getattr(self.ingredients_table.c,search['column']) + operator = search.get('operator','LIKE') + if operator=='LIKE': + criteria = col.like(search['search']) + elif operator=='REGEXP': + criteria = col.op('REGEXP')(search['search']) + elif operator == 'CONTAINS': + criteria = col.contains(search['search']) + else: + criteria = (col == search['search']) + return ( + sqlalchemy.select( + [ + sqlalchemy.func.count(self.ingredients_table.c.ingkey).label( + 'count' + ), + self.ingredients_table.c.ingkey, + ], + criteria, + **{ + 'group_by': 'ingkey', + 'order_by': make_order_by( + [], self.ingredients_table, count_by='ingkey' + ), + } + ) + .execute() + .fetchall() + ) - def delete_by_criteria (self, table, criteria): + def delete_by_criteria(self, table, criteria): """Table is our table. Criteria is a dictionary of criteria to delete by. """ criteria = fix_colnames(criteria,table) - delete_args = [] - for k,v in list(criteria.items()): - delete_args.append(k==v) + delete_args = [k==v for k,v in list(criteria.items())] if len(delete_args) > 1: delete_args = [and_(*delete_args)] table.delete(*delete_args).execute() - def update_by_criteria (self, table, update_criteria, new_values_dic): + def update_by_criteria(self, table, update_criteria, new_values_dic): try: - to_del = [] - for k in new_values_dic: - if not isinstance(k, str): - to_del.append(k) + to_del = [k for k in new_values_dic if not isinstance(k, str)] for k in to_del: v = new_values_dic[k] del new_values_dic[k] @@ -1166,27 +1171,33 @@ def modify_ings (self, ings, ingdict): # something for a whole bunch of ingredients... for i in ings: self.modify_ing(i,ingdict) - def modify_ing_and_update_keydic (self, ing, ingdict): + def modify_ing_and_update_keydic(self, ing, ingdict): """Update our key dictionary and modify our dictionary. This is a separate method from modify_ing because we only do this for hand-entered data, not for mass imports. """ # If our ingredient has changed, update our keydic... - if ing.item!=ingdict.get('item',ing.item) or ing.ingkey!=ingdict.get('ingkey',ing.ingkey): - if ing.item and ing.ingkey: - self.remove_ing_from_keydic(ing.item,ing.ingkey) - self.add_ing_to_keydic( - ingdict.get('item',ing.item), - ingdict.get('ingkey',ing.ingkey) - ) + if ( + ( + ing.item != ingdict.get('item', ing.item) + or ing.ingkey != ingdict.get('ingkey', ing.ingkey) + ) + and ing.item + and ing.ingkey + ): + self.remove_ing_from_keydic(ing.item,ing.ingkey) + self.add_ing_to_keydic( + ingdict.get('item',ing.item), + ingdict.get('ingkey',ing.ingkey) + ) return self.modify_ing(ing,ingdict) def update_hashes (self, rec): rhash,ihash = recipeIdentifier.hash_recipe(rec,self) self.do_modify_rec(rec,{'recipe_hash':rhash,'ingredient_hash':ihash}) - def find_duplicates_of_rec (self, rec, match_ingredient=True, match_recipe=True): + def find_duplicates_of_rec(self, rec, match_ingredient=True, match_recipe=True): """Return recipes that appear to be duplicates""" if match_ingredient and match_recipe: perfect_matches = self.fetch_all(ingredient_hash=rec.ingredient_hash,recipe_hash=rec.recipe_hash) @@ -1194,14 +1205,10 @@ def find_duplicates_of_rec (self, rec, match_ingredient=True, match_recipe=True) perfect_matches = self.fetch_all(ingredient_hash=rec.ingredient_hash) else: perfect_matches = self.fetch_all(recipe_hash=rec.recipe_hash) - matches = [] if len(perfect_matches) == 1: return [] else: - for r in perfect_matches: - if r.id != rec.id: - matches.append(r) - return matches + return [r for r in perfect_matches if r.id != rec.id] def find_all_duplicates (self): """Return a list of sets of duplicate recipes.""" @@ -1285,12 +1292,12 @@ def add_ing (self, dic): print('Problem adding',dic) raise - def add_ings (self, dics): + def add_ings(self, dics): """Add multiple ingredient dictionaries at a time.""" for d in dics: self.validate_ingdic(d) for k in ['refid','unit','amount','rangeamount','item','ingkey','optional','shopoptional','inggroup','position']: - if not k in d: + if k not in d: d[k] = None try: # Warning: this method relies on all the dictionaries @@ -1362,7 +1369,7 @@ def do_add_ing (self,dic): def do_add_cat (self, dic): return self.do_add_and_return_item(self.categories_table,dic) - def do_add_rec (self, rdict): + def do_add_rec(self, rdict): """Add a recipe based on a dictionary of properties and values.""" self.changed=True if 'deleted' not in rdict: @@ -1370,15 +1377,15 @@ def do_add_rec (self, rdict): if 'id' in rdict: # If our dictionary has an id, then we assume we are a # reserved ID - if rdict['id'] in self.new_ids: - rid = rdict['id']; del rdict['id'] - self.new_ids.remove(rid) - self.update_by_criteria(self.recipe_table, - {'id':rid}, - rdict) - return self.recipe_table.select(self.recipe_table.c.id==rid).execute().fetchone() - else: + if rdict['id'] not in self.new_ids: raise ValueError('New recipe created with preset id %s, but ID is not in our list of new_ids'%rdict['id']) + rid = rdict['id'] + del rdict['id'] + self.new_ids.remove(rid) + self.update_by_criteria(self.recipe_table, + {'id':rid}, + rdict) + return self.recipe_table.select(self.recipe_table.c.id==rid).execute().fetchone() insert_statement = self.recipe_table.insert() select = self.recipe_table.select(self.recipe_table.c.id==insert_statement.execute(**rdict).inserted_primary_key[0]) return select.execute().fetchone() @@ -1419,14 +1426,11 @@ def do_modify(self, select = table.select() return select.execute().fetchone() - def get_ings (self, rec): + def get_ings(self, rec): """Handed rec, return a list of ingredients. rec should be an ID or an object with an attribute ID)""" - if hasattr(rec,'id'): - id=rec.id - else: - id=rec + id = rec.id if hasattr(rec,'id') else rec return self.fetch_all(self.ingredients_table,recipe_id=id,deleted=False) def get_cats(self, rec): @@ -1501,21 +1505,19 @@ def new_id(self) -> int: # Convenience functions for dealing with ingredients - def order_ings (self, ings): + def order_ings(self, ings): """Handed a view of ingredients, we return an alist: [['group'|None ['ingredient1', 'ingredient2', ...]], ... ] """ defaultn = 0 groups = {} group_order = {} - n = 0; group = 0 + n = 0 + group = 0 for i in ings: # defaults - if not hasattr(i,'inggroup'): - group = None - else: - group=i.inggroup - if group == None: + group = None if not hasattr(i,'inggroup') else i.inggroup + if group is None: group = n; n+=1 position = getattr(i, 'position', None) @@ -1542,7 +1544,7 @@ def order_ings (self, ings): last_g = -1 for g,ii in alist: if isinstance(g, int): - if last_g == None: + if last_g is None: final_alist[-1][1].extend(ii) else: final_alist.append([None,ii]) @@ -1561,14 +1563,11 @@ def replace_ings (self, ingdicts): for ingd in ingdicts: self.add_ing(ingd) - def ingview_to_lst (self, view): + def ingview_to_lst(self, view): """Handed a view of ingredient data, we output a useful list. The data we hand out consists of a list of tuples. Each tuple contains amt, unit, key, alternative?""" - ret = [] - for i in view: - ret.append([self.get_amount(i), i.unit, i.ingkey,]) - return ret + return [[self.get_amount(i), i.unit, i.ingkey,] for i in view] def get_amount (self, ing, mult=1): """Given an ingredient object, return the amount for it. @@ -1646,10 +1645,7 @@ def format_amount_string_from_amount(amt, fractions=None, unit=None): if fractions is None: # None means use the default value fractions = convert.USE_FRACTIONS - if unit: - approx = defaults.unit_rounding_guide.get(unit, 0.01) - else: - approx = 0.01 + approx = defaults.unit_rounding_guide.get(unit, 0.01) if unit else 0.01 if isinstance(amt, tuple): return "%s-%s" % (convert.float_to_frac(amt[0], fractions=fractions, @@ -1664,7 +1660,7 @@ def format_amount_string_from_amount(amt, fractions=None, unit=None): else: return "" - def get_amount_as_float (self, ing, mode=1): #1 == self.AMT_MODE_AVERAGE + def get_amount_as_float(self, ing, mode=1): #1 == self.AMT_MODE_AVERAGE """Return a float representing our amount. If we have a range for amount, this function will ignore the range and simply @@ -1676,19 +1672,18 @@ def get_amount_as_float (self, ing, mode=1): #1 == self.AMT_MODE_AVERAGE amt = self.get_amount(ing) if isinstance(amt, (float, int, type(None))): return amt + # otherwise we do our magic + amt=list(amt) + amt.sort() # make sure these are in order + low,high=amt + if mode==self.AMT_MODE_AVERAGE: return (low+high)/2.0 + elif mode==self.AMT_MODE_LOW: return low + elif mode==self.AMT_MODE_HIGH: return high # mode==self.AMT_MODE_HIGH else: - # otherwise we do our magic - amt=list(amt) - amt.sort() # make sure these are in order - low,high=amt - if mode==self.AMT_MODE_AVERAGE: return (low+high)/2.0 - elif mode==self.AMT_MODE_LOW: return low - elif mode==self.AMT_MODE_HIGH: return high # mode==self.AMT_MODE_HIGH - else: - raise ValueError("%s is an invalid value for mode"%mode) + raise ValueError("%s is an invalid value for mode"%mode) @pluggable_method - def add_ing_to_keydic (self, item, key): + def add_ing_to_keydic(self, item, key): #print 'add ',item,key,'to keydic' if not item or not key: return @@ -1698,11 +1693,7 @@ def add_ing_to_keydic (self, item, key): item = item.decode('utf-8', 'replace') else: item = str(item) - if isinstance(key, bytes): - key = key.decode('utf-8', 'replace') - else: - key = str(key) - + key = key.decode('utf-8', 'replace') if isinstance(key, bytes) else str(key) row = self.fetch_one(self.keylookup_table, item=item, ingkey=key) if row: self.do_modify(self.keylookup_table,row,{'count':row.count+1}) @@ -1742,13 +1733,10 @@ def ing_shopper (self, view): # functions to undoably modify tables - def get_dict_for_obj (self, obj, keys): + def get_dict_for_obj(self, obj, keys): orig_dic = {} for k in keys: - if k=='category': - v = ", ".join(self.get_cats(obj)) - else: - v=getattr(obj,k) + v = ", ".join(self.get_cats(obj)) if k=='category' else getattr(obj,k) orig_dic[k]=v return orig_dic @@ -1827,12 +1815,13 @@ def undo_action (): def undoable_delete_ings (self, ings, history, make_visible=None): """Delete ingredients in list ings and add to our undo history.""" def do_delete(): - modded_ings = [self.modify_ing(i,{'deleted':True}) for i in ings] if make_visible: + modded_ings = [self.modify_ing(i,{'deleted':True}) for i in ings] + make_visible(modded_ings) + def undo_delete(): + if make_visible: + modded_ings = [self.modify_ing(i,{'deleted':False}) for i in ings] make_visible(modded_ings) - def undo_delete (): - modded_ings = [self.modify_ing(i,{'deleted':False}) for i in ings] - if make_visible: make_visible(modded_ings) obj = Undo.UndoableObject(do_delete,undo_delete,history) obj.perform() @@ -1873,7 +1862,7 @@ def __getattr__(self, name): raise AttributeError(name) return getattr(self.rd, name) - def key_search (self, ing): + def key_search(self, ing): """Handed a string, we search for keys that could match the ingredient.""" result=self.km.look_for_key(ing) @@ -1884,16 +1873,13 @@ def key_search (self, ing): # item of every cell. if len(result)>0 and result[0][1]>0.8: return [a[0] for a in result] - else: - ## otherwise, we make a mad attempt to guess! - k=self.km.generate_key(ing) - l = [k] - l.extend([a[0] for a in result]) - return l + ## otherwise, we make a mad attempt to guess! + k=self.km.generate_key(ing) + return [k, *[a[0] for a in result]] else: return None - def parse_ingredient (self, s, conv=None, get_key=True): + def parse_ingredient(self, s, conv=None, get_key=True): """Handed a string, we hand back a dictionary representing a parsed ingredient (sans recipe ID)""" #if conv: # print 'parse_ingredient: conv argument is now ignored' @@ -1943,11 +1929,11 @@ def parse_ingredient (self, s, conv=None, get_key=True): d['item']=i.strip() if get_key: d['ingkey']=self.km.get_key(i.strip()) debug('ingredient_parser returning: %s'%d,0) - return d else: debug("Unable to parse %s"%s,0) d['item'] = s - return d + + return d ingredient_parser = parse_ingredient @@ -1984,7 +1970,7 @@ def ings_search (self, ings, keyed=None, recipe_table=None, use_regexp=True, exa """Search for multiple ingredients.""" raise NotImplementedError - def clear_remembered_optional_ings (self, recipe=None): + def clear_remembered_optional_ings(self, recipe=None): """Clear our memories of optional ingredient defaults. If handed a recipe, we clear only for the recipe we've been @@ -1992,10 +1978,7 @@ def clear_remembered_optional_ings (self, recipe=None): Otherwise, we clear *all* recipes. """ - if recipe: - vw = self.rd.get_ings(recipe) - else: - vw = self.rd.ingredients_table + vw = self.rd.get_ings(recipe) if recipe else self.rd.ingredients_table # this is ugly... vw1 = vw.select(shopoptional=1) vw2 = vw.select(shopoptional=2) @@ -2069,10 +2052,9 @@ def __setitem__ (self, k, v): self.db.changed=True return v - def __getitem__ (self, k): + def __getitem__(self, k): if k in self.just_got: return self.just_got[k] - v = getattr(self.db.fetch_one(self.vw,**{self.kp:k}),self.vp) - return v + return getattr(self.db.fetch_one(self.vw,**{self.kp:k}),self.vp) def __repr__ (self): retstr = " {" @@ -2102,18 +2084,11 @@ def initialize (self, d): dics.append({self.kp:k,self.vp:store_v}) self.vw.insert().execute(*dics) - def keys (self): - ret = [] - for i in self.db.fetch_all(self.vw): - ret.append(getattr(i,self.kp)) - return ret + def keys(self): + return [getattr(i,self.kp) for i in self.db.fetch_all(self.vw)] - def values (self): - ret = [] - for i in self.db.fetch_all(self.vw): - val = getattr(i,self.vp) - ret.append(val) - return ret + def values(self): + return [getattr(i,self.vp) for i in self.db.fetch_all(self.vw)] def items (self): ret = [] diff --git a/src/gourmand/batchEditor.py b/src/gourmand/batchEditor.py index f845aad8..6c0e178f 100644 --- a/src/gourmand/batchEditor.py +++ b/src/gourmand/batchEditor.py @@ -20,7 +20,7 @@ def setup_ui (self): self.setup_boxes() self.dialog.connect('response',self.response_cb) - def setup_boxes (self): + def setup_boxes(self): self.attribute_widgets = {} self.get_data_methods = {} for a,l,w in gglobals.REC_ATTRS: @@ -32,7 +32,7 @@ def setup_boxes (self): setattr(self,'%sBox'%a,box) checkbutton.connect('toggled',self.toggle_cb,a) box.set_sensitive(False) - if w=='Combo': + if w == 'Combo': # If this is a combo box, we'll get info via the child's get_text method... self.get_data_methods[a] = (checkbutton, getattr(self,'%sBox'%a).get_children()[0].get_text) @@ -40,11 +40,8 @@ def setup_boxes (self): box.set_model(self.rg.get_attribute_model(a)) box.set_text_column(0) cb_extras.setup_completion(box) - elif w=='Entry': - if hasattr(box,'get_value'): - method = box.get_value - else: - method = box.get_text + elif w == 'Entry': + method = box.get_value if hasattr(box,'get_value') else box.get_text self.get_data_methods[a] = (checkbutton, method) diff --git a/src/gourmand/check_encodings.py b/src/gourmand/check_encodings.py index b3850056..b7e6242e 100644 --- a/src/gourmand/check_encodings.py +++ b/src/gourmand/check_encodings.py @@ -179,7 +179,7 @@ def move_to_difference (self, forward=True): ) self.tv.scroll_to_mark(mark,0) - def set_buffer_text (self, buffer, text): + def set_buffer_text(self, buffer, text): """Set buffer text to show encoding differences.""" lines = text.splitlines() totl = len(lines) @@ -187,7 +187,7 @@ def set_buffer_text (self, buffer, text): for line,diffs in list(self.diff_lines.items()): if line in shown: continue start_at = line - self.context_lines - if start_at < 0: start_at = 0 + start_at = max(start_at, 0) end_at = line + self.context_lines if end_at >= totl: end_at = totl-1 if start_at != 0: @@ -230,12 +230,14 @@ def diff_texts(self): # If not all lines are the same, create a diff marking where they # differ. - if not all(line == ol for ol in other_lines): + if any(line != ol for ol in other_lines): ranges = [] for chnum, ch in enumerate(line): # Check that the lines are the same. If not, mark where - if not all([len(line) > chnum and ch == line[chnum] - for line in other_lines]): + if not all( + len(line) > chnum and ch == line[chnum] + for line in other_lines + ): if ranges and ranges[-1][1] == chnum: ranges[-1][1] = chnum+1 else: diff --git a/src/gourmand/convert.py b/src/gourmand/convert.py index 3607e0dd..6ba766ad 100644 --- a/src/gourmand/convert.py +++ b/src/gourmand/convert.py @@ -47,12 +47,12 @@ def __repr__(self): def __delitem__(self, key): norm = self.__normalization(key) - if norm in self.__mapping: - del self.__orig[norm] - del self.__mapping[norm] - else: + if norm not in self.__mapping: raise KeyError(key) + del self.__orig[norm] + del self.__mapping[norm] + def __getitem__(self, key): norm = self.__normalization(key) if norm in self.__mapping: @@ -152,11 +152,11 @@ def create_unit_dict(self): for u,alts in self.time_units: lst = [] for a in alts: - if not a in lst: lst.append(a) - if not a.title() in lst: lst.append(a.title()) - if not a.capitalize() in lst: lst.append(a.capitalize()) - if not a.upper() in lst: lst.append(a.upper()) - if not a.lower() in lst: lst.append(a.lower()) + if a not in lst: lst.append(a) + if a.title() not in lst: lst.append(a.title()) + if a.capitalize() not in lst: lst.append(a.capitalize()) + if a.upper() not in lst: lst.append(a.upper()) + if a.lower() not in lst: lst.append(a.lower()) self.units.append((u,lst)) self.unit_dict=PossiblyCaseInsensitiveDictionary() for itm in self.units: @@ -213,17 +213,16 @@ def convert (u1,u2): to_expand.append(k) expanded.append(itm) - def convert_simple (self, u1, u2, item=None): + def convert_simple(self, u1, u2, item=None): if u1 == u2: return 1.0 + dict=self.conv_table + if (u1,u2) in dict: + return dict[(u1,u2)] + elif (u2,u1) in dict: + return float(1) / float(dict[(u2,u1)]) else: - dict=self.conv_table - if (u1,u2) in dict: - return dict[(u1,u2)] - elif (u2,u1) in dict: - return float(1) / float(dict[(u2,u1)]) - else: - return 0 + return 0 def convert_w_density (self, u1, u2, density=None, item=None): if u1 == u2: @@ -242,17 +241,17 @@ def convert_w_density (self, u1, u2, density=None, item=None): else: return None - def list_of_cu_tables (self, dictcu=None): + def list_of_cu_tables(self, dictcu=None): if (not dictcu): dictcu = self.cross_unit_table values = list(dictcu.values()) ret = [] for v in values: - if not v[0] in ret: + if v[0] not in ret: ret.append(v[0]) return ret - def conv_dict_for_item (self, item=None, dictcu=None, mult=None): + def conv_dict_for_item(self, item=None, dictcu=None, mult=None): """item overrides mult""" if (not dictcu): dictcu = self.cross_unit_table @@ -260,26 +259,20 @@ def conv_dict_for_item (self, item=None, dictcu=None, mult=None): # my_tbls = [] ret = {} for itm in list(dictcu.items()): - k = itm[0] v = itm[1] dct = self.cross_unit_dicts[v[0]] - conv = v[1] if item and item in dct: mult = dct[item] if mult: + k = itm[0] + conv = v[1] ret[k] = conv * mult return ret - def converter (self, u1, u2, item=None, density=None): + def converter(self, u1, u2, item=None, density=None): ## Just a front end to convert_fancy that looks up units - if u1 in self.unit_dict: - unit1 = self.unit_dict[u1] - else: - unit1 = u1 - if u2 in self.unit_dict: - unit2 = self.unit_dict[u2] - else: - unit2 = u2 + unit1 = self.unit_dict[u1] if u1 in self.unit_dict else u1 + unit2 = self.unit_dict[u2] if u2 in self.unit_dict else u2 ## provide some kind of item lookup? return self.convert_fancy(unit1, unit2, item=item, density=density) @@ -300,16 +293,16 @@ def get_conversions (self, u, item=None, density=None): dct.update(self.conv_dict_for_item(mult=density)) return self.possible_conversions(u, dct) - def get_all_conversions (self, u, item=None, density=None): + def get_all_conversions(self, u, item=None, density=None): dict = self.get_conversions(u, item, density) expanded = [] conversions = list(dict.keys()) lst = conversions[0:] # make another copy to chew up while len(lst) >= 1: itm = lst.pop() - if not itm in conversions: + if itm not in conversions: conversions.append(itm) - if not itm in expanded: + if itm not in expanded: d = self.get_conversions(u,itm,density) lst.extend(list(d.keys())) expanded.append(itm) @@ -332,7 +325,7 @@ def possible_conversions(self, u, dict=0): ret[i1] = float(item[1]) return ret - def readability_score (self,amt,unit=None): + def readability_score(self,amt,unit=None): """We rate the readability of a number and unit This is rather advanced. We presume a few things -- such as that we @@ -392,19 +385,15 @@ def readability_score (self,amt,unit=None): readability += -2 # now we get clever and add a penalty proportional to the oversizedness if (amt-mx): readability += - ((amt - mx)/float(mx))*2 - else: - # otherwise, we'll make some assumptions about numbers - # we don't like things over a thousand and we really don't - # or under a hundredth - if amt > 1000: readability += -2 - elif amt < .1: + elif amt > 1000: readability += -2 + elif amt < .1: + readability += -1 + if amt < .01: readability += -1 - if amt < .01: + if amt < .001: readability += -1 - if amt < .001: + if amt < .0001: readability += -1 - if amt < .0001: - readability += -1 ## And we like numbers between 1/8 and 4 #if 0.25 <= amt <= 4: # readability += 1 @@ -424,7 +413,7 @@ def readability_score (self,amt,unit=None): # readability += -20 return readability - def adjust_unit (self, amt, unit, item=None, favor_current_unit=True, preferred_unit_groups=[]): + def adjust_unit(self, amt, unit, item=None, favor_current_unit=True, preferred_unit_groups=[]): """Return the most readable equivalent of amount and unit for item ITM @@ -444,17 +433,16 @@ def adjust_unit (self, amt, unit, item=None, favor_current_unit=True, preferred_ return amt,unit else: units=defaults.UNIT_GROUPS[ugroup] - if preferred_unit_groups: - if ugroup not in preferred_unit_groups: - for ug in preferred_unit_groups: - conv = self.converter(u,defaults.UNIT_GROUPS[ug][0][0]) - if conv: - units = defaults.UNIT_GROUPS[ug] - amt = conv * amt - u = unit = defaults.UNIT_GROUPS[ug][0][0] - break - else: - continue + if preferred_unit_groups and ugroup not in preferred_unit_groups: + for ug in preferred_unit_groups: + conv = self.converter(u,defaults.UNIT_GROUPS[ug][0][0]) + if conv: + units = defaults.UNIT_GROUPS[ug] + amt = conv * amt + u = unit = defaults.UNIT_GROUPS[ug][0][0] + break + else: + continue ret_readability = self.readability_score(amt,unit) if favor_current_unit: ret_readability += 1 ret_amt = amt @@ -637,7 +625,7 @@ def seconds_to_timestring(time: int, # round because 1/2 = 1 as far as plural forms are concerned time_formatters[unit](round(time_covered)) ])) - time = time - time_covered * divisor + time -= time_covered * divisor if time==0: break if len(time_strings)>2: # Translators... this is a messay way of concatenating @@ -686,8 +674,10 @@ def integerp (num, approx=0.01): )) NUMBER_WORD_REGEXP = '|'.join(all_number_words).replace(' ',r'\s+') -FRACTION_WORD_REGEXP = '|'.join([n for n in all_number_words if NUMBER_WORDS[n]<1.0] - ).replace(' ',r'\s+') +FRACTION_WORD_REGEXP = '|'.join( + n for n in all_number_words if NUMBER_WORDS[n] < 1.0 +).replace(' ', r'\s+') + NORMAL_FRACTIONS = [(1,2),(1,4),(3,4)] @@ -764,10 +754,10 @@ def integerp (num, approx=0.01): NUMBER_END_REGEXP = NUMBER_START_REGEXP NUMBER_REGEXP = "("+NUMBER_START_REGEXP+"*"+NUMBER_MID_REGEXP+"*"+NUMBER_END_REGEXP if NUMBER_WORD_REGEXP: - NUMBER_REGEXP = NUMBER_REGEXP + '|' + NUMBER_WORD_REGEXP + ')' - NUMBER_NO_RANGE_REGEXP = '(' + NUMBER_START_REGEXP + '+|' + NUMBER_WORD_REGEXP + ')' + NUMBER_REGEXP = NUMBER_REGEXP + '|' + NUMBER_WORD_REGEXP + ')' + NUMBER_NO_RANGE_REGEXP = '(' + NUMBER_START_REGEXP + '+|' + NUMBER_WORD_REGEXP + ')' else: - NUMBER_REGEXP = NUMBER_REGEXP + ")" + NUMBER_REGEXP += ")" NUMBER_NO_RANGE_REGEXP = NUMBER_START_REGEXP + '+' NUMBER_MATCHER = re.compile("^%s$"%NUMBER_REGEXP,re.UNICODE) @@ -815,9 +805,10 @@ def integerp (num, approx=0.01): if ' ' in canonical_name: multi_word_units.append(canonical_name) for n in other_names: if ' ' in n: multi_word_units.append(n) -MULTI_WORD_UNIT_REGEXP = '(' + \ - '|'.join([re.escape(str(u)) for u in multi_word_units]) \ - + ')' +MULTI_WORD_UNIT_REGEXP = ( + '(' + '|'.join(re.escape(str(u)) for u in multi_word_units) +) + ')' + # generic ingredient matcher. This is far from a good matcher -- it's @@ -841,7 +832,7 @@ def integerp (num, approx=0.01): (?P\s*(%(MULTI_WORD_UNIT_REGEXP)s|[\w.]+))?\s+ # a unit (?P.*?)$ # and the rest of our stuff... """ - ING_MATCHER_REGEXP = ING_MATCHER_REGEXP%locals() + ING_MATCHER_REGEXP %= locals() except: print('Failure with local vars...') for s in ['NUMBER_FINDER_REGEXP', @@ -870,7 +861,7 @@ def convert_fractions_to_ascii (s): s=re.sub(SLASH,'/',s) return s -def fractify (decimal, divisor, approx=0.01, fractions=FRACTIONS_NORMAL): +def fractify(decimal, divisor, approx=0.01, fractions=FRACTIONS_NORMAL): """Return fraction equivalent of decimal using divisor If we don't have a fit within our approximation, return the @@ -880,54 +871,49 @@ def fractify (decimal, divisor, approx=0.01, fractions=FRACTIONS_NORMAL): if dividend == divisor: return 1 if dividend: - if fractions==FRACTIONS_ASCII: + if ( + fractions != FRACTIONS_ASCII + and fractions == FRACTIONS_ALL + and (dividend, divisor) in NUM_TO_FRACTIONS + or fractions != FRACTIONS_ASCII + and fractions != FRACTIONS_ALL + and (dividend, divisor) in NORMAL_FRACTIONS + ): + return NUM_TO_FRACTIONS[(dividend,divisor)] + elif fractions != FRACTIONS_ASCII and fractions == FRACTIONS_ALL: + if dividend in SUP_DICT: dividend = SUP_DICT[dividend] + if divisor in SUB_DICT: divisor = SUB_DICT[divisor] + return '%s%s%s'%(dividend,SLASH,divisor) + else: return "%s/%s"%(dividend,divisor) - elif fractions==FRACTIONS_ALL: - # otherwise, we have to do nice unicode magic - if (dividend,divisor) in NUM_TO_FRACTIONS: - return NUM_TO_FRACTIONS[(dividend,divisor)] - else: - if dividend in SUP_DICT: dividend = SUP_DICT[dividend] - if divisor in SUB_DICT: divisor = SUB_DICT[divisor] - return '%s%s%s'%(dividend,SLASH,divisor) - else: # fractions==FRACTIONS_NORMAL - #fallback to "normal" fractions -- 1/4, 1/2, 3/4 are special - if (dividend,divisor) in NORMAL_FRACTIONS: - return NUM_TO_FRACTIONS[(dividend,divisor)] - else: - return "%s/%s"%(dividend,divisor) -def float_to_frac (n, d=[2,3,4,5,6,8,10,16],approx=0.01,fractions=FRACTIONS_NORMAL): +def float_to_frac(n, d=[2,3,4,5,6,8,10,16],approx=0.01,fractions=FRACTIONS_NORMAL): """Take a number -- or anything that can become a float -- and attempt to return a fraction with a denominator in the list `d'. We approximate fractions to within approx. i.e. if approx=0.01, then 0.331=1/3""" if USE_FRACTIONS == FRACTIONS_OFF: return float_to_metric(n,approx) - else: - if not n: return "" - n=float(n) - i = int(n) - if i >= 1: - i="%s"%int(n) - else: - i="" - rem = n - int(n) - if rem==0 or rem= 1 else "" + rem = n - int(n) + if rem==0 or rem 1): - rounded = round(n) - if rounded == 0: - return float_to_metric(n,approx*.01) - return locale.format("%i",int(rounded),True) - else: - rounded = round(n,decimals_to_preserve) - if rounded == 0: - return float_to_metric(n,approx*.01) - return locale.format("%."+str(decimals_to_preserve)+"f",rounded,True) # format(formatstring, number, use_thousands_separator) - else: - return locale.format("%i",n,True) + if n is None: + return "" + + if int(n) == n: + return locale.format("%i",n,True) + if (n - int(n) < approx) or ((n - int(n) + approx) > 1): + rounded = round(n) + if rounded == 0: + return float_to_metric(n,approx*.01) + return locale.format("%i",int(rounded),True) else: - return "" + rounded = round(n,decimals_to_preserve) + if rounded == 0: + return float_to_metric(n,approx*.01) + return locale.format("%."+str(decimals_to_preserve)+"f",rounded,True) # format(formatstring, number, use_thousands_separator) def float_string (s): """Convert string to a float, assuming it is some sort of decimal number @@ -994,7 +979,7 @@ def float_string (s): # otherwise just trust our locale float return locale.atof(s) -def frac_to_float (s): +def frac_to_float(s): """We assume fractions look like this (I )?N/D""" if s in NUMBER_WORDS: return NUMBER_WORDS[s] if hasattr(s,'lower') and s.lower() in NUMBER_WORDS: @@ -1004,8 +989,7 @@ def frac_to_float (s): if m: i = m.group('int') frac = m.group('frac') - if i: i=float_string(i) - else: i = 0 + i = float_string(i) if i else 0 if frac in UNICODE_FRACTIONS: return i+UNICODE_FRACTIONS[frac] elif frac in NUMBER_WORDS: @@ -1070,14 +1054,14 @@ def get_unit (self, prompt="Enter unit: "): print('(Type "list" for a list of valid units)') return self.get_unit(prompt) - def get_amount (self, prompt="Enter amount: "): + def get_amount(self, prompt="Enter amount: "): amt = frac_to_float(input(prompt)) - if not amt: - print("Please enter an amount!") - return self.get_amount(prompt) - else: + if amt: return amt + print("Please enter an amount!") + return self.get_amount(prompt) + def converter (self): u1 = self.get_unit("Enter source unit: ") amt = self.get_amount("Enter source amount: ") diff --git a/src/gourmand/defaults/defaults_ru.py b/src/gourmand/defaults/defaults_ru.py index 34047863..67595182 100644 --- a/src/gourmand/defaults/defaults_ru.py +++ b/src/gourmand/defaults/defaults_ru.py @@ -780,7 +780,7 @@ def guess_singulars(s): rets.append(Language.irregular_plurals[s]) if Language.two_digit_plural_matcher.search(s): wrd=s[0:-2] - if not wrd in rets: rets.append(wrd) + if wrd not in rets: rets.append(wrd) if Language.v_plural_matcher.search(s): rets.append(s[0:-3]+'f') if Language.one_digit_plural_matcher.search(s): diff --git a/src/gourmand/defaults/defaults_sv.py b/src/gourmand/defaults/defaults_sv.py index b2de7486..1f4a607c 100644 --- a/src/gourmand/defaults/defaults_sv.py +++ b/src/gourmand/defaults/defaults_sv.py @@ -555,14 +555,14 @@ class Language(AbstractLanguage): v_plural_matcher = re.compile('ves') @staticmethod - def guess_singulars (s): + def guess_singulars(s): if len(s)<3: return [] rets = [] if s in Language.irregular_plurals: rets.append(Language.irregular_plurals[s]) if Language.two_digit_plural_matcher.search(s): wrd=s[0:-2] - if not wrd in rets: rets.append(wrd) + if wrd not in rets: rets.append(wrd) if Language.v_plural_matcher.search(s): rets.append(s[0:-3]+'f') if Language.one_digit_plural_matcher.search(s): diff --git a/src/gourmand/exporters/MarkupString.py b/src/gourmand/exporters/MarkupString.py index aa55848d..436d207e 100644 --- a/src/gourmand/exporters/MarkupString.py +++ b/src/gourmand/exporters/MarkupString.py @@ -47,7 +47,7 @@ def __init__ (self, string): def __getitem__ (self, n): return self.__getslice__(n,n+1) - def __getslice__ (self, s, e): + def __getslice__(self, s, e): # only include relevant elements if not e or e > len(self.raw): e = len(self.raw) elements = [tp for tp in self.handler.elements if (tp[0][1] >= s and # end after the start... @@ -68,8 +68,8 @@ def __getslice__ (self, s, e): etag = ""%name # simple end tag spos = pos[0] epos = pos[1] - if spos < s: spos=s - if epos > e: epos=e + spos = max(spos, s) + epos = min(epos, e) if epos != spos: # we don't care about tags that don't markup any text if spos not in starts: starts[spos]=[] starts[spos].append(stag) diff --git a/src/gourmand/exporters/eatdrinkfeelgood_exporter.py b/src/gourmand/exporters/eatdrinkfeelgood_exporter.py index 6b7c98b3..2b50718b 100644 --- a/src/gourmand/exporters/eatdrinkfeelgood_exporter.py +++ b/src/gourmand/exporters/eatdrinkfeelgood_exporter.py @@ -175,7 +175,7 @@ def write_ingref (self, amount=1, unit=None, item=None, refid=None, optional=False): print('write_ingref not implemented yet') - def write_ing (self, amount=1, unit=None, item=None, + def write_ing(self, amount=1, unit=None, item=None, key=None, optional=False): # item's are the same as keys in cozyland... if not key: key = item @@ -199,12 +199,13 @@ def write_ing (self, amount=1, unit=None, item=None, e_parent.appendChild(e) e_parent = e e_amount = self.xmlDoc.createElement('amount') - if gram_amount: - if not isinstance(gram_amount, (tuple, list)) or None not in gram_amount: - e_amount.appendChild( - self.quantity_element(gram_amount, - 'gram') - ) + if gram_amount and ( + not isinstance(gram_amount, (tuple, list)) or None not in gram_amount + ): + e_amount.appendChild( + self.quantity_element(gram_amount, + 'gram') + ) e_parent.appendChild(e_amount) e_displayamount = self.xmlDoc.createElement('displayamount') e_displayamount.appendChild( @@ -217,10 +218,10 @@ def write_ing (self, amount=1, unit=None, item=None, e_item.appendChild(t) if ndbno: e_usda = self.xmlDoc.createElement('usdaid') - if ndbno: - t = self.xmlDoc.createTextNode("%05i"%ndbno) - e_usda.appendChild(t) - e_parent.appendChild(e_usda) + if ndbno: + t = self.xmlDoc.createTextNode("%05i"%ndbno) + e_usda.appendChild(t) + e_parent.appendChild(e_usda) def write_grouphead (self, name): print('write_grouphead not implemented yet') @@ -228,7 +229,7 @@ def write_grouphead (self, name): def write_groupfoot (self): print('write_groupfoot not implemented yet') - def quantity_element (self, amount, unit): + def quantity_element(self, amount, unit): """Make a quantity element based on our amount and unit. """ customunit = unit not in self.units @@ -243,19 +244,18 @@ def quantity_element (self, amount, unit): e = self.xmlDoc.createElement(typ) e_rng.appendChild(e) e.appendChild(self.n_element(a)) + elif isinstance(amount, (list, tuple)): + # If we have a list here, something's gone a bit screwy... + for possible_n in amount: + try: + e = self.n_element(amount) + except TypeError: + continue + else: + e_qty.appendChild(e) + break else: - if isinstance(amount, (list, tuple)): - # If we have a list here, something's gone a bit screwy... - for possible_n in amount: - try: - e = self.n_element(amount) - except TypeError: - continue - else: - e_qty.appendChild(e) - break - else: - e_qty.appendChild(self.n_element(amount)) + e_qty.appendChild(self.n_element(amount)) # Now for the measure... if unit: e_msr = self.xmlDoc.createElement('measure') diff --git a/src/gourmand/exporters/exportManager.py b/src/gourmand/exporters/exportManager.py index d944c7d4..f6f5f18b 100644 --- a/src/gourmand/exporters/exportManager.py +++ b/src/gourmand/exporters/exportManager.py @@ -168,17 +168,11 @@ def can_export_type (self, name): return name in self.plugins_by_name def get_exporter (self, name): return self.plugins_by_name[name] - def get_single_filters (self): - filters = [] - for plugin in self.plugins: - filters.append(plugin.saveas_single_filters) - return filters - - def get_multiple_filters (self): - filters = [] - for plugin in self.plugins: - filters.append(plugin.saveas_filters) - return filters + def get_single_filters(self): + return [plugin.saveas_single_filters for plugin in self.plugins] + + def get_multiple_filters(self): + return [plugin.saveas_filters for plugin in self.plugins] def register_plugin (self, plugin): name = plugin.saveas_filters[0] diff --git a/src/gourmand/exporters/exporter.py b/src/gourmand/exporters/exporter.py index 84b92614..6df132d2 100644 --- a/src/gourmand/exporters/exporter.py +++ b/src/gourmand/exporters/exporter.py @@ -75,12 +75,11 @@ def __init__ (self, rd, r, out, Pluggable.__init__(self,[BaseExporterPlugin]) SuspendableThread.__init__(self,self.name) - def do_run (self): + def do_run(self): self.write_head() for task in self.order: - if task=='image': - if self._grab_attr_(self.r,'image'): - self.write_image(self.r.image) + if task == 'image' and self._grab_attr_(self.r, 'image'): + self.write_image(self.r.image) if task=='attr': self._write_attrs_() @@ -93,22 +92,24 @@ def do_run (self): # Internal methods -- ideally, subclasses should have no reason to # override any of these methods. @pluggable_method - def _write_attrs_ (self): + def _write_attrs_(self): self.write_attr_head() for a in self.attr_order: txt=self._grab_attr_(self.r,a) debug('_write_attrs_ writing %s=%s'%(a,txt),1) - if txt and ((not isinstance(txt, str)) or txt.strip()): - if (a=='preptime' or a=='cooktime') and a.find("0 ")==0: pass + if ( + txt + and ((not isinstance(txt, str)) or txt.strip()) + and (a not in ['preptime', 'cooktime'] or a.find("0 ") != 0) + ): + if self.convert_attnames: + self.write_attr(REC_ATTR_DIC.get(a,a),txt) else: - if self.convert_attnames: - self.write_attr(REC_ATTR_DIC.get(a,a),txt) - else: - self.write_attr(a,txt) + self.write_attr(a,txt) self.write_attr_foot() @pluggable_method - def _write_text_ (self): + def _write_text_(self): #print 'exporter._write_text_',self.text_attr_order,'!' for a in self.text_attr_order: # This code will never be called for Gourmet @@ -131,10 +132,7 @@ def _write_text_ (self): if self.do_markup: txt=self.handle_markup(s) if not self.use_ml: txt = xml.sax.saxutils.unescape(s) - if self.convert_attnames: - out_a = TEXT_ATTR_DIC.get(a,a) - else: - out_a = a + out_a = TEXT_ATTR_DIC.get(a,a) if self.convert_attnames else a # Goodness this is an ugly way to pass the # time as a parameter... we use try/except to # allow all gourmet exporters to ignore this @@ -424,38 +422,33 @@ def write_attr (self, label, text): #attr = NAME_TO_ATTR[label] self.out.write("%s: %s\n"%(label, text)) - def _grab_attr_ (self, obj, attr): + def _grab_attr_(self, obj, attr): """Grab attribute attr of obj obj. Possibly manipulate the attribute we get to hand out export something readable. """ - if attr=='servings' or attr=='yields' and self.mult: - ret = getattr(obj,attr) - if isinstance(ret, (int, float)): - fl_ret = float(ret) - else: - if ret is not None: - print('WARNING: IGNORING serving value ',ret) - fl_ret = None - if fl_ret: - ret = convert.float_to_frac(fl_ret * self.mult, - fractions=self.fractions) - if attr=='yields' : - yield_unit = self._grab_attr_(obj,'yield_unit') - if yield_unit: - ret = '%s %s'%(ret,yield_unit) # FIXME: i18n? - return ret - else: + if attr != 'servings' and (attr != 'yields' or not self.mult): return exporter._grab_attr_(self,obj,attr) - - def _get_amount_and_unit_ (self, ing): - if self.mult != 1 and self.change_units: - return self.rd.get_amount_and_unit(ing,mult=self.mult,conv=self.conv, - fractions=self.fractions) + ret = getattr(obj,attr) + if isinstance(ret, (int, float)): + fl_ret = float(ret) else: - return self.rd.get_amount_and_unit(ing,mult=self.mult,conv=self.conv, - fractions=self.fractions) + if ret is not None: + print('WARNING: IGNORING serving value ',ret) + fl_ret = None + if fl_ret: + ret = convert.float_to_frac(fl_ret * self.mult, + fractions=self.fractions) + if attr=='yields' : + yield_unit = self._grab_attr_(obj,'yield_unit') + if yield_unit: + ret = '%s %s'%(ret,yield_unit) # FIXME: i18n? + return ret + + def _get_amount_and_unit_(self, ing): + return self.rd.get_amount_and_unit(ing,mult=self.mult,conv=self.conv, + fractions=self.fractions) @pluggable_method def write_ing (self, amount=1, unit=None, item=None, key=None, optional=False): @@ -535,14 +528,14 @@ def _grab_attr_ (self, obj, attr): return ret - def append_referenced_recipes (self): + def append_referenced_recipes(self): for r in self.recipes[:]: reffed = self.rd.db.execute( 'select * from ingredients where recipe_id=%s and refid is not null' % r.id ) for ref in reffed: rec = self.rd.get_rec(ref.refid) - if rec is not None and not rec in self.recipes: + if rec is not None and rec not in self.recipes: self.recipes.append(rec) @pluggable_method @@ -600,16 +593,13 @@ def write_header (self): def write_footer (self): pass - def generate_filename (self, rec, ext, add_id=False): + def generate_filename(self, rec, ext, add_id=False): title=rec.title # get rid of potentially confusing characters in the filename # Windows doesn't like a number of special characters, so for # the time being, we'll just get rid of all non alpha-numeric # characters - ntitle = "" - for c in title: - if re.match("[A-Za-z0-9 ]",c): - ntitle += c + ntitle = "".join(c for c in title if re.match("[A-Za-z0-9 ]",c)) title = ntitle # truncate long filenames max_filename_length = 252 @@ -633,17 +623,15 @@ def recipe_hook (self, rec, filename=None, exporter=None): an index (written to a file specified in write_header.""" pass - def unique_name (self, filename): - if os.path.exists(filename): - n=1 - fn,ext=os.path.splitext(filename) - if ext: dot=os.path.extsep - else: dot="" - while os.path.exists("%s%s%s%s"%(fn,n,dot,ext)): - n += 1 - return "%s%s%s%s"%(fn,n,dot,ext) - else: + def unique_name(self, filename): + if not os.path.exists(filename): return filename + n=1 + fn,ext=os.path.splitext(filename) + dot = os.path.extsep if ext else "" + while os.path.exists("%s%s%s%s"%(fn,n,dot,ext)): + n += 1 + return "%s%s%s%s"%(fn,n,dot,ext) def check_for_sleep (self): if self.terminated: diff --git a/src/gourmand/exporters/recipe_emailer.py b/src/gourmand/exporters/recipe_emailer.py index fa56034a..3e0f11ea 100644 --- a/src/gourmand/exporters/recipe_emailer.py +++ b/src/gourmand/exporters/recipe_emailer.py @@ -79,33 +79,31 @@ def write_email_text (self): self.body += s.getvalue() s.close_really() - def write_email_html (self): + def write_email_html(self): for r in self.recipes: fi = os.path.join(gglobals.tmpdir,"%s.htm"%r.title) - ofi = open(fi,'w') - e=html_exporter.html_exporter(self.rd, - r, - ofi, - conv=self.conv, - embed_css=True, - imagedir="") - ofi.close() + with open(fi,'w') as ofi: + e=html_exporter.html_exporter(self.rd, + r, + ofi, + conv=self.conv, + embed_css=True, + imagedir="") self.attachments.append(fi) for i in e.images: self.attachments.append(i) - def write_email_pdf (self): + def write_email_pdf(self): prefs = pdf_exporter.get_pdf_prefs() for r in self.recipes: fi = os.path.join(gglobals.tmpdir,"%s.pdf"%r.title) - ofi = open(fi,'w') - e = pdf_exporter.PdfExporter(self.rd, - r, - ofi, - conv=self.conv, - change_units=self.change_units, - pdf_args=prefs) - ofi.close() + with open(fi,'w') as ofi: + e = pdf_exporter.PdfExporter(self.rd, + r, + ofi, + conv=self.conv, + change_units=self.change_units, + pdf_args=prefs) self.attachments.append(fi) def send_email_html (self, emailaddress=None, include_plain_text=True): @@ -136,29 +134,27 @@ def __init__ (self, recipes, rd, prefs, conv=None): self.email_options[v[0]]=self.prefs.get(*v) self.option_list.append([k,self.email_options[v[0]]]) - def dont_ask_cb (self, widget, *args): - if widget.get_active(): - self.prefs['emailer_dont_ask']=True - else: - self.prefs['emailer_dont_ask']=False - - def setup_dialog (self, force = False): - if force or not self.prefs.get('emailer_dont_ask',False): - d=de.PreferencesDialog(options=self.option_list, - option_label=_("Email Options"), - value_label="", - dont_ask_cb=self.dont_ask_cb, - dont_ask_custom_text=_("Don't ask before sending e-mail.")) - retlist = d.run() - if retlist: - for o in retlist: - k = o[0] - v = o[1] - pref = self.options[k][0] - self.email_options[pref]=v - self.prefs[pref]=v - - def email (self, address=None): + def dont_ask_cb(self, widget, *args): + self.prefs['emailer_dont_ask'] = bool(widget.get_active()) + + def setup_dialog(self, force = False): + if not force and self.prefs.get('emailer_dont_ask', False): + return + d=de.PreferencesDialog(options=self.option_list, + option_label=_("Email Options"), + value_label="", + dont_ask_cb=self.dont_ask_cb, + dont_ask_custom_text=_("Don't ask before sending e-mail.")) + retlist = d.run() + if retlist: + for o in retlist: + k = o[0] + v = o[1] + pref = self.options[k][0] + self.email_options[pref]=v + self.prefs[pref]=v + + def email(self, address=None): if address: self.emailaddress=address if self.email_options['email_include_body']: self.write_email_text() @@ -166,7 +162,7 @@ def email (self, address=None): self.write_email_html() if self.email_options['email_include_pdf']: self.write_email_pdf() - if not self.email_options['email_include_body'] and not self.email_options['email_include_body']: + if not self.email_options['email_include_body']: de.show_message(_("E-mail not sent"), sublabel=_("You have not chosen to include the recipe in the body of the message or as an attachment.") ) diff --git a/src/gourmand/exporters/rtf_exporter.py b/src/gourmand/exporters/rtf_exporter.py index 08e98802..c57be962 100644 --- a/src/gourmand/exporters/rtf_exporter.py +++ b/src/gourmand/exporters/rtf_exporter.py @@ -53,11 +53,9 @@ def __init__ (self, rd, r, out, ) - def setup_document (self, doc=None, ss=None): - if doc: self.doc=doc - else: self.doc = PyRTF.Document() - if ss: self.ss=ss - else: self.ss = self.doc.StyleSheet + def setup_document(self, doc=None, ss=None): + self.doc = doc or PyRTF.Document() + self.ss = ss or self.doc.StyleSheet self.ss.ParagraphStyles.Normal.TextStyle.TextPropertySet.Font = self.ss.Fonts.TimesNewRoman self.ss.ParagraphStyles.Heading1.TextStyle.TextPropertySet.Bold = True if not hasattr(self.ss.ParagraphStyles, 'Heading3'): diff --git a/src/gourmand/gdebug.py b/src/gourmand/gdebug.py index 9c08c743..1f333b26 100644 --- a/src/gourmand/gdebug.py +++ b/src/gourmand/gdebug.py @@ -15,9 +15,8 @@ if debug_file: print('DEBUG_FILE=',debug_file) -def debug (message, level=10): - if timestamp: ts= '%s:'%time.time() - else: ts = '' +def debug(message, level=10): + ts = '%s:'%time.time() if timestamp else '' if level <= debug_level: stack = traceback.extract_stack() if len(stack) >= 2: @@ -27,10 +26,11 @@ def debug (message, level=10): else: finame = " ".join(stack) line = "" - if args.debug_file: - if debug_file.search(finame): - print("DEBUG: ",ts,"%s: %s"%(finame,line),message) - else: + if ( + args.debug_file + and debug_file.search(finame) + or not args.debug_file + ): print("DEBUG: ",ts,"%s: %s"%(finame,line),message) timers = {} @@ -42,23 +42,24 @@ def __init__ (self, name, level=10): self.name = name self.start = time.time() - def end (self): - if self.level <= debug_level: - end = time.time() - t=end-self.start - # grab our location - stack=traceback.extract_stack() - if len(stack)>2: - caller=stack[-2] - finame=caller[0] - line = caller[1] - else: - finame = " ".join(stack) - line = "" - if not args.debug_file or debug_file.search(finame): - print("DEBUG: %s TOOK %s SECONDS"%(self.name,t)) - if self.name not in timers: timers[self.name]=[t] - else: timers[self.name].append(t) + def end(self): + if self.level > debug_level: + return + end = time.time() + t=end-self.start + # grab our location + stack=traceback.extract_stack() + if len(stack)>2: + caller=stack[-2] + finame=caller[0] + line = caller[1] + else: + finame = " ".join(stack) + line = "" + if not args.debug_file or debug_file.search(finame): + print("DEBUG: %s TOOK %s SECONDS"%(self.name,t)) + if self.name not in timers: timers[self.name]=[t] + else: timers[self.name].append(t) def print_timer_info (): diff --git a/src/gourmand/gglobals.py b/src/gourmand/gglobals.py index daf73101..4e2ed9b5 100644 --- a/src/gourmand/gglobals.py +++ b/src/gourmand/gglobals.py @@ -99,7 +99,6 @@ def add_icon( icon_factory.add_default() # TODO: fix adding icons return - Gtk.stock_add([(stock_id, label, modifier, keyval, "")]) for filename, stock_id, label, modifier, keyval in [ diff --git a/src/gourmand/gtk_extras/LinkedTextView.py b/src/gourmand/gtk_extras/LinkedTextView.py index 7e3f599e..3c9f08b8 100644 --- a/src/gourmand/gtk_extras/LinkedTextView.py +++ b/src/gourmand/gtk_extras/LinkedTextView.py @@ -68,13 +68,12 @@ def get_text(self, if end is None: end = self.get_end_iter() - if include_hidden_chars is False: + if not include_hidden_chars: return super().get_text(start, end, include_hidden_chars) - else: - format_ = self.register_serialize_tagset() - pango_markup = self.serialize(self, format_, start, end) - return PangoToHtml().feed(pango_markup, self.markup_dict, - ignore_links) + format_ = self.register_serialize_tagset() + pango_markup = self.serialize(self, format_, start, end) + return PangoToHtml().feed(pango_markup, self.markup_dict, + ignore_links) class LinkedTextView(Gtk.TextView): @@ -122,8 +121,11 @@ def event_after(self, text_view: 'LinkedTextView', event: Gdk.Event) -> bool: # Check for selection buffer = text_view.get_buffer() selection = buffer.get_selection_bounds() - selecting = not (len(selection) != 0 and - (selection[0].get_offset() != selection[1].get_offset())) + selecting = ( + len(selection) == 0 + or selection[0].get_offset() == selection[1].get_offset() + ) + # Check for a left mouse click (as set by the system, not hardware). if (event.type == Gdk.EventType.BUTTON_RELEASE @@ -152,8 +154,6 @@ def set_cursor_if_appropriate(self, If leaving the area of a time link, set the cursor to an I-beam. """ _, itr = text_view.get_iter_at_location(x, y) - hovering_over_link = False - # Get the tags surrounding the text at the cursor. begin = itr.copy() begin.forward_to_tag_toggle() @@ -163,9 +163,7 @@ def set_cursor_if_appropriate(self, # Check if the text is the content of a link. text = text_view.get_buffer().get_text(begin, end) - if text in text_view.get_buffer().markup_dict: - hovering_over_link = True - + hovering_over_link = text in text_view.get_buffer().markup_dict cursor = self.hand_cursor if hovering_over_link else self.text_cursor text_view.get_window(Gtk.TextWindowType.TEXT).set_cursor(cursor) diff --git a/src/gourmand/gtk_extras/WidgetSaver.py b/src/gourmand/gtk_extras/WidgetSaver.py index 5407bcde..9bd2b608 100644 --- a/src/gourmand/gtk_extras/WidgetSaver.py +++ b/src/gourmand/gtk_extras/WidgetSaver.py @@ -89,10 +89,9 @@ def __init__ (self, prefs, glade=None, hideable_widgets=[], basename='hide_'): self.hideable_widgets = hideable_widgets self.apply_widget_prefs() - def toggle_widget (self, w, val): + def toggle_widget(self, w, val): """Toggle the visibility of widget 'w'""" - if val: method = 'hide' - else: method = 'show' + method = 'hide' if val else 'show' if isinstance(w, str): w = [w] for wn in w: diff --git a/src/gourmand/gtk_extras/cb_extras.py b/src/gourmand/gtk_extras/cb_extras.py index 48774964..d6441962 100644 --- a/src/gourmand/gtk_extras/cb_extras.py +++ b/src/gourmand/gtk_extras/cb_extras.py @@ -16,12 +16,12 @@ def __init__ (self,cbe): def focus_in_cb (self, widget, event): self.e.grab_focus() - def focus_out_cb (self, widget, event): + def focus_out_cb(self, widget, event): if not event.in_ and self.key in ['Tab']: parent = widget.get_parent() while parent and not isinstance(parent,Gtk.Window) : parent = parent.get_parent() - for n in range(2): + for _ in range(2): parent.emit('move-focus',Gtk.DirectionType.RIGHT) #parent.emit('move-focus',Gtk.DIRECTION_LEFT) @@ -36,17 +36,15 @@ def cb_get_active_text (combobox): return None return model[active][0] -def cb_set_active_text (combobox, text, col=0): +def cb_set_active_text(combobox, text, col=0): """Set the active text of combobox to text. We fail if the text is not already in the model. Column is the column of the model from which text is drawn.""" model = combobox.get_model() - n = 0 - for rw in model: + for n, rw in enumerate(model): if rw[col]==text: combobox.set_active(n) return n - n += 1 return None class setup_typeahead: @@ -89,14 +87,12 @@ def key_press_cb (self, widget, event): def reset_str (self, *args): self.string = "" - def match_string_in_combo (self, str): + def match_string_in_combo(self, str): mod = self.cb.get_model() - n = 0 - for r in mod: + for n, r in enumerate(mod): modstr = r[self.col] if modstr.lower().find(str.lower()) == 0: return n - n += 1 def setup_completion (cbe, col=0): diff --git a/src/gourmand/gtk_extras/dialog_extras.py b/src/gourmand/gtk_extras/dialog_extras.py index 8865b665..51901b5f 100644 --- a/src/gourmand/gtk_extras/dialog_extras.py +++ b/src/gourmand/gtk_extras/dialog_extras.py @@ -187,11 +187,7 @@ def __init__(self, default=None, label=False, sublabel=False, step_incr=1, self.vbox.add(self.hbox) self.spinButton = Gtk.SpinButton() - if not default: - val = 0 - else: - val = float(default) - + val = 0 if not default else float(default) self.adjustment = Gtk.Adjustment(val, lower=min, upper=max, @@ -479,10 +475,7 @@ def __init__(self, options=([None, None]), option_label="Option", If apply_func is True, we will have an apply button, which will hand the option tuple as its argument. Otherwise, okay will simply return the list on okay.""" - if apply_func: - modal = False - else: - modal = True + modal = not apply_func self.apply_func = apply_func self.options = options ModalDialog.__init__(self, okay=True, label=label, @@ -539,16 +532,15 @@ def run(self): self.show() if self.apply_func: return - else: - Gtk.main() - return self.ret + Gtk.main() + return self.ret def okcb(self, *args): if self.apply_func: - if self.apply.get_property('sensitive'): - # if there are unsaved changes... - if getBoolean(label="Would you like to apply the changes you've made?"): - self.applycb() + if self.apply.get_property('sensitive') and getBoolean( + label="Would you like to apply the changes you've made?" + ): + self.applycb() self.hide() else: self.table.apply() @@ -1001,7 +993,10 @@ def setup_dialog(self): def setup_buttons(self): """Set our self.buttons attribute""" if not self.buttons: - if self.action == Gtk.FileChooserAction.OPEN or self.action == Gtk.FileChooserAction.SELECT_FOLDER: + if self.action in [ + Gtk.FileChooserAction.OPEN, + Gtk.FileChooserAction.SELECT_FOLDER, + ]: self.buttons = ( Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK) else: @@ -1032,18 +1027,15 @@ def setup_saveas_widget(self): self.do_saveas = False return self.do_saveas = True - n = 0 self.ext_to_filter = {} self.name_to_ext = {} - for name, mimetypes, regexps in self.filters: + for n, (name, mimetypes, regexps) in enumerate(self.filters): # name_to_ext lets us grab the correct extension from our active iter self.name_to_ext[name] = os.path.splitext(regexps[0])[-1] for r in regexps: ext = os.path.splitext(r)[-1] # ext_to_filter let's us select the correct iter from the extension typed in self.ext_to_filter[ext] = self.fsd.list_filters()[n] - n += 1 - self.fn = None self.fsd.connect('notify::filter', self.change_file_extension) self.fsd.connect('selection-changed', self.update_filetype_widget) @@ -1141,10 +1133,7 @@ def post_dialog(self): def update_preview(self, *args): uri = self.fsd.get_uri() - thumbnail = None - if uri is not None: - thumbnail = make_thumbnail(uri) - + thumbnail = make_thumbnail(uri) if uri is not None else None if thumbnail is not None: self.preview.set_from_pixbuf(image_to_pixbuf(thumbnail)) self.preview.show() diff --git a/src/gourmand/gtk_extras/mnemonic_manager.py b/src/gourmand/gtk_extras/mnemonic_manager.py index f9e9837f..fad079d8 100644 --- a/src/gourmand/gtk_extras/mnemonic_manager.py +++ b/src/gourmand/gtk_extras/mnemonic_manager.py @@ -1,7 +1,7 @@ from gi.repository import Gdk, Gtk -def collect_descendants (parent, descendants=None): +def collect_descendants(parent, descendants=None): """Return all descendants of parent widget. Crawls tree recursively. @@ -11,11 +11,9 @@ def collect_descendants (parent, descendants=None): for c in parent.get_children(): if c not in descendants: descendants.append(c) collect_descendants(c,descendants) - if hasattr(parent,'get_submenu'): - #print 'Getting submenu!' - if parent.get_submenu(): - descendants.append(parent.get_submenu()) - collect_descendants(parent.get_submenu(),descendants) + if hasattr(parent, 'get_submenu') and parent.get_submenu(): + descendants.append(parent.get_submenu()) + collect_descendants(parent.get_submenu(),descendants) return descendants class MnemonicManager: @@ -65,7 +63,7 @@ def add_toplevel_widget (self, w): widgets = collect_descendants(w) self.add_ui(widgets) - def add_builder (self, ui=None, ui_file=None): + def add_builder(self, ui=None, ui_file=None): """Add all mnemonic widgets in Gtk.Builder object. We can be passed a Gtk.Builder (.ui) file or a Gtk.Builder object. @@ -80,7 +78,7 @@ def add_builder (self, ui=None, ui_file=None): # Check if there are more than one window, in which case we # each window gets its own sub_handler windows = [w for w in widgets if isinstance(w,Gtk.Window)] - if len(windows)>0: + if windows: for w in windows: self.sub_managers[w]=MnemonicManager() self.sub_managers[w].add_toplevel_widget(w) @@ -88,7 +86,7 @@ def add_builder (self, ui=None, ui_file=None): else: self.add_ui(widgets) - def add_ui (self, widgets): + def add_ui(self, widgets): added = [] # handle menu items menus = [x for x in widgets if isinstance(x,Gtk.Menu)] @@ -146,13 +144,12 @@ def add_ui (self, widgets): if page not in self.notebook_managers[nb]: self.notebook_managers[nb][page]=MnemonicManager() self.notebook_managers[nb][page].add_widget_mnemonic(w) + elif isinstance(w.get_parent(),Gtk.Notebook): + # make notebook tab labels (should be our only + # direct descendant labels) untouchable. + self.add_widget_mnemonic(w,untouchable=True,fix_untouchables=True) else: - if isinstance(w.get_parent(),Gtk.Notebook): - # make notebook tab labels (should be our only - # direct descendant labels) untouchable. - self.add_widget_mnemonic(w,untouchable=True,fix_untouchables=True) - else: - self.add_widget_mnemonic(w) + self.add_widget_mnemonic(w) more_mnemonics = [] def add_treeview (self, tv): @@ -167,7 +164,7 @@ def add_treeview (self, tv): widg.show() self.add_widget_mnemonic(widg) - def add_widget_mnemonic (self, w, untouchable=False, fix_untouchables=False): + def add_widget_mnemonic(self, w, untouchable=False, fix_untouchables=False): k = Gdk.keyval_name(w.get_mnemonic_keyval()) if w.get_text().lower().replace('_','') in self.sacred_cows: untouchable = True; fix_untouchables=False @@ -182,7 +179,7 @@ def add_widget_mnemonic (self, w, untouchable=False, fix_untouchables=False): self.untouchable_accels.append(k) self.untouchable_widgs.append(w) if k not in self.mnemonics: self.mnemonics[k]=[] - if not w in self.mnemonics[k]: + if w not in self.mnemonics[k]: self.mnemonics[k].append(w) def generate_new_mnemonic (self, text): @@ -196,14 +193,13 @@ def generate_new_mnemonic (self, text): self.mnemonics[text[0].lower()].append(text) return '_'+text - def find_alternatives (self, w, filter_untouchables = True): + def find_alternatives(self, w, filter_untouchables = True): text = w.get_text() if not text: return [] cur_ind = text.find('_')+1 alts = [text[cur_ind].lower()] # Now we go through and find first letters of words... - if cur_ind == 1: ind=2 - else: ind = 0 + ind = 2 if cur_ind == 1 else 0 ind = text.find(' ',ind) last_letter_that_could_be_word_start = len(text)-2 while -1 < ind <= last_letter_that_could_be_word_start: @@ -211,9 +207,7 @@ def find_alternatives (self, w, filter_untouchables = True): if alt not in alts: alts.append(alt) ind = text.find(' ',ind+1) for l in list(text): - if l.lower() not in alts: - if l in list(' (),_[]:;,.!{}/=+'): continue - else: alts.append(l.lower()) + if l.lower() not in alts and l not in list(' (),_[]:;,.!{}/=+'): alts.append(l.lower()) if filter_untouchables: alts = [l for l in alts if l not in self.untouchable_accels] return alts diff --git a/src/gourmand/gtk_extras/pageable_store.py b/src/gourmand/gtk_extras/pageable_store.py index a7d61f90..7b047074 100644 --- a/src/gourmand/gtk_extras/pageable_store.py +++ b/src/gourmand/gtk_extras/pageable_store.py @@ -143,17 +143,17 @@ def update_iter (self, itr): self.set(itr,*args) - def update_tree (self): + def update_tree(self): """Update our tree based on current page, etc.""" # clear the existing rows... - for n in range(len(self)): + for _ in range(len(self)): self.remove(self.get_iter(0,)) # and add the new ones... length = self._get_length_() start_at = self.page * self.per_page end_at = (self.page+1) * self.per_page if start_at > length: return # we're empty then... - if end_at > length: end_at = length + end_at = min(end_at, length) for row in self._get_slice_(int(start_at),int(end_at)): try: self.append(row) @@ -243,17 +243,17 @@ def __init__ (self, types, parent_args=[], parent_kwargs={}, per_page=15): self.update_tree() self.sort_dict = {} - def update_tree (self): + def update_tree(self): """Update our tree based on current page, etc.""" # clear the existing rows... - for n in range(len(self)): + for _ in range(len(self)): self.remove(self.get_iter(0,)) # and add the new ones... length = self._get_length_() start_at = self.page * self.per_page end_at = (self.page+1) * self.per_page if start_at > length: return # we're empty then... - if end_at > length: end_at = length + end_at = min(end_at, length) for row in self._get_slice_(int(start_at),int(end_at)): itr=self.append(None,row) self.append_descendants(itr) @@ -288,9 +288,9 @@ def set_sort_column_id (self, tree_column, model_column): #tree_column.set_sort_column_id(model_column) tree_column.connect('clicked',self.sort_by_column_callback,model_column) - def sort_by_column_callback (self,tree_column,model_column): + def sort_by_column_callback(self,tree_column,model_column): toggle_to = self.mod.toggle_sort(model_column) - if toggle_to==None: + if toggle_to is None: tree_column.set_sort_indicator(False) else: tree_column.set_sort_indicator(True) diff --git a/src/gourmand/gtk_extras/pango_buffer.py b/src/gourmand/gtk_extras/pango_buffer.py index 6fd9703d..c0e17f85 100644 --- a/src/gourmand/gtk_extras/pango_buffer.py +++ b/src/gourmand/gtk_extras/pango_buffer.py @@ -53,12 +53,11 @@ def get_text(self, if end is None: end = self.get_end_iter() - if include_hidden_chars is False: + if not include_hidden_chars: return super().get_text(start, end, include_hidden_chars=False) - else: - format_ = self.register_serialize_tagset() - content = self.serialize(self, format_, start, end) - return PangoToHtml().feed(content) + format_ = self.register_serialize_tagset() + content = self.serialize(self, format_, start, end) + return PangoToHtml().feed(content) def get_selection_bounds(self): """A get_selection_bounds that returns either the selection, or diff --git a/src/gourmand/gtk_extras/pango_html.py b/src/gourmand/gtk_extras/pango_html.py index 5b91ff5d..4fe0474d 100644 --- a/src/gourmand/gtk_extras/pango_html.py +++ b/src/gourmand/gtk_extras/pango_html.py @@ -124,12 +124,11 @@ def feed(self, name = attribute['name'] if vtype == "GdkColor": # Convert colours to html - if name in ['foreground-gdk', 'background-gdk']: - opening, closing = self.tag2html[name] - hex_color = self.pango_to_html_hex(value) - opening = opening.format(hex_color) - else: + if name not in ['foreground-gdk', 'background-gdk']: continue # no idea! + opening, closing = self.tag2html[name] + hex_color = self.pango_to_html_hex(value) + opening = opening.format(hex_color) else: opening, closing = self.tag2html.get(value, ('', '')) @@ -169,9 +168,8 @@ def handle_starttag(self, tag: str, attrs: List[Tuple[str, str]]) -> None: self.current_opening_tags.append(opening_tag) self.current_closing_tags.append(closing_tag) - if self.current_opening_tags: - if 'foreground' and '' in self.current_opening_tags[-1]: - self.is_colored_and_underlined = True + if self.current_opening_tags and '' in self.current_opening_tags[-1]: + self.is_colored_and_underlined = True def handle_data(self, data: str) -> None: target = self.links.get(data) diff --git a/src/gourmand/gtk_extras/ratingWidget.py b/src/gourmand/gtk_extras/ratingWidget.py index 7cfe04a8..bf0e345b 100644 --- a/src/gourmand/gtk_extras/ratingWidget.py +++ b/src/gourmand/gtk_extras/ratingWidget.py @@ -66,17 +66,16 @@ def __init__(self, self.pixbufs = {} self.image_files = {} - def get_pixbuf (self,n,max=10): + def get_pixbuf(self,n,max=10): """Return a pixbuf with an image representing n/max stars""" if (n,max) in self.pixbufs: return self.pixbufs[(n,max)] - else: - img = self.build_image(n,max) - pb=self.get_pixbuf_from_image(img) - self.pixbufs[(n,max)]=pb - return pb + img = self.build_image(n,max) + pb=self.get_pixbuf_from_image(img) + self.pixbufs[(n,max)]=pb + return pb def get_full_width (self, max=10): return self.width*max//2 @@ -100,13 +99,13 @@ def get_file (self, n, max=10, ext='.jpg'): self.image_files[(n,max,ext)]=fi return fi - def build_image (self, n, max=10): + def build_image(self, n, max=10): """Build an image representing n/max stars.""" img=Image.new('RGBA', (self.get_full_width(max), self.height), self.background) - for i in range(0,(max//2)): + for i in range(max//2): if i*2+2 <= n: to_paste = self.set_region elif (i*2)+1 <= n: @@ -130,7 +129,7 @@ def get_pixbuf_from_image(self, image, make_white_opaque=True): is_rgba = image.mode == 'RGBA' rowstride = 4 if is_rgba else 3 - pb = GdkPixbuf.Pixbuf.new_from_data( + return GdkPixbuf.Pixbuf.new_from_data( image.tobytes(), GdkPixbuf.Colorspace.RGB, is_rgba, @@ -138,7 +137,6 @@ def get_pixbuf_from_image(self, image, make_white_opaque=True): image.size[0], image.size[1], rowstride * image.size[0]) - return pb star_generator = StarGenerator() @@ -167,12 +165,12 @@ def __init__ (self, self.upper = upper self.set_value(value) - def set_value (self, value): + def set_value(self, value): """Set value. Silently floor value at 0 and cap it at self.upper""" - if value > self.upper: value = self.upper - if value < 0: value = 0 + value = min(value, self.upper) + value = max(value, 0) self.set_from_pixbuf( self.stars.get_pixbuf(value,self.upper) ) diff --git a/src/gourmand/gtk_extras/treeview_extras.py b/src/gourmand/gtk_extras/treeview_extras.py index 7d574818..2331a783 100644 --- a/src/gourmand/gtk_extras/treeview_extras.py +++ b/src/gourmand/gtk_extras/treeview_extras.py @@ -11,14 +11,13 @@ def print_tree (mod): for child in row.iterchildren(): print('-> ',[col for col in child]) -def path_next (path, inc=1): +def path_next(path, inc=1): """Return the path NEXT rows after PATH. Next can be negative, in which case we get previous paths.""" next=list(path[0:-1]) last=path[-1] last += inc - if last < 0: - last=0 + last = max(last, 0) next.append(last) next=tuple(next) return next @@ -71,13 +70,11 @@ def move_iter(mod: Gtk.TreeStore, dpath = () rowdata = get_row(mod, iter) children=harvest_children(mod, iter) - def insert_new (parent): + def insert_new(parent): """A little subroutine to insert our row. We'll call this at the appropriate time depending on the order of source and destination iters""" if not parent: - parent=None - if len(dpath) > 1: - parent=mod.get_iter(dpath[0:-1]) + parent = mod.get_iter(dpath[0:-1]) if len(dpath) > 1 else None if parent==sibling or not sibling: """If our parent is our destination iter or if we have only a parent specified, we're moving inside, not before""" @@ -126,7 +123,7 @@ def harvest_children (mod, iter): child = mod.iter_nth_child(iter, n) return ret -def path_compare (p1, p2): +def path_compare(p1, p2): """Return 1 if p1 > p2, 0 if p1 = p2 and -1 if p1 < p2 Greater than means comes after.""" flag = True @@ -147,12 +144,8 @@ def path_compare (p1, p2): flag=False else: ## otherwise one of these is greater (the longer path comes after/is greater than the shorter) - if len(p1) > len(p2): - retval=1 - flag=False - else: - retval=-1 - flag=False + retval = 1 if len(p1) > len(p2) else -1 + flag=False n += 1 return retval @@ -212,18 +205,15 @@ def rem_selection (self, itr): except ValueError: pass - def restore_selections (self, tv=None): + def restore_selections(self, tv=None): """Restore selections. We can optionally do the unlikely task of restoring selections to a new treeView. This might come in handy w/ dragndrop within an application between treeViews. Otherwise, we remember and use the treeView we were initially handed.""" if tv: self.tv=tv - self.model=self.tv.get_model() - self.selection=self.tv.get_selection() - else: - self.model = self.tv.get_model() - self.selection = self.tv.get_selection() + self.model=self.tv.get_model() + self.selection=self.tv.get_selection() self.selection.unselect_all() itr = self.model.get_iter_first() new_paths=[] @@ -243,10 +233,7 @@ def restore_selections (self, tv=None): itr = next else: parent = self.model.iter_parent(itr) - if parent: - itr = self.model.iter_next(parent) - else: - itr = None + itr = self.model.iter_next(parent) if parent else None class TreeViewConf: """Handed a treeView and two configuration items, this class allows @@ -287,13 +274,11 @@ def apply_column_order (self): else: debug("There is no column in position %s"%n,4) - def save_column_change_cb (self,tv): + def save_column_change_cb(self,tv): self.order = {} - n=0 - for c in tv.get_columns(): + for n, c in enumerate(tv.get_columns()): titl=c.get_title() self.order[titl]=n - n += 1 class QuickTree (Gtk.ScrolledWindow): def __init__ (self, rows, titles=None): diff --git a/src/gourmand/gtk_extras/validation.py b/src/gourmand/gtk_extras/validation.py index d6ad334e..5ce4bb1a 100644 --- a/src/gourmand/gtk_extras/validation.py +++ b/src/gourmand/gtk_extras/validation.py @@ -74,7 +74,7 @@ def set_warning_text(self, text: str): self.warning.set_use_markup(True) def _show_warning(self): - if not self.warned > 0: + if self.warned <= 0: self.warned = time.time() self.warning_box.show_all() @@ -165,8 +165,11 @@ def find_errors_in_progress(self, text: str) -> Optional[str]: partial_unit = '' has_number = NUMBER_MATCHER.match(number) - has_unit = any([unit.startswith(partial_unit) - for unit in self.conv.unit_to_seconds.keys()]) + has_unit = any( + unit.startswith(partial_unit) + for unit in self.conv.unit_to_seconds.keys() + ) + if not (has_number and has_unit): return self._error_msg @@ -225,15 +228,14 @@ def find_completed_errors(self, text: str): def set_value(self, number: int): if self.default_to_fractions: self.set_text(float_to_frac(number, fractions=FRACTIONS_ASCII)) + elif self.decimals >= 0: + decimals = self.decimals + while number < 10 ** -decimals: + decimals += 1 + format_string = "%" + "." + "%i" % decimals + "f" + self.set_text(format_string % number) else: - if self.decimals >= 0: - decimals = self.decimals - while number < 10 ** -decimals: - decimals += 1 - format_string = "%" + "." + "%i" % decimals + "f" - self.set_text(format_string % number) - else: - self.set_text(str(number)) + self.set_text(str(number)) def get_value(self) -> float: return frac_to_float(self.get_text()) diff --git a/src/gourmand/image_utils.py b/src/gourmand/image_utils.py index 09622365..4d2718d2 100644 --- a/src/gourmand/image_utils.py +++ b/src/gourmand/image_utils.py @@ -100,11 +100,8 @@ def pixbuf_to_image(pixbuf: Pixbuf) -> Image.Image: width = pixbuf.props.width height = pixbuf.props.height stride = pixbuf.props.rowstride - mode = "RGB" - if pixbuf.props.has_alpha: - mode = "RGBA" - image = Image.frombytes(mode, (width, height), data, "raw", mode, stride) - return image + mode = "RGBA" if pixbuf.props.has_alpha else "RGB" + return Image.frombytes(mode, (width, height), data, "raw", mode, stride) def image_to_pixbuf(image: Image.Image) -> Pixbuf: diff --git a/src/gourmand/importers/generic_recipe_parser.py b/src/gourmand/importers/generic_recipe_parser.py index 0c3352e2..32edd727 100644 --- a/src/gourmand/importers/generic_recipe_parser.py +++ b/src/gourmand/importers/generic_recipe_parser.py @@ -5,18 +5,17 @@ from gourmand.i18n import _ -def parse_group (match, text, group_number, tag): +def parse_group(match, text, group_number, tag): start,end = match.span(group_number) if start==-1: return None - else: - retv = [] - if start > 0: - retv.append((text[0:start],None)) - retv.append((text[start:end],tag)) - if end < len(text): - retv.append((text[end:],None)) - return retv + retv = [] + if start > 0: + retv.append((text[0:start],None)) + retv.append((text[start:end],tag)) + if end < len(text): + retv.append((text[end:],None)) + return retv class RecipeParser: @@ -196,7 +195,7 @@ def parse (self, txt, parentThread=None): self.join_the_joinable() return self.parsed - def join_the_joinable (self): + def join_the_joinable(self): """Go through self.parsed and join joinable elements. This means: produce fewer elements to jump through for the @@ -225,7 +224,7 @@ def join_the_joinable (self): if n > 1: self.parsed = self.parsed[0:-(n-1)] break - if oldtag == None: + if oldtag is None: add_on += oldchunk else: break diff --git a/src/gourmand/importers/html_importer.py b/src/gourmand/importers/html_importer.py index db5d34d6..761fb4a8 100644 --- a/src/gourmand/importers/html_importer.py +++ b/src/gourmand/importers/html_importer.py @@ -136,7 +136,7 @@ def apply_rule (self, rule): tag = self.get_tag_according_to_path(tagpath) self.store_tag(store_as,tag,retmethod,post_processing) - def post_process (self, post_processing, value, tag): + def post_process(self, post_processing, value, tag): """Post process value according to post_processing post_processing is either callable (and will return a modified @@ -154,9 +154,8 @@ def post_process (self, post_processing, value, tag): regexp=re.compile(post_processing[0],re.UNICODE) m=regexp.search(value) if m: return m.groups()[0] - else: - if post_processing[1]: return "" - else: return value + if post_processing[1]: return "" + else: return value elif callable(post_processing): return post_processing(value,tag) else: @@ -175,7 +174,7 @@ def get_tag_according_to_path (self, path): break return base - def follow_path (self, base, step): + def follow_path(self, base, step): """Follow step from base of base. Base is a tag. Step is a set of instructions as a dictionary. @@ -225,30 +224,25 @@ def follow_path (self, base, step): break if isinstance(ind, (list, tuple)): return ret[ind[0]:ind[1]] - else: #ind is an integer - if ind < len(ret): - return ret[ind] - else: - print('Problem following path.') - print('I am supposed to get item: ',ind) - print('from: ',ret) - print('instructions were : ', end=' ') - try: print('base: ',base) - except UnicodeDecodeError: print('(ugly unicodeness)') - try: print('step: ',step) - except UnicodeDecodeError: print('(ugly unicodeness)') - - def store_tag (self, name, tag, method, post_processing=None): + if ind < len(ret): + return ret[ind] + print('Problem following path.') + print('I am supposed to get item: ',ind) + print('from: ',ret) + print('instructions were : ', end=' ') + try: print('base: ',base) + except UnicodeDecodeError: print('(ugly unicodeness)') + try: print('step: ',step) + except UnicodeDecodeError: print('(ugly unicodeness)') + + def store_tag(self, name, tag, method, post_processing=None): """Store our tag in our dictionary according to our method.""" if isinstance(tag, list): for t in tag: self.store_tag(name,t,method,post_processing) return - if method==self.TEXT: - if tag: val = get_text(tag) - else: val = "" - elif method==self.MARKUP: - if tag: val = tag.prettify() - else: val = "" + if method == self.TEXT and tag: val = get_text(tag) + elif method == self.TEXT or method == self.MARKUP and not tag: val = "" + elif method == self.MARKUP: val = tag.prettify() else: #otherwise, we assume our method is an attribute name val = "" if tag: @@ -331,7 +325,7 @@ def __call__ (self, top_tag, strip=True): def add_tag (self, t): for item in t.contents: self.get_text_fancy(item) - def get_text_fancy (self, item): + def get_text_fancy(self, item): #print 'get_text_fancy looking at:',item if self.text and hasattr(item,'name'): if item.name in self.IGNORE: return @@ -355,7 +349,7 @@ def get_text_fancy (self, item): if hasattr(item,'name'): print(item.name) if hasattr(item,'fetchParents'): - print('CHILD OF: ','<'.join([p.name for p in item.fetchParents()])) + print('CHILD OF: ', '<'.join(p.name for p in item.fetchParents())) get_text = FancyTextGetter() @@ -393,7 +387,7 @@ def add_to_fn (fn): except: return f + "%s1"%os.path.extsep + e -def import_url (url, rd, progress=None, add_webpage_source=True, threaded=False, +def import_url(url, rd, progress=None, add_webpage_source=True, threaded=False, interactive=True): """Import information from URL. We handle HTML with scrape_url. @@ -422,9 +416,8 @@ def import_url (url, rd, progress=None, add_webpage_source=True, threaded=False, fn = os.path.join(tempfile.tempdir,url.split('/')[-1]) while os.path.exists(fn): fn=add_to_fn(fn) - ofi = open(fn,'w') - ofi.write(get_url(sock,progress)) - ofi.close() + with open(fn,'w') as ofi: + ofi.write(get_url(sock,progress)) return [fn] class WebPageImporter (importer.Importer): @@ -512,7 +505,7 @@ def run (self): if self.prog: self.prog(1,_('Import complete.')) return - def get_url_based_on_template (self): + def get_url_based_on_template(self): """Get URL based on template stored in d """ self.start_rec() @@ -556,11 +549,8 @@ def get_url_based_on_template (self): self.commit_ing() continue - # Listy stuff... elif isinstance(v, list): - if k in self.JOIN_AS_PARAGRAPHS: v = "\n".join(v) - else: v = " ".join(v) - + v = "\n".join(v) if k in self.JOIN_AS_PARAGRAPHS else " ".join(v) # Ingredients in blocks if k == 'ingredient_block': for l in v.split('\n'): diff --git a/src/gourmand/importers/importManager.py b/src/gourmand/importers/importManager.py index 6c03746f..a53562c0 100644 --- a/src/gourmand/importers/importManager.py +++ b/src/gourmand/importers/importManager.py @@ -233,16 +233,12 @@ def get_tempfilename(self, url: str, """ if url in self.tempfiles: return self.tempfiles[url] - else: - fn = url.split('/')[-1] - if '.' in fn: - ext = fn.split('.')[-1] - elif content_type: - ext = self.guess_extension(content_type) - if ext: - tf = tempfile.mkstemp('.' + ext) - else: - tf = tempfile.mkstemp() + fn = url.split('/')[-1] + if '.' in fn: + ext = fn.split('.')[-1] + elif content_type: + ext = self.guess_extension(content_type) + tf = tempfile.mkstemp('.' + ext) if ext else tempfile.mkstemp() self.tempfiles[url] = tf with open(tf, "wb") as fout: fout.write(data) diff --git a/src/gourmand/importers/importer.py b/src/gourmand/importers/importer.py index 30024d0b..c44a08d3 100644 --- a/src/gourmand/importers/importer.py +++ b/src/gourmand/importers/importer.py @@ -41,7 +41,7 @@ class Importer (SuspendableThread): self.rec and then commits that dictionary with commit_rec(). Similarly, ingredients are built as self.ing and then committed with commit_ing().""" - def __init__ (self, + def __init__(self, rd = None, # OBSOLETE total=0, prog=None, # OBSOLETE @@ -61,11 +61,12 @@ def __init__ (self, self.id_converter = {} # a dictionary for tracking named IDs self.total = total if prog or rd: - import traceback; traceback.print_stack() - if prog: - print('WARNING: ',self,'handed obsolete parameter prog=',prog) - if rd: - print('WARNING: ',self,'handed obsolete parameter rd=',rd) + import traceback + traceback.print_stack() + if prog: + print('WARNING: ',self,'handed obsolete parameter prog=',prog) + if rd: + print('WARNING: ',self,'handed obsolete parameter rd=',rd) self.do_markup=do_markup self.count = 0 self.rd = get_recipe_manager() @@ -110,11 +111,9 @@ def do_run (self): #self.rd.add_hooks = self.rd_orig_hooks #print_timer_info() - def _run_cleanup_ (self): - if self.do_conversion: - # if we have something to convert - if self.rating_converter.to_convert: - self.rating_converter.do_conversions(self.rd) + def _run_cleanup_(self): + if self.do_conversion and self.rating_converter.to_convert: + self.rating_converter.do_conversions(self.rd) def check_for_sleep (self): timeaction = TimeAction('importer.check_for_sleep',10) @@ -129,7 +128,7 @@ def check_for_sleep (self): time.sleep(1) timeaction.end() - def start_rec (self, dict=None): + def start_rec(self, dict=None): self.rec_timer = TimeAction('importer RECIPE IMPORT',10) timeaction = TimeAction('importer.start_rec',10) self.check_for_sleep() @@ -138,10 +137,7 @@ def start_rec (self, dict=None): print('Unadded ingredients: ',self.added_ings) self.added_ings=[] self.group = None - if dict: - self.rec=dict - else: - self.rec = {} + self.rec = dict or {} #if not self.rec.has_key('id'): #else: # self.rec['id']=self.rd.new_id() @@ -165,7 +161,7 @@ def _move_to_instructions (self, recdic, attr): recdic['instructions']=recdic['instructions']+'\n'+text_to_add del recdic[attr] - def commit_rec (self): + def commit_rec(self): timeaction = TimeAction('importer.commit_rec',10) for key in ['cuisine','category','title']: if key in self.rec: @@ -235,10 +231,7 @@ def commit_rec (self): del self.rec['image'] del self.rec['thumb'] ## if we have an ID, we need to remember it for the converter - if 'id' in self.rec: - id_to_convert = self.rec['id'] - else: - id_to_convert = None + id_to_convert = self.rec['id'] if 'id' in self.rec else None if id_to_convert: if self.rec['id'] in self.id_converter: self.rec['id']=self.id_converter[self.rec['id']] @@ -273,25 +266,25 @@ def commit_rec (self): _("Imported %s of %s recipes.")%(self.count,self.total) ) - def parse_yields (self, str): + def parse_yields(self, str): '''Parse number and field.''' m = re.match(r"(?P\w+\s+)?(?P[0-9/. ]+)(?P\s*\w+)?",str) - if m: - num = m.group('num') - num = convert.frac_to_float(num) - unit = (m.group('unit') or '').strip() - prefix = (m.group('prefix') or '').strip() - if not unit: - if prefix in ['Serves','Feeds']: - unit = 'servings' - elif prefix: - if prefix not in ['Makes','Yields']: - print('Warning: parse_yields ignoring prefix, "%(prefix)s" in "%(str)s"'%locals()) - if not unit: unit='servings' # default/fallback - return num,unit - else: + if not m: return None,None + num = m.group('num') + num = convert.frac_to_float(num) + unit = (m.group('unit') or '').strip() + prefix = (m.group('prefix') or '').strip() + if not unit: + if prefix in ['Serves','Feeds']: + unit = 'servings' + elif prefix: + if prefix not in ['Makes','Yields']: + print('Warning: parse_yields ignoring prefix, "%(prefix)s" in "%(str)s"'%locals()) + if not unit: unit='servings' # default/fallback + return num,unit + def convert_str_to_num (self, str): """Return a numerical servings value""" timeaction = TimeAction('importer.convert_str_to_num',10) @@ -323,7 +316,7 @@ def start_ing (self, **kwargs): #debug('ing ID %s, recipe ID %s'%(self.ing['recipe_id'],self.rec['id']),0) timeaction.end() - def finish_ing (self): + def finish_ing(self): timeaction = TimeAction('importer.finish_ing 1',10) # Strip whitespace... for key in ['item','ingkey','unit']: @@ -344,10 +337,13 @@ def finish_ing (self): timeaction.end() # if we have an amount (and it's not None), let's convert it # to a number - if 'amount' in self.ing and self.ing['amount']\ - and 'rangeamount' not in self.ing: - if convert.RANGE_MATCHER.search(str(self.ing['amount'])): - self.ing['amount'],self.ing['rangeamount']=parse_range(self.ing['amount']) + if ( + 'amount' in self.ing + and self.ing['amount'] + and 'rangeamount' not in self.ing + and convert.RANGE_MATCHER.search(str(self.ing['amount'])) + ): + self.ing['amount'],self.ing['rangeamount']=parse_range(self.ing['amount']) if 'amount' in self.ing: self.ing['amount']=convert.frac_to_float( self.ing['amount'] @@ -366,7 +362,8 @@ def finish_ing (self): self.ing['inggroup']=self.group timeaction.end() timeaction = TimeAction('importer.commit_ing 4',10) - self.added_ings.append(self.ing); self.ing = {} + self.added_ings.append(self.ing) + self.ing = {} timeaction.end() commit_ing = finish_ing diff --git a/src/gourmand/importers/interactive_importer.py b/src/gourmand/importers/interactive_importer.py index 801ee94c..17d3f8d3 100644 --- a/src/gourmand/importers/interactive_importer.py +++ b/src/gourmand/importers/interactive_importer.py @@ -93,22 +93,22 @@ class InteractiveImporter (ConvenientImporter, NotThreadSafe): NEW_REC_TEXT = _('New Recipe') - def __init__ (self, + def __init__(self, custom_parser = None, tags=DEFAULT_TAGS, tag_labels=DEFAULT_TAG_LABELS, modal=True, title=_('Import recipe')): self.title = title - if custom_parser: self.parser = custom_parser - else: self.parser = RecipeParser() + self.parser = custom_parser or RecipeParser() self.labels_by_tag = tag_labels self.tags_by_label = {self.NEW_REC_TEXT:'newrec'} for k,v in list(self.labels_by_tag.items()): self.tags_by_label[v]=k self.tags = tags self.setup_window() self.setup_action_area() - self.markup_marks = {}; self.markup_partners = {} + self.markup_marks = {} + self.markup_partners = {} self.anchors = [] self.midno = 0 # an ID counter for markup marks we insert self.labelled = [] @@ -375,15 +375,12 @@ def remove_markup_text (self, idno): self.tb.get_iter_at_mark(emark)) self.tb.delete(sitr,eitr) - def clear_tags (self, *args): + def clear_tags(self, *args): """Clear all markup in current selection, or whole buffer if there is no selection """ cursel = self.tb.get_selection_bounds() - if cursel: - st,end = cursel - else: - st,end = self.tb.get_bounds() + st,end = cursel or self.tb.get_bounds() st_offset = st.get_offset() e_offset = end.get_offset() for idno,iters in list(self.markup_marks.items()): @@ -479,11 +476,11 @@ def set_text (self, txt): txt = self.parser.parse(txt) # Parse self.set_parsed(txt) - def set_parsed (self, parsed): + def set_parsed(self, parsed): #dbg_file = open('/tmp/out','w') for chunk,tag in parsed: #dbg_file.write(chunk) - if tag==None: + if tag is None: self.tb.insert(self.tb.get_end_iter(), chunk) else: @@ -508,10 +505,9 @@ def do_run (self): ii = InteractiveImporter() ii.w.connect('delete-event',Gtk.main_quit) ii.w.show_all() - if True: - ii.images = ['http://thinkle.github.io/gourmet/images/screenshots/CardView.png'] - ii.set_text( - """ + ii.images = ['http://thinkle.github.io/gourmet/images/screenshots/CardView.png'] + ii.set_text( + """ Quick Pesto Dinner Category: Quick, Easy, Summer diff --git a/src/gourmand/keymanager.py b/src/gourmand/keymanager.py index 6bf3cbcb..8c22133b 100644 --- a/src/gourmand/keymanager.py +++ b/src/gourmand/keymanager.py @@ -40,7 +40,7 @@ def _snip_notes(s: str) -> str: return s ret = s[:m.start()].strip() - return ret if ret else s + return ret or s def initialize_from_defaults(self): dics = [] @@ -94,9 +94,8 @@ def grab_ordered_key_list(self, str): added_gk = True if not nwlst.__contains__(key): nwlst.append(key) - if not added_gk: - if not nwlst.__contains__(gk): - nwlst.append(gk) + if not added_gk and not nwlst.__contains__(gk): + nwlst.append(gk) return nwlst def get_key_fast(self, s) -> str: @@ -104,9 +103,8 @@ def get_key_fast(self, s) -> str: sort_by=[('count', 1)]) if srch: return srch[-1].ingkey - else: - s = self._snip_notes(s) - return self.generate_key(s) + s = self._snip_notes(s) + return self.generate_key(s) def get_key(self, txt: str, certainty: Optional[float] = 0.61) -> str: """Grab a single key. This is simply a best guess at the @@ -117,10 +115,9 @@ def get_key(self, txt: str, certainty: Optional[float] = 0.61) -> str: txt = self._snip_notes(txt) result = self.look_for_key(txt) if result and result[0][0] and result[0][1] > certainty: - k = result[0][0] + return result[0][0] else: - k = self.generate_key(txt) - return k + return self.generate_key(txt) def look_for_key(self, txt: str) -> Optional[List[Tuple[str, float]]]: """Given a key, return a sorted list of potential matching known keys. @@ -138,8 +135,7 @@ def look_for_key(self, txt: str) -> Optional[List[Tuple[str, float]]]: retvals = defaultdict(float) # First look for matches for our full text (or full text +/- s) - main_txts = [txt] - main_txts.extend(defaults.guess_singulars(txt)) + main_txts = [txt, *defaults.guess_singulars(txt)] if len(main_txts) == 1: main_txts.extend(defaults.guess_plurals(txt)) @@ -178,7 +174,7 @@ def look_for_key(self, txt: str) -> Optional[List[Tuple[str, float]]]: if not word: return srch = self.rm.fetch_all(self.rm.keylookup_table, word=word) - total_count = sum([m.count for m in srch]) + total_count = sum(m.count for m in srch) for match in srch: # We have a lovely ratio. # @@ -192,7 +188,7 @@ def look_for_key(self, txt: str) -> Optional[List[Tuple[str, float]]]: # of words we're dealing with. ik = match.ingkey words_in_key = len(ik.split()) - wordcount = words_in_key if words_in_key > nwords else nwords + wordcount = max(words_in_key, nwords) retvals[ik] += (match.count / total_count) * (1 / wordcount) # Add some probability if our word shows up in the key @@ -216,7 +212,6 @@ def generate_key(self, ingr: str) -> str: # if there are no commas, we see if it makes sense # to turn, e.g. whole-wheat bread into bread, whole-wheat words = ingr.split() - if len(words) >= 2: - if self.cats.__contains__(words[-1]): - ingr = f'{words[-1]}, {"".join(words[0:-1])}' + if len(words) >= 2 and self.cats.__contains__(words[-1]): + ingr = f'{words[-1]}, {"".join(words[0:-1])}' return ingr diff --git a/src/gourmand/main.py b/src/gourmand/main.py index af2e69ea..de4a1a9b 100644 --- a/src/gourmand/main.py +++ b/src/gourmand/main.py @@ -105,12 +105,12 @@ def toggleFractions (prefname,use): ) # Convenience method for showing progress dialogs for import/export/deletion - def show_progress_dialog (self, thread, progress_dialog_kwargs=None, + def show_progress_dialog(self, thread, progress_dialog_kwargs=None, message=_("Import paused"), stop_message=_("Stop import")): """Show a progress dialog""" if progress_dialog_kwargs is None: - progress_dialog_kwargs = dict() + progress_dialog_kwargs = {} name = getattr(thread, 'name', '') for k,v in [('okay',True), ('label',name), @@ -274,21 +274,20 @@ def update_attribute_model(self, attribute: str) -> Gtk.ListStore: for n, item in enumerate(slist): if model[n][0] == item: continue - else: - # See if we match something later in the model -- if - # we do, suck up the whole model - additional = 1 - found_match = False - while len(model) > (n+additional): - if model[n+additional][0] == item: - while additional > 0: - model.remove(model.get_iter(n)) - additional -= 1 - found_match = False - break - additional += 1 - if not found_match: - model.insert(n,[item]) + # See if we match something later in the model -- if + # we do, suck up the whole model + additional = 1 + found_match = False + while len(model) > (n+additional): + if model[n+additional][0] == item: + while additional > 0: + model.remove(model.get_iter(n)) + additional -= 1 + found_match = False + break + additional += 1 + if not found_match: + model.insert(n,[item]) while len(model) > len(slist): last = model.get_iter(len(model) - 1) model.remove(last) @@ -388,7 +387,7 @@ def save (self, file=None, db=None, xml=None): self.message(_("Saved!")) self.loader.save_active_plugins() # relies on us being a pluggable... - def quit (self): + def quit(self): # TODO: check if this method is called. for c in self.conf: c.save_properties() @@ -415,29 +414,28 @@ def quit (self): custom_yes=Gtk.STOCK_QUIT, custom_no=_("Don't exit!"), cancel=False) - if quit_anyway: - for t in threads: - if t.getName() !='MainThread': - try: - t.terminate() - except: - debug("Unable to terminate thread %s"%t,0) - # try not to lose data if this is going to - # end up in a force quit - #self.save_default() - return True - if not use_threads: - for t in self._threads: - try: - t.terminate() - self.threads = self.threads - 1 - except: - # try not to lose data if this is going to - # end up in a force quit - #self.save_default() - return True - else: + if not quit_anyway: return True + for t in threads: + if t.getName() !='MainThread': + try: + t.terminate() + except: + debug("Unable to terminate thread %s"%t,0) + # try not to lose data if this is going to + # end up in a force quit + #self.save_default() + return True + if not use_threads: + for t in self._threads: + try: + t.terminate() + self.threads = self.threads - 1 + except: + # try not to lose data if this is going to + # end up in a force quit + #self.save_default() + return True # Delete our deleted ingredient keys -- we don't need these # for posterity since there is no "trash" interface for # ingredients anyway. @@ -564,16 +562,22 @@ def purge_all (self, *args): self.update_from_db() class UnitModel (Gtk.ListStore): - def __init__ (self, converter): + def __init__(self, converter): debug('UnitModel.__init__',5) self.conv = converter Gtk.ListStore.__init__(self, str, str) # the first item of each conv.units ## areckx: is there a reason why this is formatted this way? - lst = [(a[1][0],a[0]) for a in [x for x in self.conv.units if not (x[1][0] in converter.unit_to_seconds - or - x[0] in converter.unit_to_seconds - )]] + lst = [ + (a[1][0], a[0]) + for a in [ + x + for x in self.conv.units + if x[1][0] not in converter.unit_to_seconds + and x[0] not in converter.unit_to_seconds + ] + ] + ## lst.sort() for ulong,ushort in lst: @@ -717,7 +721,7 @@ def copy_recipes_callback(self, action: Gtk.Action): ce = ClipboardExporter(list(zip(recipes, ingredients))) ce.export() - def batch_edit_recs (self, *args): + def batch_edit_recs(self, *args): recs = self.get_selected_recs_from_rec_tree() if not hasattr(self,'batchEditor'): self.batchEditor = batchEditor.BatchEditor(self) @@ -727,7 +731,7 @@ def batch_edit_recs (self, *args): if self.batchEditor.values: changes = self.batchEditor.values only_where_blank = self.batchEditor.setFieldWhereBlank - attributes = ', '.join([_(k) for k in list(changes.keys())]) + attributes = ', '.join(_(k) for k in list(changes.keys())) msg = ngettext('Set %(attributes)s for %(num)s selected recipe?', 'Set %(attributes)s for %(num)s selected recipes?', len(recs))%{'attributes':attributes, @@ -899,10 +903,8 @@ def toggleToolbar (prefname,use): # user settings toggleToolbar(None, self.prefs.get('showToolbar',True)) - def configure_columns (self, retcolumns): - hidden=[] - for c,v in retcolumns: - if not v: hidden.append(c) + def configure_columns(self, retcolumns): + hidden = [c for c,v in retcolumns if not v] self.rectree_conf.hidden=self.prefs['rectree_hidden_columns']=hidden self.rectree_conf.apply_visibility() @@ -1121,16 +1123,14 @@ def show (): GObject.idle_add(show) # Deletion - def show_deleted_recs (self, *args): + def show_deleted_recs(self, *args): if not hasattr(self,'recTrash'): self.recTrash = RecTrash(self.rg) - self.recTrash.show() - else: - self.recTrash.show() + self.recTrash.show() - def rec_tree_keypress_cb (self, widget, event): + def rec_tree_keypress_cb(self, widget, event): keyname = Gdk.keyval_name(event.keyval) - if keyname == 'Delete' or keyname == 'BackSpace': + if keyname in ['Delete', 'BackSpace']: self.rec_tree_delete_rec_cb() return True @@ -1161,11 +1161,8 @@ def delete_open_card_carefully (self, rec): self.del_rc(rec.id) @plugin_loader.pluggable_method - def rec_tree_delete_recs (self, recs): - cancelled = [] - for rec in recs: - if self.delete_open_card_carefully(rec): # returns True if user cancels - cancelled.append(rec) + def rec_tree_delete_recs(self, recs): + cancelled = [rec for rec in recs if self.delete_open_card_carefully(rec)] if cancelled: for c in cancelled: recs.remove(c) self.rd.undoable_delete_recs( diff --git a/src/gourmand/plugin.py b/src/gourmand/plugin.py index 6c9e7349..856f3c8f 100644 --- a/src/gourmand/plugin.py +++ b/src/gourmand/plugin.py @@ -191,12 +191,9 @@ def add_field (self, field_name, field_fetcher, values will not print. ''' if type==self.TEXT: - def do_write (*args): + def do_write(*args): #print 'do_write received arguments',args - if position==plugin_loader.POST: - klass = args[1] - else: - klass = args[0] + klass = args[1] if position==plugin_loader.POST else args[0] val = field_fetcher(klass.r) if klass.do_markup: val = klass.handle_markup(val) @@ -205,12 +202,9 @@ def do_write (*args): klass.write_text(field_name,val) self.hooks_to_add.append((position,'_write_text_',do_write)) else: - def do_write (*args): + def do_write(*args): #print 'do_write received arguments',args - if position==plugin_loader.POST: - klass = args[1] - else: - klass = args[0] + klass = args[1] if position==plugin_loader.POST else args[0] val = field_fetcher(klass.r) if klass.do_markup: val = klass.handle_markup(val) @@ -485,7 +479,7 @@ def save (self, recdict): self.emit('saved') return recdict - def undo_action_callback (self, undo_history, action, typ): + def undo_action_callback(self, undo_history, action, typ): # For all actions that go into the undo system, not just UNDO widget = action.widget #prop = self.get_prop_for_widget(widget) @@ -518,35 +512,25 @@ def undo_action_callback (self, undo_history, action, typ): del self.re.widgets_changed_since_save[prop] else: self.re.widgets_changed_since_save[prop]=val - else: - # If we can't compare with original values, we keep a - # dictionary of all changes made on a per-widget basis. - if not widget: - self.re.widgets_changed_since_save['UntrackableChange']=True + elif not widget: + self.re.widgets_changed_since_save['UntrackableChange']=True + elif widget in self.re.widgets_changed_since_save: + old_change = self.re.widgets_changed_since_save[widget][-1] + if (old_change.is_undo != action.is_undo + and + old_change not in undo_history): + # If we are the inverse of the old action and + # the old action is no longer in history, then + # we can assume (safely?) that we have undone + # the old action + del self.re.widgets_changed_since_save[widget][-1] + if not self.re.widgets_changed_since_save[widget]: + del self.re.widgets_changed_since_save[widget] else: - # We store each change in our dictionary... if the - # change has disappeared from the history list, then - # we can surmise it has been "undone" - if widget in self.re.widgets_changed_since_save: - old_change = self.re.widgets_changed_since_save[widget][-1] - if (old_change.is_undo != action.is_undo - and - old_change not in undo_history): - # If we are the inverse of the old action and - # the old action is no longer in history, then - # we can assume (safely?) that we have undone - # the old action - del self.re.widgets_changed_since_save[widget][-1] - if not self.re.widgets_changed_since_save[widget]: - del self.re.widgets_changed_since_save[widget] - else: - self.re.widgets_changed_since_save[widget].append(action) - else: - self.re.widgets_changed_since_save[widget]=[action] - if self.re.widgets_changed_since_save: - self.edited = True + self.re.widgets_changed_since_save[widget].append(action) else: - self.edited = False + self.re.widgets_changed_since_save[widget]=[action] + self.edited = bool(self.re.widgets_changed_since_save) def grab_focus (self): """Put focus on appropriate widget for editing.""" diff --git a/src/gourmand/plugin_gui.py b/src/gourmand/plugin_gui.py index f65caed9..7cba08a3 100644 --- a/src/gourmand/plugin_gui.py +++ b/src/gourmand/plugin_gui.py @@ -104,7 +104,7 @@ def toggled_cb (self, renderer, path, tv): self.do_change_plugin(plugin_set, state, ls) ls[path][0] = state - def do_change_plugin (self, plugin_set, state, ls): + def do_change_plugin(self, plugin_set, state, ls): try: if state: try: @@ -121,20 +121,28 @@ def do_change_plugin (self, plugin_set, state, ls): else: dependers = self.loader.check_if_depended_upon(plugin_set) if dependers: - if de.getBoolean( - label=_("Plugin is needed for other plugins. Deactivate plugin anyway?"), - sublabel=(_('The following plugins require %s:'%plugin_set.name) + '\n' + - '\n'.join(plugin_set.name for plugin_set in dependers) - ), + if not de.getBoolean( + label=_( + "Plugin is needed for other plugins. Deactivate plugin anyway?" + ), + sublabel=( + _( + 'The following plugins require %s:' + % plugin_set.name + ) + + '\n' + + '\n'.join( + plugin_set.name for plugin_set in dependers + ) + ), custom_yes=_('Deactivate anyway'), - custom_no=_('Keep plugin active') - ): - self.loader.deactivate_plugin_set(plugin_set) - for row in ls: - if row[1] in dependers: - row[0] = False - else: + custom_no=_('Keep plugin active'), + ): raise Exception("Cancelled") + self.loader.deactivate_plugin_set(plugin_set) + for row in ls: + if row[1] in dependers: + row[0] = False else: self.loader.deactivate_plugin_set(plugin_set) except: diff --git a/src/gourmand/plugin_loader.py b/src/gourmand/plugin_loader.py index 499de0d1..7aed862e 100644 --- a/src/gourmand/plugin_loader.py +++ b/src/gourmand/plugin_loader.py @@ -72,7 +72,7 @@ def __init__(self): os.path.join(current_path, 'plugins'), os.path.join(current_path, 'plugins', 'import_export'), ] - self.errors = dict() + self.errors = {} self.pluggables_by_class: Dict = dict() self.active_plugin_sets: List[str] = [] self.available_plugin_sets: Dict[str, LegacyPlugin] = self.load_legacy_plugins(self.plugin_directories) # noqa @@ -89,7 +89,7 @@ def load_legacy_plugins(directories: List[str]) -> Dict[str, object]: for ppath in plugins: debug('Found %s'%ppath,1) plugin_set = LegacyPlugin(ppath) - if plugin_set.module in ret.keys(): + if plugin_set.module in ret: print('Ignoring duplicate plugin ',plugin_set.module,'found in ',ppath) else: ret[plugin_set.module] = plugin_set @@ -141,11 +141,8 @@ def save_active_plugins(self): def check_dependencies(self, plugin_set): if plugin_set.dependencies: - missing = [] depends = plugin_set.dependencies or [] - for dep in depends: - if not dep in self.active_plugin_sets: - missing.append(dep) + missing = [dep for dep in depends if dep not in self.active_plugin_sets] if missing: raise DependencyError(plugin_set,missing) @@ -205,15 +202,14 @@ def deactivate_plugin_set (self, plugin_set: 'LegacyPlugin'): self.instantiated_plugins[plugin].remove() self.active_plugins.remove(plugin) - def get_instantiated_plugin (self, plugin): - if plugin in self.instantiated_plugins: - return self.instantiated_plugins[plugin] - else: + def get_instantiated_plugin(self, plugin): + if plugin not in self.instantiated_plugins: debug('Instantiate %s from %s'%(plugin, plugin.__module__), 1) self.instantiated_plugins[plugin] = plugin() - return self.instantiated_plugins[plugin] + + return self.instantiated_plugins[plugin] def register_pluggable (self, pluggable, klass): if klass not in self.pluggables_by_class: @@ -289,24 +285,23 @@ def __init__(self, plugin_info_path: str): def get_module(self): if self._loaded is not None: return self._loaded - else: - if self.curdir not in sys.path: - sys.path.append(self.curdir) - if self.plugin_modules_dir not in sys.path: - sys.path.append(self.plugin_modules_dir) - if self.import_export_modules_dir not in sys.path: - sys.path.append(self.import_export_modules_dir) + if self.curdir not in sys.path: + sys.path.append(self.curdir) + if self.plugin_modules_dir not in sys.path: + sys.path.append(self.plugin_modules_dir) + if self.import_export_modules_dir not in sys.path: + sys.path.append(self.import_export_modules_dir) - try: - self._loaded = __import__(self.module) - except ImportError as ie: - print('WARNING: Plugin module import failed') - print('PATH:', sys.path) - traceback.print_exc() - self.error = ie - return None - else: - return self._loaded + try: + self._loaded = __import__(self.module) + except ImportError as ie: + print('WARNING: Plugin module import failed') + print('PATH:', sys.path) + traceback.print_exc() + self.error = ie + return None + else: + return self._loaded def __getattr__ (self, attr): if attr == 'plugins': @@ -401,16 +396,14 @@ def run_post_hook (self, fname, retval, *args, **kwargs): retval = hook(retval,self,*args,**kwargs) return retval - def add_hook (self, type, name, hook): - if type==PRE: hookdic = self.pre_hooks - else: hookdic = self.post_hooks + def add_hook(self, type, name, hook): + hookdic = self.pre_hooks if type==PRE else self.post_hooks if name not in hookdic: hookdic[name] = [] hookdic[name].append(hook) - def remove_hook (self, type, name, hook): - if type==PRE: hookdic = self.pre_hooks - else: hookdic = self.post_hooks + def remove_hook(self, type, name, hook): + hookdic = self.pre_hooks if type==PRE else self.post_hooks hookdic.pop(name, None) def get_plugin_by_module (self, module): diff --git a/src/gourmand/plugins/browse_recipes/__init__.py b/src/gourmand/plugins/browse_recipes/__init__.py index 1b1d5e8e..e7e361ff 100644 --- a/src/gourmand/plugins/browse_recipes/__init__.py +++ b/src/gourmand/plugins/browse_recipes/__init__.py @@ -48,11 +48,9 @@ def reset_view(self, *args): def update_recipe(self, recipe): self.reset_view() - def get_selected_post_hook (self, recs_from_recindex, pluggable): + def get_selected_post_hook(self, recs_from_recindex, pluggable): if self.main.main_notebook.get_current_page() in self.added_tabs: - # then get recipes from iconview... - retval = self.browser.view.get_selected_recipes() - return retval + return self.browser.view.get_selected_recipes() else: return recs_from_recindex diff --git a/src/gourmand/plugins/browse_recipes/browser.py b/src/gourmand/plugins/browse_recipes/browser.py index c8592319..e611bdc8 100644 --- a/src/gourmand/plugins/browse_recipes/browser.py +++ b/src/gourmand/plugins/browse_recipes/browser.py @@ -86,7 +86,7 @@ def get_pixbuf(self, attr: str, val: str) -> GdkPixbuf.Pixbuf: self.category_images.append(result.title) elif attr == 'rating': return star_generator.get_pixbuf(val) - elif attr in ['preptime', 'cooktime']: + elif attr in {'preptime', 'cooktime'}: return get_time_slice(val) else: tbl = self.rd.recipe_table @@ -108,13 +108,12 @@ def convert_val(self, attr, val) -> str: elif attr == 'rating': if not val: return _('Unrated') - else: - val = int(val) - txt = str(val // 2) - if val % 2: - txt += ' 1/2' - txt += ' ' + _('Stars') - return txt + val = int(val) + txt = str(val // 2) + if val % 2: + txt += ' 1/2' + txt += ' ' + _('Stars') + return txt else: return str(val) diff --git a/src/gourmand/plugins/browse_recipes/icon_helpers.py b/src/gourmand/plugins/browse_recipes/icon_helpers.py index 3a01e16e..0f0679f7 100644 --- a/src/gourmand/plugins/browse_recipes/icon_helpers.py +++ b/src/gourmand/plugins/browse_recipes/icon_helpers.py @@ -12,12 +12,11 @@ COOK = 2 -def scale_pb (pb, do_grow=True): +def scale_pb(pb, do_grow=True): w = pb.get_width() h = pb.get_height () if not do_grow and (w < ICON_SIZE or h < ICON_SIZE): - if w < h: target = w - else: target = h + target = min(w, h) else: target = ICON_SIZE if w > h: @@ -48,7 +47,7 @@ def scale_pb (pb, do_grow=True): 'preptime':scale_pb(preptime_image), } -def get_recipe_image (rec): +def get_recipe_image(rec): if rec.image: pb = scale_pb(bytes_to_pixbuf(rec.image)) else: @@ -60,8 +59,8 @@ def get_recipe_image (rec): ratingPB = sg.get_pixbuf(rec.rating) h = pb.get_height() - ratingPB.get_height() - 5 w = pb.get_width() - ratingPB.get_width() - 5 - if h < 0: h = 0 - if w < 0: w = 0 + h = max(h, 0) + w = max(w, 0) if ratingPB.get_property('width') > pb.get_property('width'): SCALE = float(pb.get_property('width'))/ratingPB.get_property('width') else: diff --git a/src/gourmand/plugins/clipboard_exporter.py b/src/gourmand/plugins/clipboard_exporter.py index fadd7ab7..2e4bc894 100644 --- a/src/gourmand/plugins/clipboard_exporter.py +++ b/src/gourmand/plugins/clipboard_exporter.py @@ -44,11 +44,11 @@ def export(self): # Each item in self.recipes is a set of (a recipe, its ingredients). for recipe, ingredients in self.recipes: # The ingredients have the name, quantity, and units attached - formatted_ingredients = [] - for ingredient in ingredients: - formatted_ingredients.append( - f"{ingredient.amount} {ingredient.unit} {ingredient.item}" - ) + formatted_ingredients = [ + f"{ingredient.amount} {ingredient.unit} {ingredient.item}" + for ingredient in ingredients + ] + formatted_ingredients = '\n'.join(formatted_ingredients) # The description is optional, but we add extra formatting, to make diff --git a/src/gourmand/plugins/duplicate_finder/recipeMerger.py b/src/gourmand/plugins/duplicate_finder/recipeMerger.py index 5be4a651..a9dfc24d 100644 --- a/src/gourmand/plugins/duplicate_finder/recipeMerger.py +++ b/src/gourmand/plugins/duplicate_finder/recipeMerger.py @@ -53,11 +53,8 @@ class RecipeMergerDialog: DUP_INDEX_PAGE = 0 MERGE_PAGE = 1 - def __init__ (self, rd=None, in_recipes=None, on_close_callback=None): - if rd: - self.rd = rd - else: - self.rd = recipeManager.get_recipe_manager() + def __init__(self, rd=None, in_recipes=None, on_close_callback=None): + self.rd = rd or recipeManager.get_recipe_manager() self.in_recipes = in_recipes self.on_close_callback = on_close_callback self.to_merge = [] # Queue of recipes to be merged... @@ -287,14 +284,14 @@ def cancel_merge (self, *args): if not self.to_merge: self.populate_tree() - def populate_tree_if_possible (self): + def populate_tree_if_possible(self): self.populate_tree() if not self.dups: self.searchTypeCombo.set_active(self.RECIPE_DUP_MODE) self.populate_tree() - if not self.dups: - self.searchTypeCombo.set_active(self.ING_DUP_MODE) - self.populate_tree() + if not self.dups: + self.searchTypeCombo.set_active(self.ING_DUP_MODE) + self.populate_tree() def show_if_there_are_dups (self, label=None): self.populate_tree_if_possible() @@ -331,17 +328,16 @@ class RecipeMerger: def __init__ (self, rd): self.rd = rd - def autoMergeRecipes (self, recs): + def autoMergeRecipes(self, recs): to_fill,conflicts = recipeIdentifier.merge_recipes(self.rd, recs) if conflicts: raise ConflictError(conflicts) - else: - to_keep = recs[0] - # Update a single recipe with our information... - self.rd.modify_rec(to_keep,to_fill) - # Delete the other recipes... - for r in recs[1:]: - self.rd.delete_rec(r.id) + to_keep = recs[0] + # Update a single recipe with our information... + self.rd.modify_rec(to_keep,to_fill) + # Delete the other recipes... + for r in recs[1:]: + self.rd.delete_rec(r.id) def uiMergeRecipes (self, recs): diffs = recipeIdentifier.diff_recipes(self.rd, recs) @@ -525,8 +521,8 @@ def get_ing_text_blobs (self, r1, r2): """Return an ing-blurb for r1 and r2 suitable for display.""" idiff = recipeIdentifier.diff_ings(self.rd, r1, r2) if idiff: self.idiffs.append(idiff) - def is_line (l): - return not (l == '') + def is_line(l): + return l != '' if idiff: ret = [] for igroup in idiff: diff --git a/src/gourmand/plugins/email_plugin/emailer_plugin.py b/src/gourmand/plugins/email_plugin/emailer_plugin.py index bf7c40a7..9bde5112 100644 --- a/src/gourmand/plugins/email_plugin/emailer_plugin.py +++ b/src/gourmand/plugins/email_plugin/emailer_plugin.py @@ -37,19 +37,18 @@ def get_selected_recs (self): recs = self.rd.fetch_all(self.rd.recipe_table, deleted=False, sort_by=[('title',1)]) return recs - def email_selected (self, *args): + def email_selected(self, *args): recs = self.get_selected_recs() l = len(recs) - if l > 20: - if not de.getBoolean( - title=_('Email recipes'), - # only called for l>20, so fancy gettext methods - # shouldn't be necessary if my knowledge of - # linguistics serves me - sublabel=_('Do you really want to email all %s selected recipes?')%l, - custom_yes=_('Yes, e_mail them'), - cancel=False, - ): - return + if l > 20 and not de.getBoolean( + title=_('Email recipes'), + # only called for l>20, so fancy gettext methods + # shouldn't be necessary if my knowledge of + # linguistics serves me + sublabel=_('Do you really want to email all %s selected recipes?') % l, + custom_yes=_('Yes, e_mail them'), + cancel=False, + ): + return re = RecipeEmailer(recs) re.send_email_with_attachments() diff --git a/src/gourmand/plugins/field_editor/fieldEditor.py b/src/gourmand/plugins/field_editor/fieldEditor.py index 8ce19b3e..84615248 100644 --- a/src/gourmand/plugins/field_editor/fieldEditor.py +++ b/src/gourmand/plugins/field_editor/fieldEditor.py @@ -205,16 +205,11 @@ def get_other_changes (self): else: return {} - def get_selected_values (self, ts=None): + def get_selected_values(self, ts=None): if not ts: ts = self.treeview.get_selection() mod,paths = ts.get_selected_rows() - values = [] - for p in paths: - values.append( - mod.get_value(mod.get_iter(p),0) - ) - return values + return [mod.get_value(mod.get_iter(p),0) for p in paths] def get_criteria_and_table (self): values = self.get_selected_values() @@ -228,7 +223,7 @@ def get_criteria_and_table (self): table = self.rd.recipe_table return criteria,table - def apply_changes (self, criteria, table): + def apply_changes(self, criteria, table): changes = self.get_changes() other_changes = self.get_other_changes() if self.field != 'category' and self.other_field != 'category': @@ -242,20 +237,13 @@ def apply_changes (self, criteria, table): if not self.rd.fetch_one(self.rd.categories_table,{'id':r.id}): self.rd.do_add_cat({'id':r.id,'category':other_changes['category']}) else: - if self.field=='category': - IDs = [r.id for r in self.rd.fetch_all(self.rd.categories_table,**criteria)] - new_criteria = {'id':('==',('or',IDs))} - self.rd.update_by_criteria( - self.rd.recipe_table, - new_criteria, - other_changes - ) - else: - self.rd.update_by_criteria( - self.rd.recipe_table, - criteria, - other_changes - ) + IDs = [r.id for r in self.rd.fetch_all(self.rd.categories_table,**criteria)] + new_criteria = {'id':('==',('or',IDs))} + self.rd.update_by_criteria( + self.rd.recipe_table, + new_criteria, + other_changes + ) if self.field=='category' and not changes['category']: self.rd.delete_by_criteria(table,criteria) else: diff --git a/src/gourmand/plugins/import_export/archive_plugin/zip_readers.py b/src/gourmand/plugins/import_export/archive_plugin/zip_readers.py index b670d521..80b31a90 100644 --- a/src/gourmand/plugins/import_export/archive_plugin/zip_readers.py +++ b/src/gourmand/plugins/import_export/archive_plugin/zip_readers.py @@ -33,7 +33,7 @@ def archive_to_filelist (fi, progress=None, name='zipfile'): except IOError: return zipfile_to_filelist(fi,progress,name) -def zipfile_to_filelist (fi, progress=None, name="zipfile"): +def zipfile_to_filelist(fi, progress=None, name="zipfile"): """Take our zipfile and return a list of files. We're quite liberal in what we allow fi to be. If fi is a string, @@ -65,9 +65,8 @@ def zipfile_to_filelist (fi, progress=None, name="zipfile"): debug('Unzipping item %s'%i,1) if progress: progress(float(i)/totlen,_("Unzipping zip archive")) fn = os.path.join(fbase,n) - ifi=open(fn,'wb') - ifi.write(zf.read(n)) - ifi.close() + with open(fn,'wb') as ifi: + ifi.write(zf.read(n)) flist.append(fn) zf.close() debug('zipfile returning filelist %s'%flist,1) diff --git a/src/gourmand/plugins/import_export/epub_plugin/epub_exporter.py b/src/gourmand/plugins/import_export/epub_plugin/epub_exporter.py index 5023c205..a35a92fb 100644 --- a/src/gourmand/plugins/import_export/epub_plugin/epub_exporter.py +++ b/src/gourmand/plugins/import_export/epub_plugin/epub_exporter.py @@ -244,7 +244,11 @@ def _write_ing_impl(self, amount, unit, item, link, optional): self.preparedDocument.append('
  • ') # Escape all incoming things first. - (amount, unit, item) = tuple([xml.sax.saxutils.escape("%s"%o) if o else "" for o in [amount, unit, item]]) + (amount, unit, item) = tuple( + xml.sax.saxutils.escape("%s" % o) if o else "" + for o in [amount, unit, item] + ) + self.preparedDocument.append('
    %s
    ' % (amount if len(amount) != 0 else " ")) self.preparedDocument.append('
    %s
    ' % (unit if len(unit) != 0 else " ")) diff --git a/src/gourmand/plugins/import_export/gxml_plugin/gxml2_importer.py b/src/gourmand/plugins/import_export/gxml_plugin/gxml2_importer.py index d3b44d41..c5f661b2 100644 --- a/src/gourmand/plugins/import_export/gxml_plugin/gxml2_importer.py +++ b/src/gourmand/plugins/import_export/gxml_plugin/gxml2_importer.py @@ -34,9 +34,10 @@ def startElement(self, name, attrs): if name=='ingredient': self.start_ing(recipe_id=self.rec['id']) - if attrs.get('optional',False): - if attrs.get('optional',False) not in ['no','No','False','false','None']: - self.ing['optional']=True + if attrs.get('optional', False) and attrs.get( + 'optional', False + ) not in ['no', 'No', 'False', 'false', 'None']: + self.ing['optional']=True if name=='ingref': self.start_ing(id=self.rec['id']) self.add_ref(unquoteattr(attrs.get('refid'))) diff --git a/src/gourmand/plugins/import_export/gxml_plugin/gxml_importer.py b/src/gourmand/plugins/import_export/gxml_plugin/gxml_importer.py index 9f0589d3..63ed5fd8 100644 --- a/src/gourmand/plugins/import_export/gxml_plugin/gxml_importer.py +++ b/src/gourmand/plugins/import_export/gxml_plugin/gxml_importer.py @@ -21,7 +21,7 @@ def __init__ (self, total=None, conv=None, parent_thread=None): def startElement(self, name, attrs): self.elbuf = "" - if name=='category' or name=='cuisine' or name=='source': + if name in ['category', 'cuisine', 'source']: self.in_mixed=0 self.metaid=unquoteattr(attrs.get('id',"")) if name=='recipe': @@ -46,9 +46,10 @@ def startElement(self, name, attrs): if name=='ingredient': self.in_mixed=0 self.start_ing(id=self.rec['id']) - if attrs.get('optional',False): - if attrs.get('optional',False) not in ['no','false','False','No','None']: #support for obsolete values - self.ing['optional']=True + if attrs.get('optional', False) and attrs.get( + 'optional', False + ) not in ['no', 'false', 'False', 'No', 'None']: #support for obsolete values + self.ing['optional']=True if name=='ingref': self.in_mixed=0 self.start_ing(id=self.rec['id']) @@ -67,12 +68,12 @@ def startElement(self, name, attrs): for (n,v) in list(attrs.items()): self.mixed += " %s='%s'" % (n,v) self.mixed += ">" - if name=='instructions' or name=='modifications': + if name in ['instructions', 'modifications']: self.in_mixed = 1 self.mixed = "" - def endElement (self, name): - if name=='category' or name=='cuisine' or name=='source': + def endElement(self, name): + if name in ['category', 'cuisine', 'source']: self.meta[name][self.metaid]=xml.sax.saxutils.unescape(self.elbuf) if name=='title': self.rec['title']=xml.sax.saxutils.unescape(self.elbuf) @@ -92,7 +93,7 @@ def endElement (self, name): self.add_item(xml.sax.saxutils.unescape(self.elbuf)) if name=='amount': self.add_amt(self.elbuf) - if name=='instructions' or name=='modifications': + if name in ['instructions', 'modifications']: self.in_mixed = 0 self.mixed += self.elbuf # special unescaping of our grand little tags diff --git a/src/gourmand/plugins/import_export/html_plugin/html_exporter.py b/src/gourmand/plugins/import_export/html_plugin/html_exporter.py index cc2ec7e4..62723851 100644 --- a/src/gourmand/plugins/import_export/html_plugin/html_exporter.py +++ b/src/gourmand/plugins/import_export/html_plugin/html_exporter.py @@ -93,16 +93,15 @@ def write_head (self): self.out.write('') self.out.write('
    ') - def write_image (self, image): + def write_image(self, image): imgout = os.path.join(self.imagedir_absolute,"%s.jpg"%self.imgcount) while os.path.isfile(imgout): self.imgcount += 1 imgout = os.path.join(self.imagedir_absolute,"%s.jpg"%self.imgcount) if not os.path.isdir(self.imagedir_absolute): os.mkdir(self.imagedir_absolute) - o = open(imgout,'wb') - o.write(image) - o.close() + with open(imgout,'wb') as o: + o.write(image) # we use urllib here because os.path may fsck up slashes for urls. self.out.write('%s'%( self.make_relative_link("%s%s.jpg"%(self.imagedir, @@ -291,15 +290,14 @@ def write_footer (self): self.indexf.write('
    ') self.indexf.close() - def generate_link (self, id): + def generate_link(self, id): if id in self.added_dict: return self.added_dict[id] + rec = self.rd.get_rec(id) + if rec: + return self.generate_filename(rec,self.ext,add_id=True) else: - rec = self.rd.get_rec(id) - if rec: - return self.generate_filename(rec,self.ext,add_id=True) - else: - return None + return None def make_relative_link (self, filename): if self.outdir[-1] != os.path.sep: diff --git a/src/gourmand/plugins/import_export/mastercook_import_plugin/mastercook_importer.py b/src/gourmand/plugins/import_export/mastercook_import_plugin/mastercook_importer.py index f28aad90..79fc6ff5 100644 --- a/src/gourmand/plugins/import_export/mastercook_import_plugin/mastercook_importer.py +++ b/src/gourmand/plugins/import_export/mastercook_import_plugin/mastercook_importer.py @@ -21,41 +21,40 @@ def __init__ (self): self.attr_regexp = re.compile(self.attr_regexp) self.encodings = ['cp1252','iso8859','ascii','latin_1','cp850','utf-8'] - def cleanup (self, infile, outfile): + def cleanup(self, infile, outfile): infile = open(infile, 'rb') - outfile = open(outfile,'w', encoding='utf-8') - for l in infile.readlines(): - l = self.decode(l) - l = self.toss_regs(l) - l = self.fix_attrs(l) - outfile.write(l) - infile.close() - outfile.close() - - def toss_regs (self, instr): + with open(outfile,'w', encoding='utf-8') as outfile: + for l in infile.readlines(): + l = self.decode(l) + l = self.toss_regs(l) + l = self.fix_attrs(l) + outfile.write(l) + infile.close() + + def toss_regs(self, instr): m = self.toss_regexp.search(instr) - if m: - outstr = instr[0:m.start()] + instr[m.end():] - debug('Converted "%s" to "%s"'%(instr,outstr),1) - return outstr - else: + if not m: return instr - def fix_attrs (self, instr): + outstr = instr[0:m.start()] + instr[m.end():] + debug('Converted "%s" to "%s"'%(instr,outstr),1) + return outstr + + def fix_attrs(self, instr): match = self.attr_regexp.search(instr) outstr = "" while match: - outstr = outstr + instr[0:match.start()] + outstr += instr[0:match.start()] pre,badattr = match.groups() - outstr = outstr + pre - outstr = outstr + xml.sax.saxutils.quoteattr(badattr) + outstr += pre + outstr += xml.sax.saxutils.quoteattr(badattr) debug('Fixed broken attribute: %s -> %s'%(instr,outstr),0) instr = instr[match.end():] match = self.attr_regexp.search(instr) - outstr = outstr + instr + outstr += instr return outstr - def decode (self, l: bytes) -> str: + def decode(self, l: bytes) -> str: """Try several encodings, return the line once it's succesfully decoded """ for e in self.encodings: @@ -63,7 +62,6 @@ def decode (self, l: bytes) -> str: return l.decode(e) except UnicodeDecodeError: debug('Could not decode as %s'%e,2) - pass class MastercookXMLHandler (xml_importer.RecHandler): """We handle MasterCook XML Files""" @@ -108,13 +106,12 @@ def startElement (self, name, attrs): handler = self._get_handler(name) handler(start=True,attrs=attrs) - def endElement (self, name): + def endElement(self, name): if name not in self.elements: return - else: - self.current_elements.remove(name) - handler = self._get_handler(name) - handler(end=True) + self.current_elements.remove(name) + handler = self._get_handler(name) + handler(end=True) def endDocument (self): @@ -123,9 +120,8 @@ def endDocument (self): def _get_handler (self, name): return getattr(self,'%s_handler'%name) - def mx2_handler (self, start=False, end=False, attrs=None): - if start: - pass + def mx2_handler(self, start=False, end=False, attrs=None): + pass def characters (self, ch): if self.bufs: diff --git a/src/gourmand/plugins/import_export/mastercook_import_plugin/mastercook_plaintext_importer.py b/src/gourmand/plugins/import_export/mastercook_import_plugin/mastercook_plaintext_importer.py index 1160cf93..dffa9f91 100644 --- a/src/gourmand/plugins/import_export/mastercook_import_plugin/mastercook_plaintext_importer.py +++ b/src/gourmand/plugins/import_export/mastercook_import_plugin/mastercook_plaintext_importer.py @@ -156,16 +156,15 @@ def handle_attribute(self, line): attr = attr.strip() self.last_attr = self.ATTR_DICT[attr] self.rec[self.ATTR_DICT[attr]] = val + elif self.last_attr: + # attribute values can run over one line... + self.rec[self.last_attr] = ', '.join([self.rec[self.last_attr], + self.join_multiple_attvals( + line.strip()) + ]) else: - if self.last_attr: - # attribute values can run over one line... - self.rec[self.last_attr] = ', '.join([self.rec[self.last_attr], - self.join_multiple_attvals( - line.strip()) - ]) - else: - # otherwise, we add this to instructions, like we do with all junk - self.instr += line + # otherwise, we add this to instructions, like we do with all junk + self.instr += line def join_multiple_attvals(self, txt): """We take replace more than one space with a comma.""" diff --git a/src/gourmand/plugins/import_export/mealmaster_plugin/mealmaster_exporter.py b/src/gourmand/plugins/import_export/mealmaster_plugin/mealmaster_exporter.py index 68a6edf4..75d2d118 100644 --- a/src/gourmand/plugins/import_export/mealmaster_plugin/mealmaster_exporter.py +++ b/src/gourmand/plugins/import_export/mealmaster_plugin/mealmaster_exporter.py @@ -37,14 +37,21 @@ def __init__ (self, rd, r, out, conv=None, change_units=True, mult=1): mult=mult) @pluggable_method - def _write_attrs_ (self): + def _write_attrs_(self): self.write_attr_head() title = self._grab_attr_(self.r,'title') if not title: title = '' - categories = ', '.join([x for x in (self._grab_attr_(self.r,'cuisine'), - self._grab_attr_(self.r,'category')) if x]) + categories = ', '.join( + x + for x in ( + self._grab_attr_(self.r, 'cuisine'), + self._grab_attr_(self.r, 'category'), + ) + if x + ) + yields = self._grab_attr_(self.r,'yields') if not yields: # MealMaster format mandates numeric yield information @@ -103,7 +110,7 @@ def write_grouphead (self, name): def write_groupfoot (self): self.ings = self.master_ings # back to master level - def write_ing (self, amount="1", unit=None, item=None, key=None, optional=False): + def write_ing(self, amount="1", unit=None, item=None, key=None, optional=False): if isinstance(amount, (float, int)): amount = convert.float_to_frac(amount) if not amount: amount = "" @@ -114,11 +121,10 @@ def write_ing (self, amount="1", unit=None, item=None, key=None, optional=False) # Try to fix the unit if unit in self.conv.unit_dict: new_u = self.conv.unit_dict[unit] - if len(new_u) <= 2 and not '.' in new_u: + if len(new_u) <= 2 and '.' not in new_u: unit = new_u; unit_bad = False - else: - if new_u in self.uc: - unit = self.uc[new_u]; unit_bad = False + elif new_u in self.uc: + unit = self.uc[new_u]; unit_bad = False if unit_bad: # If we couldn't fix the unit... we add it to # the item if unit: item="%s %s"%(unit,item) diff --git a/src/gourmand/plugins/import_export/mealmaster_plugin/mealmaster_importer.py b/src/gourmand/plugins/import_export/mealmaster_plugin/mealmaster_importer.py index c598fa54..2ae88523 100644 --- a/src/gourmand/plugins/import_export/mealmaster_plugin/mealmaster_importer.py +++ b/src/gourmand/plugins/import_export/mealmaster_plugin/mealmaster_importer.py @@ -7,7 +7,7 @@ class mmf_constants: - def __init__ (self): + def __init__(self): self.committed = False self.recattrs={'Title':'title', 'Name':'title', @@ -21,25 +21,25 @@ def __init__ (self): 'Preparation Time':'preptime', } - self.unit_conv = {'ts':'tsp', - 'tb':'Tbs', - 'sm':'small', - 'md':'medium', - 'ea':'', - 'lg':'large', - 'c':'c', - 'pn':'pinch', - 'ds':'dash', - 'T' : 'tbs', - 't' : 'tsp', - 'pk' : 'package', - 'x' : '', - 'ea' : '', - 't' : 'tsp', - 'pt' : 'pt', - 'qt' : 'qt', - 'oz' : 'oz' - } + self.unit_conv = { + 'ts': 'tsp', + 'tb': 'Tbs', + 'sm': 'small', + 'md': 'medium', + 'lg': 'large', + 'c': 'c', + 'pn': 'pinch', + 'ds': 'dash', + 'T': 'tbs', + 'pk': 'package', + 'x': '', + 'ea': '', + 't': 'tsp', + 'pt': 'pt', + 'qt': 'qt', + 'oz': 'oz', + } + self.unit_convr = {} for k,v in list(self.unit_conv.items()): self.unit_convr[v]=k @@ -105,7 +105,7 @@ def __init__ (self,filename='Data/mealmaster.mmf', #threaded=threaded,conv=conv) testtimer.end() - def compile_regexps (self): + def compile_regexps(self): testtimer = TimeAction('mealmaster_importer.compile_regexps',10) debug("start compile_regexps",5) plaintext_importer.TextImporter.compile_regexps(self) @@ -121,11 +121,16 @@ def compile_regexps (self): # followed by a two digit unit (or spaces) c = convert.get_converter() self.ing_num_matcher = re.compile( - r"^\s*%s+\s+([a-z ]{1,2}|%s)\s+.*\w+.*"%( - convert.NUMBER_REGEXP, - '('+'|'.join([x for x in list(c.unit_dict.keys()) if x])+')' - ), - re.IGNORECASE) + ( + r"^\s*%s+\s+([a-z ]{1,2}|%s)\s+.*\w+.*" + % ( + convert.NUMBER_REGEXP, + '(' + '|'.join(x for x in list(c.unit_dict.keys()) if x) + ')', + ) + ), + re.IGNORECASE, + ) + self.amt_field_matcher = re.compile(r"^(\s*%s\s*)$"%convert.NUMBER_REGEXP) # we build a regexp to match anything that looks like # this: ^\s*ATTRIBUTE: Some entry of some kind...$ @@ -137,7 +142,7 @@ def compile_regexps (self): self.attr_matcher = re.compile(attrmatch) testtimer.end() - def handle_line (self,l): + def handle_line(self,l): """Handle an individual line of a mealmaster file. @@ -206,8 +211,7 @@ def handle_line (self,l): self.ingrs.append([l,self.group]) else: ## otherwise, we assume a line of instructions - if self.last_line_was == 'blank': add_blank=True - else: add_blank = False + add_blank = self.last_line_was == 'blank' if self.in_variation: debug('Adding to instructions: %s'%l,4) self.last_line_was = 'mod' @@ -300,7 +304,7 @@ def handle_group (self, groupm): # we were in instructions. If we see a group heading, # we know that's not the case! - def find_ing_fields (self): + def find_ing_fields(self): """Find fields in an ingredient line.""" testtimer = TimeAction('mealmaster_importer.find_ing_fields',10) all_ings = [i[0] for i in self.ingrs] @@ -315,10 +319,7 @@ def find_ing_fields (self): if ufield: fields = fields[1:] fields_is_numfield = fields_is_numfield[1:] - if fields: - ifield = [fields[0][0],None] - else: - ifield = 0,None + ifield = [fields[0][0],None] if fields else (0, None) retval = [[afield,ufield,ifield]] sec_col_fields = [x for x in fields if x[0]>self.two_col_minimum] if sec_col_fields: @@ -510,7 +511,7 @@ def field_width (tuple): return None -def find_fields (strings, char=" "): +def find_fields(strings, char=" "): testtimer = TimeAction('mealmaster_importer.find_fields',10) cols = find_columns(strings, char) if not cols: return [] @@ -521,11 +522,9 @@ def find_fields (strings, char=" "): end = lens[-1] last_col = end for col in cols: - if col == last_col - 1: - end = col - else: + if col != last_col - 1: fields.append([col+1,end]) - end = col + end = col last_col = col if end != 0: fields.append([0,end]) fields.reverse() diff --git a/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_exporter.py b/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_exporter.py index 7987bc10..bae94151 100644 --- a/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_exporter.py +++ b/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_exporter.py @@ -52,14 +52,14 @@ def write_attr (self, attr, text): self.rec_el.appendChild(self.create_text_element(attr.replace(' ',''),text)) - def write_text (self, attr, text): + def write_text(self, attr, text): #attr mapping with li if (attr == 'instructions'): attr = 'recipetext' if (attr == 'modifications'): attr = 'comments' - if (attr == 'recipetext' or attr == 'comments'): + if attr in ['recipetext', 'comments']: linelist = text.split('\n') self.attrlist_el = self.xmlDoc.createElement(attr.replace(' ','')) self.rec_el.appendChild(self.attrlist_el) @@ -96,11 +96,11 @@ def write_inghead (self): def write_ingref (self, amount=1, unit=None, item=None, refid=None, optional=False): pass - def write_ing (self, amount=1, unit=None, item=None, key=None, optional=False): + def write_ing(self, amount=1, unit=None, item=None, key=None, optional=False): ing_txt='' if isinstance(amount, (float, int)): amount = convert.float_to_frac(amount) - ing_txt = ing_txt + amount + ing_txt += amount if unit: ing_txt = ing_txt + ' ' + unit if item: diff --git a/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_importer.py b/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_importer.py index eb5d9cf3..d6a8ebf9 100644 --- a/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_importer.py +++ b/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_importer.py @@ -84,17 +84,13 @@ def endElement(self, name): print(str(e)) # times fixing - if name == 'cooktime' or name == 'preptime': + if name in ['cooktime', 'preptime']: self.elbuf = self.elbuf.replace('mn', 'min') if re.match('([0-9]*)min', self.elbuf): self.elbuf = self.elbuf.replace('min', ' min') # other tags - if name == self.ING_TAG: - self.current_section = '' - elif name == self.INSTR_TAG: - self.current_section = '' - elif name == self.COMMENT_TAG: + if name in [self.ING_TAG, self.INSTR_TAG, self.COMMENT_TAG]: self.current_section = '' elif name in self.RECTAGS: obj = self.rec diff --git a/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_importer_plugin.py b/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_importer_plugin.py index c5761ea1..8c5c091c 100644 --- a/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_importer_plugin.py +++ b/src/gourmand/plugins/import_export/mycookbook_plugin/mycookbook_importer_plugin.py @@ -20,7 +20,7 @@ class MCBPlugin (ImporterPlugin): def test_file (self, filename): return True - def get_importer (self, filename): + def get_importer(self, filename): xmlfilename='' #Unzip in a temporary directory @@ -37,9 +37,8 @@ def get_importer (self, filename): #Create the images dir if not exists yet if not os.path.exists(fulldirpath): os.mkdir(fulldirpath, 0o775) - outfile = open(os.path.join(tempdir, name), 'wb') - outfile.write(zf.read(name)) - outfile.close() + with open(os.path.join(tempdir, name), 'wb') as outfile: + outfile.write(zf.read(name)) #Get the path to the xml file to import it if filename.endswith(".xml"): xmlfilename = os.path.join(tempdir, filename) diff --git a/src/gourmand/plugins/import_export/pdf_plugin/pdf_exporter.py b/src/gourmand/plugins/import_export/pdf_plugin/pdf_exporter.py index 898ef6aa..77797a6b 100644 --- a/src/gourmand/plugins/import_export/pdf_plugin/pdf_exporter.py +++ b/src/gourmand/plugins/import_export/pdf_plugin/pdf_exporter.py @@ -65,10 +65,7 @@ def getSpaceAfter (self): def wrap(self, availW, availH): if self.size > availW or self.size > availH: - if availW > availH: - self.size = availH - else: - self.size = availW + self.size = min(availW, availH) return (self.size,self.size) def draw (self): @@ -87,7 +84,7 @@ def draw_circle (self, x, y, r): p.close() canvas.drawPath(p,fill=1) - def draw_half_star (self, inner_length=1*inch, outer_length=2*inch, points=5, origin=None): + def draw_half_star(self, inner_length=1*inch, outer_length=2*inch, points=5, origin=None): canvas = self.canv canvas.setLineWidth(0) if not origin: canvas.translate(self.size*0.5,self.size*0.5) @@ -100,8 +97,7 @@ def draw_half_star (self, inner_length=1*inch, outer_length=2*inch, points=5, or #print 'Drawing star with radius',outer_length,'(moving origin ',origin,')' for theta in range(0, 360, 360 // (points * 2)): if 0 < theta < 180: continue - if inner: r = inner_length - else: r = outer_length + r = inner_length if inner else outer_length x = (math.sin(math.radians(theta)) * r) y = (math.cos(math.radians(theta)) * r) #print 'POINT:',x,y @@ -114,7 +110,7 @@ def draw_half_star (self, inner_length=1*inch, outer_length=2*inch, points=5, or p.close() canvas.drawPath(p,fill=1) - def draw_star (self, inner_length=1*inch, outer_length=2*inch, points=5, origin=None): + def draw_star(self, inner_length=1*inch, outer_length=2*inch, points=5, origin=None): canvas = self.canv canvas.setLineWidth(0) if not origin: canvas.translate(self.size*0.5,self.size*0.5) @@ -126,8 +122,7 @@ def draw_star (self, inner_length=1*inch, outer_length=2*inch, points=5, origin= is_origin = True #print 'Drawing star with radius',outer_length,'(moving origin ',origin,')' for theta in range(0, 360, 360 // (points * 2)): - if inner: r = inner_length - else: r = outer_length + r = inner_length if inner else outer_length x = (math.sin(math.radians(theta)) * r) y = (math.cos(math.radians(theta)) * r) #print 'POINT:',x,y @@ -256,11 +251,7 @@ def setup_frames(self, self.pagesize = getattr(pagesizes, pagemode)(pagesize) self.margins = (left_margin, right_margin, top_margin, bottom_margin) - if mode is not None: - mode, count = mode - else: - mode, count = 'column', 1 - + mode, count = mode if mode is not None else ('column', 1) if mode == 'column': frames = self.setup_column_frames(count) elif mode == 'index_cards': @@ -408,7 +399,7 @@ def close (self): class PdfExporter (exporter.exporter_mult, PdfWriter): - def __init__ (self, rd, r, out, + def __init__(self, rd, r, out, doc=None, styleSheet=None, txt=None, @@ -420,10 +411,7 @@ def __init__ (self, rd, r, out, all_recipes = all_recipes if all_recipes is not None else [] self.all_recipes = all_recipes PdfWriter.__init__(self) - if isinstance(out, str): - self.out = open(out, 'wb') - else: - self.out = out + self.out = open(out, 'wb') if isinstance(out, str) else out if not doc: self.setup_document(self.out,**pdf_args) self.multidoc = False @@ -481,11 +469,9 @@ def write_image(self, data: bytes): buf = BytesIO(data) i = platypus.Image(buf) self.scale_image(i) - factor = 1 MAX_WIDTH = self.doc.frame_width * 0.35 MAX_HEIGHT = self.doc.frame_height * 0.5 - if i.drawWidth > MAX_WIDTH: - factor = MAX_WIDTH/i.drawWidth + factor = MAX_WIDTH/i.drawWidth if i.drawWidth > MAX_WIDTH else 1 if i.drawHeight > MAX_HEIGHT: f = MAX_HEIGHT/i.drawHeight if f < factor: factor = f @@ -652,23 +638,22 @@ def write_ing (self, amount=1, unit=None, item=None, key=None, optional=False): attributes=' firstLineIndent="-%(hanging)s" leftIndent="%(hanging)s"'%locals() ) - def write_ingref (self, amount, unit, item, refid, optional): - if refid in [r.id for r in self.all_recipes]: - txt = "" - for blob in [amount,unit,item,(optional and _('optional') or '')]: - if blob == item: - blob = ''%refid + blob + '' - elif not blob: - continue - if txt: txt += " %s"%blob - else: txt = blob - hanging = inch*0.25 - self.write_paragraph( - txt, - attributes=' firstLineIndent="-%(hanging)s" leftIndent="%(hanging)s"'%locals() - ) - else: + def write_ingref(self, amount, unit, item, refid, optional): + if refid not in [r.id for r in self.all_recipes]: return self.write_ing(amount,unit,item,optional=optional) + txt = "" + for blob in [amount,unit,item,(optional and _('optional') or '')]: + if blob == item: + blob = ''%refid + blob + '' + elif not blob: + continue + if txt: txt += " %s"%blob + else: txt = blob + hanging = inch*0.25 + self.write_paragraph( + txt, + attributes=' firstLineIndent="-%(hanging)s" leftIndent="%(hanging)s"'%locals() + ) class PdfExporterMultiDoc (exporter.ExporterMultirec, PdfWriter): def __init__ (self, rd, recipes, out, conv=None, pdf_args=DEFAULT_PDF_ARGS, diff --git a/src/gourmand/plugins/import_export/pdf_plugin/print_plugin.py b/src/gourmand/plugins/import_export/pdf_plugin/print_plugin.py index c467b23f..9fbeafc7 100644 --- a/src/gourmand/plugins/import_export/pdf_plugin/print_plugin.py +++ b/src/gourmand/plugins/import_export/pdf_plugin/print_plugin.py @@ -21,13 +21,13 @@ rl2gtk_papersizes = { - tuple([int(round(s)) for s in pagesizes.letter]) : Gtk.PAPER_NAME_LETTER, - tuple([int(round(s)) for s in pagesizes.legal]) : Gtk.PAPER_NAME_LEGAL, - tuple([int(round(s)) for s in pagesizes.B5]):Gtk.PAPER_NAME_B5, - tuple([int(round(s)) for s in pagesizes.A5]):Gtk.PAPER_NAME_A5, - tuple([int(round(s)) for s in pagesizes.A4]):Gtk.PAPER_NAME_A4, - tuple([int(round(s)) for s in pagesizes.A3]):Gtk.PAPER_NAME_A3, - } + tuple(int(round(s)) for s in pagesizes.letter): Gtk.PAPER_NAME_LETTER, + tuple(int(round(s)) for s in pagesizes.legal): Gtk.PAPER_NAME_LEGAL, + tuple(int(round(s)) for s in pagesizes.B5): Gtk.PAPER_NAME_B5, + tuple(int(round(s)) for s in pagesizes.A5): Gtk.PAPER_NAME_A5, + tuple(int(round(s)) for s in pagesizes.A4): Gtk.PAPER_NAME_A4, + tuple(int(round(s)) for s in pagesizes.A3): Gtk.PAPER_NAME_A3, +} class OSXPDFPrinter: def setup_printer (self, parent=None): diff --git a/src/gourmand/plugins/import_export/plaintext_plugin/plaintext_importer_plugin.py b/src/gourmand/plugins/import_export/plaintext_plugin/plaintext_importer_plugin.py index c0bd1883..43a1494a 100644 --- a/src/gourmand/plugins/import_export/plaintext_plugin/plaintext_importer_plugin.py +++ b/src/gourmand/plugins/import_export/plaintext_plugin/plaintext_importer_plugin.py @@ -42,11 +42,11 @@ class PlainTextImporterPlugin (ImporterPlugin): antipatterns = ['*.html','*.htm','*.xml','*.doc','*.rtf'] - def test_file (self, filename): + def test_file(self, filename): '''Given a filename, test whether the file is of this type.''' if filename.endswith('.txt'): return 1 - elif not True in [fnmatch.fnmatch(filename,p) for p in self.antipatterns]: + elif True not in [fnmatch.fnmatch(filename, p) for p in self.antipatterns]: return -1 # we are a fallback option def get_importer (self, filename): diff --git a/src/gourmand/plugins/import_export/web_import_plugin/webpage_importer.py b/src/gourmand/plugins/import_export/web_import_plugin/webpage_importer.py index 3ca957fd..a84f11f3 100644 --- a/src/gourmand/plugins/import_export/web_import_plugin/webpage_importer.py +++ b/src/gourmand/plugins/import_export/web_import_plugin/webpage_importer.py @@ -57,7 +57,7 @@ def identify_match (self, tag): if tag==t: return label - def get_images (self): + def get_images(self): self.images = [] for i in self.soup('img'): try: @@ -66,11 +66,7 @@ def get_images (self): continue img_url = urllib.parse.urljoin(self.url, src) if self.imageexcluders: - exclude = False - for exc in self.imageexcluders: - if exc.search(img_url): - exclude = True - break + exclude = any(exc.search(img_url) for exc in self.imageexcluders) if exclude: continue self.images.append(img_url) @@ -84,14 +80,13 @@ def parse (self, tag=None): self.add_buffer_to_parsed() return self.parsed - def crawl (self, tag, parent_label=None): + def crawl(self, tag, parent_label=None): formatting = self.format_tag_whitespace(tag) if formatting == -1: return # special case allows formatting method to # auto-skip scripts and what-not - else: - start_ws,end_ws = formatting - self.buffer += start_ws + start_ws,end_ws = formatting + self.buffer += start_ws label = self.identify_match(tag) if not label and parent_label: # inherit... @@ -149,7 +144,7 @@ def add_buffer_to_parsed (self): self.parsed.append((pre_add,None)) self.parsed.append((to_add,self.last_label)) - def format_tag_whitespace (self, tag): + def format_tag_whitespace(self, tag): '''Return any whitespace required by tag, or -1 if tag should not be considered for text ''' @@ -163,9 +158,8 @@ def format_tag_whitespace (self, tag): if tag.name in self.IS_BREAK: return '\n','' elif tag.name in self.NESTED: - parent_types = self.NESTED[tag.name]; parents = 0 - for typ in parent_types: - parents += len(tag.fetchParents(typ)) + parent_types = self.NESTED[tag.name] + parents = sum(len(tag.fetchParents(typ)) for typ in parent_types) return '\n'+self.TAB*parents,'' elif tag.name in self.TAB_BEFORE: return self.TAB,'' @@ -174,13 +168,13 @@ def format_tag_whitespace (self, tag): else: return '','' - def postparse (self, parsed): + def postparse(self, parsed): '''Do purely text-based parsing of content. ''' new_parse = [] for p,attr in parsed: p = re.sub(r'(\n\s*\n)+','\n\n',p) # Take out extra newlines - if attr == None or attr == 'recipe': + if attr is None or attr == 'recipe': new_parse.extend( self.text_parser.parse(p) ) diff --git a/src/gourmand/plugins/import_export/website_import_plugins/cooksillustrated_plugin.py b/src/gourmand/plugins/import_export/website_import_plugins/cooksillustrated_plugin.py index f4f424ff..d9123bf7 100644 --- a/src/gourmand/plugins/import_export/website_import_plugins/cooksillustrated_plugin.py +++ b/src/gourmand/plugins/import_export/website_import_plugins/cooksillustrated_plugin.py @@ -129,7 +129,7 @@ def maybe_add (self, el, tag, ignoreSlug=False): self.maybe_add(el.findAll('h4',{'class':'section-slug'}),'ignore') - def preparse (self): + def preparse(self): self.preparsed_elements = [] self.maybe_add(self.soup.find('section',{'class':'why'}),'modifications') self.maybe_add(self.soup.find('h2',{'class':'document-header__title'}),'title') @@ -164,10 +164,7 @@ def preparse (self): self.maybe_add(self.soup.find('span',{'class':'recipe__yield'}),'yields') # Do we use automatic settings or not... - if self.preparsed_elements: - self.ignore_unparsed = True - else: - self.ignore_unparsed = False + self.ignore_unparsed = bool(self.preparsed_elements) return CooksIllustratedParser diff --git a/src/gourmand/plugins/import_export/website_import_plugins/ica_se_plugin.py b/src/gourmand/plugins/import_export/website_import_plugins/ica_se_plugin.py index a853d2cc..16115e98 100644 --- a/src/gourmand/plugins/import_export/website_import_plugins/ica_se_plugin.py +++ b/src/gourmand/plugins/import_export/website_import_plugins/ica_se_plugin.py @@ -29,11 +29,10 @@ def preparse(self): howto = self.soup.find("howto-steps") modifications = howto.find("h2") - if modifications: - if modifications.text == "Tips": - text = modifications.next_sibling - if text: - self.preparsed_elements.append((text.strip(), "modifications")) + if modifications and modifications.text == "Tips": + text = modifications.next_sibling + if text: + self.preparsed_elements.append((text.strip(), "modifications")) if not self.recipe: return diff --git a/src/gourmand/plugins/import_export/website_import_plugins/schema_org_parser.py b/src/gourmand/plugins/import_export/website_import_plugins/schema_org_parser.py index 4d27266f..c40a9ead 100644 --- a/src/gourmand/plugins/import_export/website_import_plugins/schema_org_parser.py +++ b/src/gourmand/plugins/import_export/website_import_plugins/schema_org_parser.py @@ -52,7 +52,7 @@ def preparse(self): self.preparsed_elements.append((entry, output_key)) elif isinstance(value, timedelta): minutes = int(value.total_seconds() // 60) - if not minutes % 60 == 0: + if minutes % 60 != 0: # Not full hours. self.preparsed_elements.append(("{} min".format(minutes), output_key)) else: diff --git a/src/gourmand/plugins/key_editor/keyEditor.py b/src/gourmand/plugins/key_editor/keyEditor.py index 41f169bd..c3f06721 100644 --- a/src/gourmand/plugins/key_editor/keyEditor.py +++ b/src/gourmand/plugins/key_editor/keyEditor.py @@ -338,7 +338,7 @@ def get_dic_describing_iter (self, itr): print('WTF! WE SHOULD NEVER LAND HERE!',field,value) raise Exception("WTF ERROR") - def applyEntriesCB (self, *args): + def applyEntriesCB(self, *args): newdic = {} for k, e in list(self.entries.items()): txt = e.get_text() @@ -373,7 +373,8 @@ def applyEntriesCB (self, *args): # in which case the changes would already be inherited by # the current row (i.e. if the tree has been expanded and # all rows have been selected). - parent = mod.iter_parent(itr); already_updated = False + parent = mod.iter_parent(itr) + already_updated = False while parent: if parent in updated_iters: already_updated = True @@ -383,20 +384,19 @@ def applyEntriesCB (self, *args): # Now that we're sure we really need to update... curdic,field = self.get_dic_describing_iter(itr) curkey = self.treeModel.get_value(itr,self.VALUE_COL) - if not already_updated: - self.rd.update_by_criteria( - self.rd.ingredients_table, - curdic, - newdic, + self.rd.update_by_criteria( + self.rd.ingredients_table, + curdic, + newdic, + ) + if 'ingkey' in curdic and 'ingkey' in newdic: + self.rd.delete_by_criteria( + self.rd.keylookup_table, + {'ingkey':curdic['ingkey']} ) - if 'ingkey' in curdic and 'ingkey' in newdic: - self.rd.delete_by_criteria( - self.rd.keylookup_table, - {'ingkey':curdic['ingkey']} - ) self.resetTree() - def editNutritionalInfoCB (self, *args): + def editNutritionalInfoCB(self, *args): nid = nutritionDruid.NutritionInfoDruid(self.rg.nd, self.rg.prefs) mod,rows = self.treeview.get_selection().get_selected_rows() keys_to_update = {} @@ -409,30 +409,26 @@ def editNutritionalInfoCB (self, *args): itr = parent parent = mod.iter_parent(itr) curkey = mod.get_value(itr,self.VALUE_COL) - #if mod.get_value(itr,self.NUT_COL): - # print "We can't yet edit nutritional information..." - #else: - if True: - keys_to_update[curkey]=[] - child = mod.iter_children(itr) - while child: - grandchild = mod.iter_children(child) - while grandchild: - # Grand children are units... - unit = mod.get_value(grandchild,self.VALUE_COL) - greatgrandchild = mod.iter_children(grandchild) - while greatgrandchild: - amount = mod.get_value( - greatgrandchild, - self.VALUE_COL - ) - keys_to_update[curkey].append((frac_to_float(amount), unit)) - greatgrandchild = mod.iter_next(greatgrandchild) - grandchild = mod.iter_next(grandchild) - child = mod.iter_next(child) - nid.add_ingredients(list(keys_to_update.items())) - nid.connect('finish',self.update_nutinfo) - nid.show() + keys_to_update[curkey]=[] + child = mod.iter_children(itr) + while child: + grandchild = mod.iter_children(child) + while grandchild: + # Grand children are units... + unit = mod.get_value(grandchild,self.VALUE_COL) + greatgrandchild = mod.iter_children(grandchild) + while greatgrandchild: + amount = mod.get_value( + greatgrandchild, + self.VALUE_COL + ) + keys_to_update[curkey].append((frac_to_float(amount), unit)) + greatgrandchild = mod.iter_next(greatgrandchild) + grandchild = mod.iter_next(grandchild) + child = mod.iter_next(child) + nid.add_ingredients(list(keys_to_update.items())) + nid.connect('finish',self.update_nutinfo) + nid.show() def update_nutinfo (self, *args): self.treeModel.reset_views() @@ -526,17 +522,14 @@ def __init__ (self, rd, per_page=15): ], per_page=per_page) - def reset_views (self): + def reset_views(self): if self.__last_limit_text: txt = self.__last_limit_text if hasattr(self,'use_regexp') and self.use_regexp: s = {'search':txt,'operator':'REGEXP'} else: s = {'search':'%'+txt.replace('%','%%')+'%','operator':'LIKE'} - if self.search_by == _('item'): - s['column']='item' - else: - s['column']='ingkey' + s['column'] = 'item' if self.search_by == _('item') else 'ingkey' self.view = self.rd.get_ingkeys_with_count(s) else: self.view = self.rd.get_ingkeys_with_count() diff --git a/src/gourmand/plugins/key_editor/recipeEditorPlugin.py b/src/gourmand/plugins/key_editor/recipeEditorPlugin.py index bd8c0f26..a9e04fdf 100644 --- a/src/gourmand/plugins/key_editor/recipeEditorPlugin.py +++ b/src/gourmand/plugins/key_editor/recipeEditorPlugin.py @@ -214,13 +214,13 @@ def update_from_ingredient_editor_cb (self, ie, edited): if edited: # Update based on current ingredients... ITM = ie.ingtree_ui.ingController.ITEM_COL - def process_row (row): + def process_row(row): obj = row[0] item = row[ITM] already_there = False if isinstance(obj,RecRef): return - if item == None: # if this is a group.. + if item is None: # if this is a group.. for child in row.iterchildren(): process_row(child) return diff --git a/src/gourmand/plugins/nutritional_information/databaseGrabber.py b/src/gourmand/plugins/nutritional_information/databaseGrabber.py index 531917d6..aaa17a27 100644 --- a/src/gourmand/plugins/nutritional_information/databaseGrabber.py +++ b/src/gourmand/plugins/nutritional_information/databaseGrabber.py @@ -45,16 +45,15 @@ def __init__ (self, self.show_progress=show_progress self.db = db - def get_zip_file (self): - if hasattr(self,'zipfile'): - return self.zipfile - else: + def get_zip_file(self): + if not hasattr(self, 'zipfile'): ofi = urllib.request.urlopen(self.USDA_ZIP_URL) tofi = tempfile.TemporaryFile() tofi.write(ofi.read()) tofi.seek(0) self.zipfile = zipfile.ZipFile(tofi,'r') - return self.zipfile + + return self.zipfile def get_file_from_url (self, filename): zf = self.get_zip_file() diff --git a/src/gourmand/plugins/nutritional_information/export_plugin.py b/src/gourmand/plugins/nutritional_information/export_plugin.py index 1edf0006..ecb69db9 100644 --- a/src/gourmand/plugins/nutritional_information/export_plugin.py +++ b/src/gourmand/plugins/nutritional_information/export_plugin.py @@ -18,7 +18,7 @@ def __init__ (self): self.get_nutritional_info_as_text_blob, self.TEXT) - def get_nutritional_info_as_text_blob (self, rec): + def get_nutritional_info_as_text_blob(self, rec): if not Prefs.instance().get('include_nutritional_info_in_export',True): return None txt = '' footnotes = '' @@ -37,31 +37,31 @@ def get_nutritional_info_as_text_blob (self, rec): _('Nutritional information reflects amounts for entire recipe')) if vapor: - txt = txt + '*' - footnotes = '\n*' + _('Nutritional information is missing for %s ingredients: %s')%( - len(vapor), - ', '.join([escape(nv.__ingobject__.item) for nv in vapor]) + txt += '*' + footnotes = '\n*' + ( + _('Nutritional information is missing for %s ingredients: %s') + % ( + len(vapor), + ', '.join(escape(nv.__ingobject__.item) for nv in vapor), ) + ) + for itm in MAIN_NUT_LAYOUT: if itm == SEP: # We don't have any nice way of outputting separator # lines in our export continue + label,typ,name,properties,show_percent,unit = itm + itm_text = ''+label+'' if typ==MAJOR else label + if unit: + itm_text += ' (%s)'%unit + if isinstance(properties, list): + amts = [getattr(nutinfo,att) for att in properties] + amt = sum(amts) else: - label,typ,name,properties,show_percent,unit = itm - if typ==MAJOR: - itm_text = ''+label+'' - else: - itm_text = label - if unit: - itm_text += ' (%s)'%unit - if isinstance(properties, list): - amts = [getattr(nutinfo,att) for att in properties] - amt = sum(amts) - else: - amt = getattr(nutinfo,properties) - if rec.yields: - amt = amt/rec.yields - itm_text += ' %d'%round(amt) + amt = getattr(nutinfo,properties) + if rec.yields: + amt = amt/rec.yields + itm_text += ' %d'%round(amt) txt += '\n'+itm_text return '\n'.join([txt,footnotes]) diff --git a/src/gourmand/plugins/nutritional_information/nutrition.py b/src/gourmand/plugins/nutritional_information/nutrition.py index e1e131b3..f3d81841 100644 --- a/src/gourmand/plugins/nutritional_information/nutrition.py +++ b/src/gourmand/plugins/nutritional_information/nutrition.py @@ -81,7 +81,7 @@ def get_matches(self, key, max=50): sorting algorithm succeeded in picking out the good matches!). """ words=re.split(r"\W",key) - words = [w for w in words if w and not w in ['in','or','and','with']] + words = [w for w in words if w and w not in ['in','or','and','with']] #words += ['raw'] result = self.db.search_nutrition(words) while not result and len(words)>1: @@ -92,11 +92,10 @@ def get_matches(self, key, max=50): else: return [] - def _get_key (self, key): + def _get_key(self, key): """Handed an ingredient key, get our nutritional Database equivalent if one exists.""" - row=self.db.fetch_one(self.db.nutritionaliases_table,**{'ingkey':str(key)}) - return row + return self.db.fetch_one(self.db.nutritionaliases_table,**{'ingkey':str(key)}) def get_nutinfo_for_ing (self, ing, rd, multiplier=None): """A convenience function that grabs the requisite items from @@ -140,16 +139,15 @@ def get_nutinfo_for_item (self, key, amt, unit, ingObject=None): unit=unit, ingObject=ingObject) - def get_nutinfo_from_desc (self, desc): + def get_nutinfo_from_desc(self, desc): nvrow = self.db.fetch_one(self.db.nutrition_table,**{'desc':desc}) if nvrow: return NutritionInfo(nvrow) - else: - matches = self.get_matches(desc) - if len(matches) == 1: - ndbno = matches[0][1] - nvrow = self.db.fetch_one(self.db.nutrition_table,ndbno=ndbno) - return NutritionInfo(nvrow) + matches = self.get_matches(desc) + if len(matches) == 1: + ndbno = matches[0][1] + nvrow = self.db.fetch_one(self.db.nutrition_table,ndbno=ndbno) + return NutritionInfo(nvrow) return None def get_nutinfo (self, key): @@ -245,7 +243,7 @@ def get_conversion_for_amt (self, amt, unit, key, row=None, fudge=True): if cnv: return (0.01*amt)/cnv - def get_conversions (self, key=None, row=None): + def get_conversions(self, key=None, row=None): """Handed an ingredient key or a row of the nutrition database, we return two dictionaries, one with Unit Conversions and the other with densities. Our return dictionaries look like this: @@ -270,31 +268,28 @@ def get_conversions (self, key=None, row=None): continue # if we can't get a density from this amount, we're going to treat it as a unit! if e: u = u + ", " + e - if a: gw = float(gw)/a - else: - gw = float(gw) + gw = float(gw)/a if a else float(gw) if u: units[u]=gw return densities,units - def get_densities (self,key=None,row=None): + def get_densities(self,key=None,row=None): """Handed key or nutrow, return dictionary with densities.""" if not row: row = self._get_key(key) if not row: return {} if key in self.conv.density_table: return {'':self.conv.density_table[key]} - else: - densities = {} - for gd,gw in list(self.get_gramweights(row).items()): - a,u,e = gd - if not a: - continue - convfactor=self.conv.converter(u,'ml') - if convfactor: # if we are a volume - # divide mass by volume converted to milileters - # (gramwts are in grams) - density = float(gw) / (a * convfactor) - densities[e]=density - return densities + densities = {} + for gd,gw in list(self.get_gramweights(row).items()): + a,u,e = gd + if not a: + continue + convfactor=self.conv.converter(u,'ml') + if convfactor: # if we are a volume + # divide mass by volume converted to milileters + # (gramwts are in grams) + density = float(gw) / (a * convfactor) + densities[e]=density + return densities def get_gramweights (self,row): """Return a dictionary with gram weights. @@ -384,21 +379,21 @@ def __init__ (self,rowref, mult=1, fudged=False, ingObject=None): self.__fudged__ = fudged self.__ingobject__ = ingObject - def __getattr__ (self, attr): - if attr[0]!='_': - ret = getattr(self.__rowref__, attr) - try: - if attr in SUMMABLE_FIELDS: - return (ret or 0) * self.__mult__ - else: - return ret - except: - raise - else: + def __getattr__(self, attr): + if attr[0] == '_': # somehow this magically gets us standard # attribute handling... raise AttributeError(attr) + ret = getattr(self.__rowref__, attr) + try: + if attr in SUMMABLE_FIELDS: + return (ret or 0) * self.__mult__ + else: + return ret + except: + raise + def __add__ (self, obj): if isinstance(obj,NutritionInfo): return NutritionInfoList([self,obj]) @@ -437,22 +432,21 @@ def __init__ (self, nd, key, self.__unit__ = unit self.__ingobject__ = ingObject - def _reset (self): + def _reset(self): """Try to create matter from vapor and return it. If we fail we return more vapor.""" - if not self.__rowref__: - if self.__mult__: - ni = self.__nd__.get_nutinfo(self.__key__) - if not isinstance(ni,NutritionVapor): return ni * self.__mult__ - else: return self - else: - return self.__nd__.get_nutinfo_for_item(self.__key__, - self.__amt__, - self.__unit__, - ingObject=self.__ingobject__ - ) - elif self.__amt__: + if not self.__rowref__ and self.__mult__: + ni = self.__nd__.get_nutinfo(self.__key__) + if not isinstance(ni,NutritionVapor): return ni * self.__mult__ + else: return self + elif not self.__rowref__ or not self.__amt__: + return self.__nd__.get_nutinfo_for_item(self.__key__, + self.__amt__, + self.__unit__, + ingObject=self.__ingobject__ + ) + else: c=self.__nd__.get_conversion_for_amt(self.__amt__,self.__unit__,self.__key__,fudge=False) if c: self.__mult__ = c @@ -468,7 +462,6 @@ def _reset (self): ) else: return self - else: return self.__nd__.get_nutinfo_for_item(self.__key__,self.__amt__,self.__unit__,ingObject=self.__ingobject__) def __getattr__ (self,attr): """Return 0 for any requests for a non _ prefixed attribute.""" @@ -502,19 +495,18 @@ def __init__ (self,nutinfos, mult=1,ingObject=None): self.__mult__ = 1 self.__ingobject__ = ingObject - def __getattr__ (self, attr): - if attr[0]!='_': - alist = [getattr(ni,attr) for ni in self.__nutinfos__] - if attr in SUMMABLE_FIELDS: - if self.__mult__: alist = [n * self.__mult__ for n in alist] - return sum(alist) - else: - return ", ".join(map(str,alist)) - else: + def __getattr__(self, attr): + if attr[0] == '_': # somehow this magically gets us standard # attribute handling... raise AttributeError(attr) + alist = [getattr(ni,attr) for ni in self.__nutinfos__] + if attr not in SUMMABLE_FIELDS: + return ", ".join(map(str,alist)) + if self.__mult__: alist = [n * self.__mult__ for n in alist] + return sum(alist) + def _reset (self): """See if we can turn any of our vapor into matter.""" for i in range(len(self.__nutinfos__)): @@ -535,14 +527,14 @@ def _get_vapor (self): ret.extend(i._get_vapor()) return ret - def _get_fudge (self): + def _get_fudge(self): """Return a list of fudged items """ - ret = [] - for i in self.__nutinfos__: - if hasattr(i,'__fudged__') and i.__fudged__: - ret.append(i) - return ret + return [ + i + for i in self.__nutinfos__ + if hasattr(i, '__fudged__') and i.__fudged__ + ] def __add__ (self, obj): if isinstance(obj,NutritionInfo): @@ -564,19 +556,16 @@ def __getitem__ (self,x): return self.__nutinfos__[x] def __repr__ (self): return '' - def __iter__ (self): - for i in self.__nutinfos__: yield i + def __iter__(self): + yield from self.__nutinfos__ - def recursive_length (self): + def recursive_length(self): """Return number of contained nutrition info objects, recursing any embedded lists. """ n = 0 for x in range(len(self)): obj = self[x] - if isinstance(obj,NutritionInfoList): - n += obj.recursive_length() - else: - n += 1 + n += obj.recursive_length() if isinstance(obj,NutritionInfoList) else 1 return n if __name__ == '__main__': @@ -601,7 +590,7 @@ def __init__ (self, nd): self.nd = nd self.ings = [] - def run (self): + def run(self): choices = list(self.ACTIONS.keys()) for n,a in enumerate(choices): print(n,a) @@ -609,8 +598,7 @@ def run (self): while not choice: choice = input('Enter number of choice: ') choice = int(choice) - if choice < len(choices): choice = self.ACTIONS[choices[choice]] - else: choice = None + choice = self.ACTIONS[choices[choice]] if choice < len(choices) else None try: choice() except: @@ -628,7 +616,7 @@ def add_ingredient (self): else: self.ings = self.ings + self.nd.get_nutinfo_for_item(key,amt,unit) - def add_key (self): + def add_key(self): key=input('Enter key for which we add info: ') matches = self.nd.get_matches(key,10) for n,m in enumerate(matches): @@ -637,8 +625,7 @@ def add_key (self): while not choice: choice = input('Enter number of choice: ') choice = int(choice) - if choice < len(matches): choice = matches[choice][1] - else: choice = None + choice = matches[choice][1] if choice < len(matches) else None self.nd.set_key_from_ndbno(key,choice) self.ings._reset() diff --git a/src/gourmand/plugins/nutritional_information/nutritionDruid.py b/src/gourmand/plugins/nutritional_information/nutritionDruid.py index 4d80ac2b..6fec9cb2 100644 --- a/src/gourmand/plugins/nutritional_information/nutritionDruid.py +++ b/src/gourmand/plugins/nutritional_information/nutritionDruid.py @@ -162,13 +162,11 @@ def set_search (self, txt): self.__last_search__ = search_text self.__override_search__ = False # turn back on search handling! - def get_selected_usda_item (self): + def get_selected_usda_item(self): if len(self.searchvw)==1: - nut = self.searchvw[0].ndbno - else: - mod,itr = self.usdaTreeview.get_selection().get_selected() - nut = mod.get_value(itr,0) - return nut + return self.searchvw[0].ndbno + mod,itr = self.usdaTreeview.get_selection().get_selected() + return mod.get_value(itr,0) def _setup_nuttree_ (self): """Set up our treeview with USDA nutritional equivalents""" @@ -236,12 +234,9 @@ def search (self): self.nutrition_store.change_view(self.searchvw) self.nutrition_store.set_page(0) - def food_group_filter_changed_cb (self, fgcb): + def food_group_filter_changed_cb(self, fgcb): food_group = cb.cb_get_active_text(fgcb) - if food_group==self.ALL_GROUPS: - self.group = None - else: - self.group = food_group + self.group = None if food_group==self.ALL_GROUPS else food_group GObject.idle_add(self.search) class NutritionInfoDruid (GObject.GObject): @@ -415,7 +410,7 @@ def show_info_page (self, nutalias): self.set_density_info(nutalias) self.info_nutalias = nutalias - def set_density_info (self, nutalias): + def set_density_info(self, nutalias): densities,extra_units = self.nd.get_conversions(nutalias.ingkey) density_texts = [] for k,v in list(densities.items()): @@ -431,9 +426,9 @@ def set_density_info (self, nutalias): extra_units_text or 'None' ) others = self.rd.fetch_all(self.rd.nutritionconversions_table,ingkey=nutalias.ingkey) - other_label = '\n'.join(['%s: %.1f g'%( + other_label = '\n'.join('%s: %.1f g'%( conv.unit or '100 %s'%_('ml'),1.0/conv.factor - ) for conv in others]) + ) for conv in others) if others: self.populate_custom_equivalents_table(others) else: @@ -709,7 +704,7 @@ def setup_to_units (self): self.toUnitCombo.set_active(0) self.toUnitCombo.set_wrap_width(3) - def apply_amt_convert (self,*args): + def apply_amt_convert(self,*args): to_unit = cb.cb_get_active_text(self.toUnitCombo) base_convert = self.nd.conv.converter('g',to_unit) if not base_convert: @@ -722,9 +717,9 @@ def apply_amt_convert (self,*args): to_unit,describer = to_unit.split(' (') describer = describer[0:-1] density = self.densities[describer] + elif None not in self.densities: + raise RuntimeError("Unable to make sense of conversion from %s %s"%(to_unit,self.ingkey)) else: - if None not in self.densities: - raise RuntimeError("Unable to make sense of conversion from %s %s"%(to_unit,self.ingkey)) density = self.densities[None] base_convert = self.nd.conv.converter('g',to_unit,density=density) to_amount = convert.frac_to_float(self.toAmountEntry.get_text()) @@ -756,7 +751,7 @@ def apply_nut_equivalent (self,*args): ### BEGIN CALLBACKS FOR QUICK-CHANGES OF INGREDIENT KEY / UNIT - def apply_ingkey (self,*args): + def apply_ingkey(self,*args): key = self.ingKeyEntry.get_text() if key==self.ingkey: self.changeIngKeyAction.dehighlight_action() @@ -779,16 +774,15 @@ def apply_ingkey (self,*args): except de.UserCancelledError: self.changeIngKeyAction.dehighlight_action() return - else: - if not de.getBoolean(label=_('Change ingredient key'), + elif not de.getBoolean(label=_('Change ingredient key'), sublabel=_('Change ingredient key from %(old_key)s to %(new_key)s everywhere?' )%{'old_key':self.ingkey, 'new_key':key, }, cancel=False, ): - self.changeIngKeyAction.dehighlight_action() - return + self.changeIngKeyAction.dehighlight_action() + return if self.rec and user_says_yes: self.rd.update_by_criteria(self.rd.ingredients_table, {'ingkey':self.ingkey, @@ -879,7 +873,7 @@ def apply_density (self): ### BEGIN CALLBACKS TO WALK THROUGH INGREDIENTS - def add_ingredients (self, inglist, full_inglist=[]): + def add_ingredients(self, inglist, full_inglist=[]): """Add a list of ingredients for our druid to guide the user through. Our ingredient list is in the following form for, believe it @@ -903,13 +897,12 @@ def add_ingredients (self, inglist, full_inglist=[]): # to start, we take our first ing self.inglist = inglist if not full_inglist: + self.full_inglist = [] if self.rec: - self.full_inglist = [] for i in self.rd.get_ings(self.rec): self.full_inglist.append(i.ingkey) self.def_ingredient_amounts[i.ingkey] = (i.amount,i.unit) else: - self.full_inglist = [] for ingkey,amounts_and_units in self.inglist: self.full_inglist.append(ingkey) if amounts_and_units: diff --git a/src/gourmand/reccard.py b/src/gourmand/reccard.py index 38202b01..cc2dc1fa 100644 --- a/src/gourmand/reccard.py +++ b/src/gourmand/reccard.py @@ -37,13 +37,12 @@ def find_entry(widget) -> Optional[Gtk.Entry]: """Recurse through all the children widgets to find the first Gtk.Entry.""" if isinstance(widget, Gtk.Entry): return widget - else: - if not hasattr(widget, 'get_children'): - return - for child in widget.get_children(): - e = find_entry(child) - if e is not None: - return e + if not hasattr(widget, 'get_children'): + return + for child in widget.get_children(): + e = find_entry(child) + if e is not None: + return e class RecRef: @@ -64,8 +63,8 @@ def __init__(self, self.__rec_gui = rec_gui self.__rec_editor: Optional[RecEditor] = None self.__rec_display: Optional[RecCardDisplay] = None - self.__new: bool = True if recipe is None else False - self.__current_rec: 'RowProxy' = recipe if recipe else rec_gui.rd.new_rec() # noqa + self.__new: bool = recipe is None + self.__current_rec: 'RowProxy' = recipe or rec_gui.rd.new_rec() self.conf = [] # This list is unused, and should be refactored out @@ -86,9 +85,7 @@ def current_rec(self, rec: 'RowProxy') -> None: @property def edited(self) -> bool: - if self.__rec_editor is not None and self.__rec_editor.edited: - return True - return False + return bool(self.__rec_editor is not None and self.__rec_editor.edited) @edited.setter def edited(self, val: bool) -> None: @@ -569,13 +566,9 @@ def export_cb (self, *args): url='file:///%s'%fn) - def toggle_readable_units_cb (self, widget): - if widget.get_active(): - self.prefs['readableUnits']=True - self.ingredientDisplay.display_ingredients() - else: - self.prefs['readableUnits']=False - self.ingredientDisplay.display_ingredients() + def toggle_readable_units_cb(self, widget): + self.prefs['readableUnits'] = bool(widget.get_active()) + self.ingredientDisplay.display_ingredients() def preferences_cb (self, *args): self.rg.prefsGui.show_dialog(page=self.rg.prefsGui.CARD_PAGE) @@ -698,13 +691,11 @@ def update_from_database (self): def display_ingredients(self): group_strings = [] - group_index = 0 - for group, ings in self.ing_alist: + for group_index, (group, ings) in enumerate(self.ing_alist): labels = [] if group: labels.append(f'{xml.sax.saxutils.escape(group)}') - ing_index = 0 - for i in ings: + for ing_index, i in enumerate(ings): ing_strs = [] amt, unit = self.rg.rd.get_amount_and_unit( i, @@ -727,11 +718,7 @@ def display_ingredients(self): ing_index, group_index) labels.append(istr) - ing_index += 1 - group_strings.append('\n'.join(labels)) - group_index += 1 - label = '\n\n'.join(group_strings) if label: @@ -1656,12 +1643,9 @@ def setup_main_interface (self): self.setup_action_groups() self.edit_textviews = [self.tv] - def update_from_database (self): + def update_from_database(self): txt = getattr(self.re.current_rec,self.prop) - if txt: - txt = txt.encode('utf8','ignore') - else: - txt = "".encode('utf8') + txt = txt.encode('utf8','ignore') if txt else "".encode('utf8') self.tv.get_buffer().set_text(txt) def save (self, recdic): @@ -1772,12 +1756,11 @@ def add_ingredient_from_kwargs (self, group_iter=None, prev_iter=None, ) return iter - def add_new_ingredient (self, + def add_new_ingredient(self, *args, **kwargs ): - ret = self.add_ingredient_from_kwargs(*args,**kwargs) - return ret + return self.add_ingredient_from_kwargs(*args,**kwargs) def undoable_update_ingredient_row (self, ref, d): itr = self.ingredient_editor_module.ingtree_ui.ingController.get_iter_from_persistent_ref(ref) @@ -1809,7 +1792,7 @@ def update_ingredient_row (self,iter, #elif ingkey and self.re.rg.sl.orgdic.has_key(ingkey): # self.imodel.set_value(iter,6,self.re.rg.sl.orgdic[ingkey]) - def add_ingredient (self, ing, prev_iter=None, group_iter=None, + def add_ingredient(self, ing, prev_iter=None, group_iter=None, fallback_on_append=True, shop_cat=None, is_undo=False): """add an ingredient to our model based on an ingredient @@ -1836,10 +1819,7 @@ def add_ingredient (self, ing, prev_iter=None, group_iter=None, self.imodel.set_value(iter, 1, amt) self.imodel.set_value(iter, 2, unit) self.imodel.set_value(iter, 3, i.item) - if i.optional: - opt=True - else: - opt=False + opt = bool(i.optional) self.imodel.set_value(iter, 4, opt) #self.imodel.set_value(iter, 5, i.ingkey) #if shop_cat: @@ -1851,15 +1831,14 @@ def add_ingredient (self, ing, prev_iter=None, group_iter=None, # self.imodel.set_value(iter, 6, None) return iter - def add_group (self, name, prev_iter=None, children_iters=[], fallback_on_append=True): - if not prev_iter: - if fallback_on_append: groupiter = self.imodel.append(None) - else: groupiter = self.imodel.prepend(None) - else: + def add_group(self, name, prev_iter=None, children_iters=[], fallback_on_append=True): + if prev_iter: # ALLOW NO NESTING! while self.imodel.iter_parent(prev_iter): prev_iter = self.imodel.iter_parent(prev_iter) groupiter = self.imodel.insert_after(None,prev_iter,None) + elif fallback_on_append: groupiter = self.imodel.append(None) + else: groupiter = self.imodel.prepend(None) self.imodel.set_value(groupiter, 0, "GROUP %s"%name) self.imodel.set_value(groupiter, 1, name) children_iters.reverse() @@ -1920,24 +1899,17 @@ def delete_iters (self, *iters, **kwargs): debug('IngredientController.delete_iters Performing deletion of %s'%refs,2) u.perform() - def _get_prev_path_ (self, path): + def _get_prev_path_(self, path): if path[-1]==0: - if len(path)==1: - prev_path = None - else: - prev_path = tuple(path[:-1]) + return None if len(path)==1 else tuple(path[:-1]) else: - prev_path = te.path_next(path,-1) - return prev_path + return te.path_next(path,-1) - def _get_undo_info_for_iter_ (self, iter): + def _get_undo_info_for_iter_(self, iter): deleted_dic = self.get_rowdict(iter) path = self.imodel.get_path(iter) prev_path = self._get_prev_path_(path) - if prev_path: - prev_ref = self.get_persistent_ref_from_path(prev_path) - else: - prev_ref = None + prev_ref = self.get_persistent_ref_from_path(prev_path) if prev_path else None ing_obj = self.imodel.get_value(iter,0) return deleted_dic,prev_ref,ing_obj @@ -1995,14 +1967,12 @@ def do_undelete_iters (self, rowdicts_and_iters): self.ingredient_editor_module.ingtree_ui.ingTree.expand_row(self.imodel.get_path(itr),True) # Get a dictionary describing our current row - def get_rowdict (self, iter): - d = {} - for k,n in [('amount',1), + def get_rowdict(self, iter): + d = {k: self.imodel.get_value(iter,n) for k,n in [('amount',1), ('unit',2), ('item',3), ('optional',4), - ]: - d[k] = self.imodel.get_value(iter,n) + ]} ing_obj = self.imodel.get_value(iter,0) self.get_extra_ingredient_attributes( ing_obj, @@ -2010,13 +1980,13 @@ def get_rowdict (self, iter): return d @plugin_loader.pluggable_method - def get_extra_ingredient_attributes (self, ing_obj, ingdict): - if not hasattr(ing_obj,'ingkey') or not ing_obj.ingkey: - if ingdict['item']: - ingdict['ingkey'] = ingdict['item'].split(';')[0] - else: + def get_extra_ingredient_attributes(self, ing_obj, ingdict): + if hasattr(ing_obj, 'ingkey') and ing_obj.ingkey: ingdict['ingkey'] = ing_obj.ingkey + elif ingdict['item']: + ingdict['ingkey'] = ingdict['item'].split(';')[0] + # Get persistent references to items easily def get_persistent_ref_from_path(self, path) -> 'RowProxy': @@ -2024,9 +1994,8 @@ def get_persistent_ref_from_path(self, path) -> 'RowProxy': self.imodel.get_iter(path) ) - def get_persistent_ref_from_iter (self, iter): - uid = self.imodel.get_value(iter,0) - return uid + def get_persistent_ref_from_iter(self, iter): + return self.imodel.get_value(iter,0) def get_path_from_persistent_ref (self, ref): itr = self.get_iter_from_persistent_ref(ref) @@ -2035,7 +2004,7 @@ def get_path_from_persistent_ref (self, ref): itr ) - def get_iter_from_persistent_ref (self, ref): + def get_iter_from_persistent_ref(self, ref): try: if ref in self.commited_items_converter: ref = self.commited_items_converter[ref] @@ -2056,10 +2025,7 @@ def get_iter_from_persistent_ref (self, ref): itr = next else: parent = self.imodel.iter_parent(itr) - if parent: - itr = self.imodel.iter_next(parent) - else: - itr = None + itr = self.imodel.iter_next(parent) if parent else None def commit_ingredients (self): """Commit ingredients as they appear in tree to database.""" @@ -2074,7 +2040,7 @@ def commit_ingredients (self): # can recursively crawl our tree -- so think of commit_iter as # the inside of the loop, only better - def commit_iter (iter, pos, group=None): + def commit_iter(iter, pos, group=None): ing = self.imodel.get_value(iter,0) # If ingredient is a string, than this is a group if isinstance(ing, str): @@ -2084,7 +2050,6 @@ def commit_iter (iter, pos, group=None): pos = commit_iter(i,pos,group) i = self.imodel.iter_next(i) return pos - # Otherwise, this is an ingredient... else: d = self.get_rowdict(iter) # Get the amount as amount and rangeamount @@ -2107,9 +2072,8 @@ def commit_iter (iter, pos, group=None): if not isinstance(ing, (int, RecRef)): for att in ['amount','unit','item','ingkey','position','inggroup','optional']: # Remove all unchanged attrs from dict... - if hasattr(d,att): - if getattr(ing,att)==d[att]: - del d[att] + if hasattr(d, att) and getattr(ing, att) == d[att]: + del d[att] if ing in deleted: # We have not been deleted... deleted.remove(ing) @@ -2273,22 +2237,16 @@ def setup_drag_and_drop (self): # Callbacks and the like - def my_isearch (self, mod, col, key, iter, data=None): + def my_isearch(self, mod, col, key, iter, data=None): # we ignore column info and search by item val = mod.get_value(iter,3) # and by key if val: val += mod.get_value(iter,5) - if val.lower().find(key.lower()) != -1: - return False - else: - return True + return val.lower().find(key.lower()) == -1 else: val = mod.get_value(iter,1) - if val and val.lower().find(key.lower())!=-1: - return False - else: - return True + return not val or val.lower().find(key.lower()) == -1 def ingtree_row_activated_cb (self, tv, path, col, p=None): debug("ingtree_row_activated_cb (self, tv, path, col, p=None):",5) @@ -2304,9 +2262,9 @@ def ingtree_row_activated_cb (self, tv, path, col, p=None): i.refid) ) - def ingtree_keypress_cb (self, widget, event): + def ingtree_keypress_cb(self, widget, event): keyname = Gdk.keyval_name(event.keyval) - if keyname == 'Delete' or keyname == 'BackSpace': + if keyname in ['Delete', 'BackSpace']: self.ingredient_editor_module.delete_cb() return True @@ -2323,10 +2281,9 @@ def selection_changed_cb (self, *args): # else: self.re.ie.new() return True - def selection_changed (self, selected=False): + def selection_changed(self, selected=False): if selected != self.selected: - if selected: self.selected=True - else: self.selected=False + self.selected = bool(selected) if hasattr(self.ingredient_editor_module,'ingredientEditorOnRowActionGroup'): self.ingredient_editor_module.ingredientEditorOnRowActionGroup.set_sensitive(self.selected) @@ -2366,20 +2323,19 @@ def ingtree_start_keyedit_cb (self, renderer, cbe, path_string): myfilter.set_visible_func(vis) myfilter.refilter() - def ingtree_edited_cb (self, renderer, path_string, text, colnum, head): + def ingtree_edited_cb(self, renderer, path_string, text, colnum, head): indices = path_string.split(':') path = tuple( map(int, indices)) store = self.ingTree.get_model() iter = store.get_iter(path) ing=store.get_value(iter,0) - d = {} if isinstance(ing, str): debug('Changing group to %s'%text,2) self.change_group(iter, text) return else: attr=self.head_to_att[head] - d[attr]=text + d = {attr: text} if attr=='amount': try: parse_range(text) @@ -2427,21 +2383,21 @@ def dragIngsRecCB(self, widget: Gtk.TreeView, context: Any, def do_move(): debug('do_move - inside dragIngsRecCB ',3) debug('do_move - get selected_iters from - %s '%selected_iter_refs,3) - if dref: - diter = self.ingController.get_iter_from_persistent_ref(dref) - else: - diter = None - + diter = self.ingController.get_iter_from_persistent_ref(dref) if dref else None uts.record_positions(self.selected_iters) selected_iters = reversed(self.selected_iters) - if (group and (position == Gtk.TreeViewDropPosition.INTO_OR_BEFORE or - position == Gtk.TreeViewDropPosition.INTO_OR_AFTER)): + if group and position in [ + Gtk.TreeViewDropPosition.INTO_OR_BEFORE, + Gtk.TreeViewDropPosition.INTO_OR_AFTER, + ]: for i in selected_iters: te.move_iter(mod, i, direction="before", parent=diter) - elif (position == Gtk.TreeViewDropPosition.INTO_OR_BEFORE or - position == Gtk.TreeViewDropPosition.BEFORE): # Moving up from anywhere but bottom + elif position in [ + Gtk.TreeViewDropPosition.INTO_OR_BEFORE, + Gtk.TreeViewDropPosition.BEFORE, + ]: # Moving up from anywhere but bottom for i in selected_iters: te.move_iter(mod, i, sibling=diter, direction="before") @@ -2678,19 +2634,14 @@ def getSelectedIter (self): group=None return group - def get_selected_ing (self): + def get_selected_ing(self): """get selected ingredient""" debug("get_selected_ing (self):",5) path, col = self.ingTree.get_cursor() if path: - itera = self.ingTree.get_model().get_iter(path) - else: - tv,rows = self.ingTree.get_selection().get_selected_rows() - if len(rows) > 0: - itera = rows[0] - else: - itera=None - return itera + return self.ingTree.get_model().get_iter(path) + tv,rows = self.ingTree.get_selection().get_selected_rows() + return rows[0] if len(rows) > 0 else None #if itera: # return self.ingTree.get_model().get_value(itera,0) #else: return None @@ -2890,7 +2841,7 @@ def make_item_model(self): for i,k,c in defaults.lang.INGREDIENT_DATA: self.item_model.append([i]) - def make_key_model (self, myShopCategory): + def make_key_model(self, myShopCategory): # make up the model for the combo box for the ingredient keys if myShopCategory: unique_key_vw = self.rd.get_unique_values('ingkey',table=self.rd.shopcats_table, shopcategory=myShopCategory) @@ -2899,10 +2850,7 @@ def make_key_model (self, myShopCategory): unique_key_vw = self.rd.get_unique_values('ingkey',table=self.rd.ingredients_table) # the key model by default stores a string and a list. self.key_model = Gtk.ListStore(str) - keys=[] - for k in unique_key_vw: - keys.append(k) - + keys = [k for k in unique_key_vw] keys.sort() for k in keys: self.key_model.append([k]) @@ -3007,7 +2955,7 @@ def quit (self): def rec_tree_select_rec (self, *args): self.ok() - def ok (self,*args): + def ok(self,*args): debug('ok',0) pre_iter=self.ingEditor.ingtree_ui.get_selected_ing() try: @@ -3017,10 +2965,7 @@ def ok (self,*args): sublabel=_('Infinite recursion is not allowed in recipes!') ) continue - if rec.yields: - amount = YieldSelector(rec, self.re.window).run() - else: - amount = 1 + amount = YieldSelector(rec, self.re.window).run() if rec.yields else 1 ingdic={'amount':amount, 'unit':'recipe', 'item':rec.title, diff --git a/src/gourmand/recindex.py b/src/gourmand/recindex.py index ca050891..1b123eef 100644 --- a/src/gourmand/recindex.py +++ b/src/gourmand/recindex.py @@ -328,14 +328,13 @@ def setup_reccolumns (self): renderer=Gtk.CellRendererText() renderer.set_property('editable',True) renderer.connect('edited',self.rtree_time_edited_cb,n,c) - def get_colnum (tc): + def get_colnum(tc): try: t = tc.get_title() if t: return _title_to_num_[t.replace('_','')] - else: - print('wtf, no title for ',tc) - return -1 + print('wtf, no title for ',tc) + return -1 except: print('problem with ',tc) raise @@ -514,11 +513,10 @@ def reset_search (self, *args): self.last_search={} # reset search so we redo it self.search() - def get_rec_from_iter (self, iter): + def get_rec_from_iter(self, iter): debug("get_rec_from_iter (self, iter): %s"%iter,5) obj=self.rectree.get_model().get_value(iter,0) - retval=self.rd.get_rec(obj.id) - return retval + return self.rd.get_rec(obj.id) def rtree_time_edited_cb (self, renderer, path_string, text, colnum, attribute): if not text: secs = 0 @@ -570,24 +568,25 @@ def rtree_edited_cb (self, renderer, path_string, text, colnum, attribute): self.rmodel.update_iter(iter) self.rd.save() - def tree_keypress_cb (self, widget, event): + def tree_keypress_cb(self, widget, event): keyname = Gdk.keyval_name(event.keyval) - if keyname in ['Page_Up','Page_Down']: + if keyname in ['Page_Up', 'Page_Down']: sb = self.sw.get_vscrollbar() adj = self.sw.get_vscrollbar().get_adjustment() - val = adj.get_value(); upper = adj.get_upper() - if keyname == 'Page_Up': - if val > 0: - return None - self.rmodel.prev_page() - sb.set_value(upper) - return True - if keyname == 'Page_Down': - if val < (upper - adj.page_size): - return None - self.rmodel.next_page() - sb.set_value(0) - return True + val = adj.get_value() + upper = adj.get_upper() + if keyname == 'Page_Up': + if val > 0: + return None + self.rmodel.prev_page() + sb.set_value(upper) + return True + if keyname == 'Page_Down': + if val < (upper - adj.page_size): + return None + self.rmodel.next_page() + sb.set_value(0) + return True if keyname == 'Home': self.rmodel.goto_first_page() self.sw.get_vscrollbar().set_value(0) @@ -625,26 +624,23 @@ def foreach(model,path,iter,recs): else: return [] - def selection_changedCB (self, *args): + def selection_changedCB(self, *args): """We pass along true or false to selection_changed to say whether there is a selection or not.""" debug("selection_changed (self, *args):",5) v=self.rectree.get_selection().get_selected_rows()[1] - if v: selected=True - else: selected=False + selected = bool(v) self.selection_changed(v) def selection_changed (self, selected=False): """This is a way to act whenever the selection changes.""" pass - def visibility_fun (self, model, iter): + def visibility_fun(self, model, iter): try: - if (model.get_value(iter,0) and + return bool((model.get_value(iter,0) and not model.get_value(iter,0).deleted and - model.get_value(iter, 0).id in self.visible): - return True - else: return False + model.get_value(iter, 0).id in self.visible)) except: debug('something bizaare just happened in visibility_fun',1) return False diff --git a/src/gourmand/recipeIdentifier.py b/src/gourmand/recipeIdentifier.py index 56d6b13f..8670cdd6 100644 --- a/src/gourmand/recipeIdentifier.py +++ b/src/gourmand/recipeIdentifier.py @@ -35,11 +35,8 @@ # Hash stuff. -def standardize_ingredient (ing_object, converter): - if ing_object.item: - ing = ing_object.item - else: - ing = ing_object.ingkey +def standardize_ingredient(ing_object, converter): + ing = ing_object.item or ing_object.ingkey unit,amount = ing_object.unit,ing_object.amount gconv = converter.converter(unit,'g.') vconv = converter.converter(unit,'ml.') @@ -52,10 +49,8 @@ def standardize_ingredient (ing_object, converter): elif vconv: unit = 'ml.' if amount: amount = amount*vconv - if unit in ['g.','ml.']: - # Round to the 10s place... - if amount: - amount = round(amount,-1) + if unit in ['g.', 'ml.'] and amount: + amount = round(amount,-1) istring = "%s %s %s"%(amount,unit,ing) return istring.lower() @@ -67,10 +62,13 @@ def get_ingredient_hash (ings, conv): #print 'Hash',ings,m.hexdigest() return m.hexdigest() -def get_recipe_hash (recipe_object): - recstrings = [] - for field in REC_FIELDS: - if getattr(recipe_object,field): recstrings.append(getattr(recipe_object,field)) +def get_recipe_hash(recipe_object): + recstrings = [ + getattr(recipe_object, field) + for field in REC_FIELDS + if getattr(recipe_object, field) + ] + recstring = '\n'.join(recstrings) recstring = recstring.strip() recstring = recstring.lower() @@ -110,13 +108,13 @@ def format_ings (rec, rd): alist = rd.order_ings(ings) return format_ing_text(alist,rd) -def apply_line_markup (line, markup): +def apply_line_markup(line, markup): out = '' current_tag = '' if len(markup) < len(line): markup += ' '*(len(line)-len(markup)) for n in range(len(line)): - if markup[n]==' ' or markup[n]=='\n': + if markup[n] in [' ', '\n']: tag = None elif markup[n]=='+': tag = 'add' diff --git a/src/gourmand/recipeManager.py b/src/gourmand/recipeManager.py index 3b261367..55211149 100644 --- a/src/gourmand/recipeManager.py +++ b/src/gourmand/recipeManager.py @@ -52,14 +52,12 @@ def init_pantry(self): # A simple CLI for mucking about our DB without firing up gourmet proper class SimpleCLI: - def __init__ (self, rmclass=None, rmargs=None): - if not rmclass: self.rmclass=RecipeManager - else: self.rmclass = rmclass - if not rmargs: self.args=dbargs - else: self.args=rmargs + def __init__(self, rmclass=None, rmargs=None): + self.rmclass = RecipeManager if not rmclass else rmclass + self.args = dbargs if not rmargs else rmargs self.rm = self.rmclass(**self.args) - def __call__ (self): + def __call__(self): print("""Welcome to GRM's handy debugging interface straight to our database. You are now in the midst of our caller class. You can access your recipeManager class through self.rm. @@ -69,13 +67,12 @@ class through self.rm. """) while True: inp = input('GRM>') - if inp == 'quit' or inp == '' or inp == '': + if inp in ['quit', '', '']: break - else: - try: - print('result: %s'%eval(inp)) - except: - print('invalid input.') + try: + print('result: %s'%eval(inp)) + except: + print('invalid input.') def get_recipe_manager (**kwargs): return RecipeManager.instance_for(**kwargs) diff --git a/src/gourmand/shopEditor.py b/src/gourmand/shopEditor.py index cd0cb944..9f93ec8c 100644 --- a/src/gourmand/shopEditor.py +++ b/src/gourmand/shopEditor.py @@ -69,7 +69,7 @@ def __init__ (self, rd=db.recipeManager(), rg=None): def dont_ask_cb (self, widget, *args): self.dont_ask=widget.get_active() - def sort_model_fun (model, iter1, iter2, data): + def sort_model_fun(model, iter1, iter2, data): c1 = model.get_value(iter1, self.CAT_COL) if c1 in self.rg.sl.sh.catorder_dic: c1_order = self.rg.sl.sh.catorder_dic[c1] @@ -93,12 +93,9 @@ def sort_model_fun (model, iter1, iter2, data): compare = 0 # iter1 and iter2 are equal if compare==0: return 0 - # iter1 precedes iter2 if compare: return 1 - # iter2 precedes iter1 - else: return 1 - def filter_visibility_fun (self, mod, iter): + def filter_visibility_fun(self, mod, iter): if not self.search_string: return True str = mod.get_value(iter,self.search_by) @@ -108,14 +105,18 @@ def filter_visibility_fun (self, mod, iter): cat = mod.get_value(iter,self.CAT_COL) if cat in self.cat_to_key: for itm in self.cat_to_key[cat]: - if self.use_regexp: - if re.search(self.search_string, itm): return True - elif itm.find(self.search_string) >= 0: return True - if self.use_regexp: - if re.search(self.search_string, str): return True - else: - if str.find(self.search_string) >= 0: - return True + if ( + self.use_regexp + and re.search(self.search_string, itm) + or not self.use_regexp + and itm.find(self.search_string) >= 0 + ): return True + if ( + self.use_regexp + and re.search(self.search_string, str) + or not self.use_regexp + and str.find(self.search_string) >= 0 + ): return True def setupTreeView (self): self.CAT_COL = 1 @@ -131,7 +132,7 @@ def setupTreeView (self): self.treeview.append_column(col) self.treeview.connect('row-expanded',self.populateChild) - def tree_edited (self, renderer, path_string, text, n, head): + def tree_edited(self, renderer, path_string, text, n, head): indices = path_string.split(':') path = tuple( map(int, indices)) iter = self.filteredModel.convert_iter_to_child_iter(self.filteredModel.get_iter(path)) @@ -145,10 +146,7 @@ def tree_edited (self, renderer, path_string, text, n, head): msg = "Are you sure you want to change the " if n==self.KEY_COL: msg += 'key' if n==self.ITEM_COL: msg += 'item' - if item: - msg += "for \"%s from \"%s\""%(item,key) - else: - msg += " from \"%s\" "%key + msg += "for \"%s from \"%s\""%(item,key) if item else " from \"%s\" "%key msg += " to \"%s\""%text if not de.getBoolean(label=msg, dont_ask_cb=self.dont_ask_cb, @@ -156,11 +154,10 @@ def tree_edited (self, renderer, path_string, text, n, head): return if children and n==self.KEY_COL: self.change_children(key, text, iter) - else: - if n==self.KEY_COL: - self.changeItem(key, item, new_key=text) - elif n==self.ITEM_COL: - self.changeItem(key, item, new_item=text) + elif n==self.KEY_COL: + self.changeItem(key, item, new_key=text) + elif n==self.ITEM_COL: + self.changeItem(key, item, new_item=text) self.treeModel.set_value(iter, n, text) def change_children (self, key, new_key, iter): @@ -216,16 +213,12 @@ def populateChild (self, tv, iter, path): n += 1 child = self.treeModel.iter_nth_child(iter,n) - def doSearch (self): + def doSearch(self): """Do the actual searching.""" self.search_string = self.searchEntry.get_text() search_by_str = cb.cb_get_active_text(self.searchByBox) self.use_regexp = self.regexpTog.get_active() - if search_by_str == 'Key': - self.search_by = self.KEY_COL - else: - #print self.treeModel[-1][self.ITEM_COL] - self.search_by = self.CAT_COL + self.search_by = self.KEY_COL if search_by_str == 'Key' else self.CAT_COL self.filteredModel.refilter() def isearchCB (self, *args): diff --git a/src/gourmand/shopgui.py b/src/gourmand/shopgui.py index f10da7a8..a2a3238d 100644 --- a/src/gourmand/shopgui.py +++ b/src/gourmand/shopgui.py @@ -256,7 +256,7 @@ def slTree_popup_cb (tv, event): # reset the first time self.slTree_sel_changed_cb(self.slTree.get_selection()) - def create_ingTree (self, widget, model): + def create_ingTree(self, widget, model): debug("create_ingTree (self, widget, model):",5) # self.slTree = Gtk.TreeView(self.slMod) tree=widget @@ -271,9 +271,12 @@ def create_ingTree (self, widget, model): ('STRING',0,4), ('COMPOUND_TEXT',0,5), ('text/unicode',0,6),] - tree.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, - list(Gtk.TargetEntry.new(*t) for t in targets), - Gdk.DragAction.COPY | Gdk.DragAction.MOVE) + tree.drag_source_set( + Gdk.ModifierType.BUTTON1_MASK, + [Gtk.TargetEntry.new(*t) for t in targets], + Gdk.DragAction.COPY | Gdk.DragAction.MOVE, + ) + tree.enable_model_drag_dest(targets, Gdk.DragAction.COPY | Gdk.DragAction.MOVE) tree.connect('drag_begin', self.on_drag_begin) @@ -366,7 +369,10 @@ def on_drag_data_received(self, tv, context,x,y,selection,info,time): debug("Saving new category orders",0) self.commit_category_orders(tv) # and now we need to move our new category into place... - if drop_where==Gtk.TreeViewDropPosition.AFTER or drop_where==Gtk.TreeViewDropPosition.INTO_OR_AFTER: + if drop_where in [ + Gtk.TreeViewDropPosition.AFTER, + Gtk.TreeViewDropPosition.INTO_OR_AFTER, + ]: new_pos=self.sh.catorder_dic[cat]+0.5 else: new_pos=self.sh.catorder_dic[cat]-0.5 @@ -378,7 +384,6 @@ def on_drag_data_received(self, tv, context,x,y,selection,info,time): self.resetSL() self.ssave.restore_selections(tv=self.slTree) self.pssave.restore_selections(tv=self.pTree) - # except TypeError: else: debug("Out of range!",0) elif str(selection.target) == 'GOURMET_SHOPPER': @@ -626,11 +631,11 @@ def setup_add_box (self): self.add_entry.connect('activate',self.item_added) self.add_button.connect('clicked',self.item_added) - def get_catmodel (self): - if hasattr(self,'catmodel'): return self.catmodel - else: + def get_catmodel(self): + if not hasattr(self, 'catmodel'): self.catmodel = Gtk.ListStore(str) - return self.catmodel + + if hasattr(self,'catmodel'): return self.catmodel def setup_cat_box (self): # Setup change-category widget @@ -711,7 +716,7 @@ def setup_actions (self): self.ui_manager.insert_action_group(self.recipeListActions,0) IngredientAndPantryList.setup_actions(self) - def getOptionalIngDic (self, ivw, mult, prefs): + def getOptionalIngDic(self, ivw, mult, prefs): """Return a dictionary of optional ingredients with a TRUE|FALSE value Alternatively, we return a boolean value, in which case that is @@ -726,19 +731,13 @@ def getOptionalIngDic (self, ivw, mult, prefs): # optional_mode: 0==ask, 1==add, -1==dont add optional_mode=prefs.get('shop_handle_optional',0) if optional_mode: - if optional_mode==1: - return True - elif optional_mode==-1: + if optional_mode == -1: return False + elif optional_mode == 1: + return True elif len(vw) > 0: - if not None in [i.shopoptional for i in vw]: - # in this case, we have a simple job -- load our saved - # defaults - dic = {} - for i in vw: - if i.shopoptional==2: dic[i.ingkey]=True - else: dic[i.ingkey]=False - return dic + if None not in [i.shopoptional for i in vw]: + return {i.ingkey: i.shopoptional==2 for i in vw} # otherwise, we ask our user oid=OptionalIngDialog(vw, prefs, mult) retval = oid.run() @@ -804,7 +803,7 @@ def foreach(model,path,iter,recs): debug("%s selected recs: %s"%(len(recs),recs),3) return recs - def commit_category_orders (self, tv, space_before=None, space_after=None): + def commit_category_orders(self, tv, space_before=None, space_after=None): """Commit the order of categories to memory. We allow for making room before or after a given iter, in which case""" @@ -813,10 +812,7 @@ def commit_category_orders (self, tv, space_before=None, space_after=None): last_val = -100 while iter: cat = mod.get_value(iter,0) - if cat in self.sh.catorder_dic: - val = self.sh.catorder_dic[cat] - else: - val = 0 + val = self.sh.catorder_dic[cat] if cat in self.sh.catorder_dic else 0 if val <= last_val: val = last_val + 10 self.sh.catorder_dic[cat] = val diff --git a/src/gourmand/shopping.py b/src/gourmand/shopping.py index 3b22edd6..dabeea96 100644 --- a/src/gourmand/shopping.py +++ b/src/gourmand/shopping.py @@ -146,7 +146,7 @@ def list_writer (self, for i,a in d: write_item(a,i) - def organize (self, dic=None): + def organize(self, dic=None): """We organize our ingredients into lists in the form. [Category, [[ingredient, amt], [ingredient, amt]... @@ -155,8 +155,6 @@ def organize (self, dic=None): ## first we build a dictionary, since it gives us an ## easy way to sort by category cats = {} - if not dic: - pass for i,a in list(dic.items()): if self.orgdic.has_key(i) and self.orgdic[i]: c = self.orgdic[i] @@ -169,9 +167,7 @@ def organize (self, dic=None): ## next we turn our nested dictionaries into nested lists lst = [] for c,d in list(cats.items()): - itms = [] - for i,amts in list(d.items()): - itms.append([i,self.amt_to_string(amts)]) + itms = [[i,self.amt_to_string(amts)] for i,amts in list(d.items())] lst.append([c,itms]) ## now that we have lists, we can sort them from functools import cmp_to_key @@ -199,28 +195,21 @@ def _cat_compare (self,cata,catb): if cata == catb: return 0 else: return -1 - def _ing_compare (self,inga,ingb): + def _ing_compare(self,inga,ingb): """Put two ingredients in order""" inga = inga[0] ingb = ingb[0] - if False and inga in self.ingorder_dic and ingb in self.ingorder_dic: - # if both ings have known positions, we use them to compare - inga = self.ingorder_dic[inga] - ingb = self.ingorder_dic[ingb] - else: - # otherwise, we just use > to sort alphabetically - inga = inga.lower() - ingb = ingb.lower() + # otherwise, we just use > to sort alphabetically + inga = inga.lower() + ingb = ingb.lower() if inga > ingb: return 1 if inga == ingb: return 0 else: return -1 - def get_porg_categories (self): + def get_porg_categories(self): """Return a list of categories used for sorting.""" - tmp = {} - for v in list(self.orgdic.values()): - tmp[v]=1 + tmp = {v: 1 for v in list(self.orgdic.values())} return list(tmp.keys()) def add_org_itm (self, itm, cat): @@ -294,7 +283,7 @@ def organize_list (self, lst): debug("returning: data=%s pantry=%s"%(data,pantry),5) return data,pantry - def grabIngFromRec (self, rec, mult=1): + def grabIngFromRec(self, rec, mult=1): """Get an ingredient from a recipe and return a list with our amt,unit,key""" """We will need [[amt,un,key],[amt,un,key]]""" debug("grabIngFromRec (self, rec=%s, mult=%s):"%(rec,mult),5) @@ -303,23 +292,18 @@ def grabIngFromRec (self, rec, mult=1): lst = [] include_dic = self.includes.get(rec.id) or {} for i in ings: - if hasattr(i,'refid'): refid=i.refid - else: refid=None + refid = i.refid if hasattr(i,'refid') else None debug("adding ing %s, %s"%(i.item,refid),4) if i.optional: # handle boolean includes value which applies to ALL ingredients if not include_dic: continue - if isinstance(include_dic, dict): - # Then we have to look at the dictionary itself... - if ((i.ingkey not in include_dic) - or - not include_dic[i.ingkey]): - # we ignore our ingredient (don't add it) - continue - if self.rd.get_amount(i): - amount=self.rd.get_amount(i,mult=mult) - else: amount=None + if isinstance(include_dic, dict) and ( + ((i.ingkey not in include_dic) or not include_dic[i.ingkey]) + ): + # we ignore our ingredient (don't add it) + continue + amount = self.rd.get_amount(i,mult=mult) if self.rd.get_amount(i) else None if refid: ## a reference tells us to get another recipe ## entirely. it has two parts: i.item (regular name), diff --git a/src/gourmand/timer.py b/src/gourmand/timer.py index 0c166b24..e583570a 100644 --- a/src/gourmand/timer.py +++ b/src/gourmand/timer.py @@ -72,31 +72,29 @@ def tick(self) -> bool: Returns a bool to notify the event-loop on whether the timer is done. """ - if self.is_running: - if self.previous_iter_time is None or self.remaining is None: - # 1 second is removed from the remaining time, in order to have - # a smooth start of the timer. - # Without this subtraction, after `self.previous_iter_time` is - # set, the elapsed time for this initial iteration is - # calculated, but the difference too small, making the first - # timer second last two iterations (hence two actual seconds). - self.remaining = self.get_time() - 1 - self.previous_iter_time = time.time() - - now = time.time() - elapsed = now - self.previous_iter_time - self.previous_iter_time = now - - self.remaining = self.remaining - elapsed - self.set_time(self.remaining) - - if self.remaining <= 0: - self.finish_timer() - return False - else: - return True - else: + if not self.is_running: return False + if self.previous_iter_time is None or self.remaining is None: + # 1 second is removed from the remaining time, in order to have + # a smooth start of the timer. + # Without this subtraction, after `self.previous_iter_time` is + # set, the elapsed time for this initial iteration is + # calculated, but the difference too small, making the first + # timer second last two iterations (hence two actual seconds). + self.remaining = self.get_time() - 1 + self.previous_iter_time = time.time() + + now = time.time() + elapsed = now - self.previous_iter_time + self.previous_iter_time = now + + self.remaining = self.remaining - elapsed + self.set_time(self.remaining) + + if self.remaining > 0: + return True + self.finish_timer() + return False def start_cb(self, *args): if not self.is_running: @@ -186,10 +184,7 @@ def set_time(self, s): def note_changed_cb(self, entry): txt = entry.get_text() self.note = txt - if txt: - txt = _('Timer') + ': ' + txt - else: - txt = _('Timer') + txt = _('Timer') + ': ' + txt if txt else _('Timer') self.timerDialog.set_title(txt) self.mainLabel.set_markup( '' +