def _string_dist_basic(str1, str2): """Basic edit distance between two strings, ignoring non-alphanumeric characters and case. Comparisons are based on a transliteration/lowering to ASCII characters. Normalized by string length. """ assert isinstance(str1, six.text_type) assert isinstance(str2, six.text_type) str1 = as_string(unidecode(str1)) str2 = as_string(unidecode(str2)) str1 = re.sub(r'[^a-z0-9]', '', str1.lower()) str2 = re.sub(r'[^a-z0-9]', '', str2.lower()) if not str1 and not str2: return 0.0 return levenshtein_distance(str1, str2) / float(max(len(str1), len(str2)))
def get_modifies(self, items, model_cls, context): modifies = [] for query, modify in items: modify = modify.as_str() mod_query, mods, dels = self.parse_modify(modify, model_cls) if mod_query: raise ui.UserError(u'modifyonimport.{0}["{1}"]: unexpected query `{2}` in value'.format(context, query, mod_query)) elif not mods and not dels: raise ui.UserError(u'modifyonimport.{0}["{1}"]: no modifications found'.format(context, query)) dbquery, _ = parse_query_string(util.as_string(query), model_cls) modifies.append((dbquery, mods, dels)) return modifies
def import_begin(self, session): self.should_write = ui.should_write() self.should_move = ui.should_move() for name, model_cls in [('album', Album), ('singleton', Item)]: modifies = self.get_modifies(self.config['modify_' + name].items(), model_cls, 'modify_' + name) setattr(self, name + '_modifies', modifies) self.album_item_modifies = [] for albumquery, itemmodifies in self.config['modify_album_items'].items(): albumdbquery, _ = parse_query_string(util.as_string(albumquery), Album) modifies = self.get_modifies(itemmodifies.items(), Item, u'modify_album_items.{0}'.format(albumquery)) self.album_item_modifies.append((albumdbquery, modifies))
def value_match(cls, pattern, value): """Determine whether the value matches the pattern. The value may have any type. """ return cls.string_match(pattern, util.as_string(value))
def destination(self, fragment=False, basedir=None, platform=None, path_formats=None): """Returns the path in the library directory designated for the item (i.e., where the file ought to be). fragment makes this method return just the path fragment underneath the root library directory; the path is also returned as Unicode instead of encoded as a bytestring. basedir can override the library's base directory for the destination. """ self._check_db() platform = platform or sys.platform basedir = basedir or self._db.directory path_formats = path_formats or self._db.path_formats # Use a path format based on a query, falling back on the # default. for query, path_format in path_formats: if query == PF_KEY_DEFAULT: continue query, _ = parse_query_string(query, type(self)) if query.match(self): # The query matches the item! Use the corresponding path # format. break else: # No query matched; fall back to default. for query, path_format in path_formats: if query == PF_KEY_DEFAULT: break else: assert False, u"no default path format" if isinstance(path_format, Template): subpath_tmpl = path_format else: subpath_tmpl = Template(path_format) # Evaluate the selected template. subpath = self.evaluate_template(subpath_tmpl, True) # Prepare path for output: normalize Unicode characters. if platform == "darwin": subpath = unicodedata.normalize("NFD", subpath) else: subpath = unicodedata.normalize("NFC", subpath) if beets.config["asciify_paths"]: subpath = unidecode(subpath) maxlen = beets.config["max_filename_length"].get(int) if not maxlen: # When zero, try to determine from filesystem. maxlen = util.max_filename_length(self._db.directory) subpath, fellback = util.legalize_path( subpath, self._db.replacements, maxlen, os.path.splitext(self.path)[1], fragment ) if fellback: # Print an error message if legalization fell back to # default replacements because of the maximum length. log.warning( u"Fell back to default replacements when naming " u"file {}. Configure replacements to avoid lengthening " u"the filename.", subpath, ) if fragment: return util.as_string(subpath) else: return normpath(os.path.join(basedir, subpath))
def root_parser(self, root_parser): self._root_parser = root_parser self.parser.prog = '{0} {1}'.format( as_string(root_parser.get_prog_name()), self.name)
def parse_modify(self, modify, model_cls): modify = util.as_string(modify) args = shlex.split(modify) query, mods, dels = modify_parse_args(decargs(args)) return ' '.join(query), mods, dels