Пример #1
0
    def update_sensitives(self, affectlocal=False):
        """ update bottom button sensitives based on rev and tag """
        rev = self.reventry.get_text()
        tag = self.tagentry.get_text()
        if not rev or not tag:
            self.addbtn.set_sensitive(False)
            self.removebtn.set_sensitive(False)
            return

        # check if valid revision
        try:
            self.repo[hglib.fromutf(rev)]
        except (error.LookupError, error.RepoLookupError, error.RepoError):
            self.addbtn.set_sensitive(False)
            self.removebtn.set_sensitive(False)
            return
        # check tag existence
        force = self.replacechk.get_active()
        is_exist = hglib.fromutf(tag) in self.repo.tags()
        self.addbtn.set_sensitive(not is_exist or force)
        self.removebtn.set_sensitive(is_exist)

        # check if local
        is_local = self.repo.tagtype(hglib.fromutf(tag))
        if affectlocal and is_local is not None:
            self.localchk.set_active(is_local == "local")
        self.update_revision()
Пример #2
0
 def rundlg(q):
     import win32gui, win32con, pywintypes
     cwd = os.getcwd()
     fname = None
     try:
         f = ''
         for name, mask in self.filter:
             f += '\0'.join([name, mask,''])
         flags = win32con.OFN_EXPLORER
         if self.multi:
             flags |= win32con.OFN_ALLOWMULTISELECT
         opts = dict(InitialDir=self.initial,
                 Flags=flags,
                 File=self.filename,
                 DefExt=None,
                 Title=hglib.fromutf(self.title),
                 Filter= hglib.fromutf(f),
                 CustomFilter=None,
                 FilterIndex=self.filterindex)
         if self.open:
             ret = win32gui.GetOpenFileNameW(**opts)
         else:
             ret = win32gui.GetSaveFileNameW(**opts)
         fname = ret[0]
     except pywintypes.error:
         pass
     os.chdir(cwd)
     q.put(fname)
Пример #3
0
    def update_revision(self):
        """ update revision entry based on tag """
        tagmap = self.repo.tags()
        tag = self.tagentry.get_text()
        replace = self.replacechk.get_active()
        if not tag or hglib.fromutf(tag) not in tagmap or replace:
            if self.initial_rev:
                self.reventry.set_text(self.initial_rev)
            return

        node = tagmap[hglib.fromutf(tag)]
        ctx = self.repo[node]
        self.reventry.set_text(str(ctx.rev()))
Пример #4
0
    def add_hg_tag(self, name, revision, message, local, user=None, date=None, force=False, english=False):
        if hglib.fromutf(name) in self.repo.tags() and not force:
            raise util.Abort(_('a tag named "%s" already exists') % name)

        ctx = self.repo[revision]
        r = ctx.node()

        if not message:
            msgset = keep._("Added tag %s for changeset %s")
            message = (english and msgset["id"] or msgset["str"]) % (name, str(ctx))
        if name in self.repo.tags() and not force:
            raise util.Abort(_("Tag '%s' already exist") % name)

        lname = hglib.fromutf(name)
        self.repo.tag(lname, r, hglib.fromutf(message), local, user, date)
Пример #5
0
    def _refresh(self, initial):
        def fill_history(history, vlist, cpath):
            vlist.clear()
            if cpath not in history.get_keys():
                return
            for v in history.get_value(cpath):
                vlist.append([v])

        history = settings.Settings('email')
        try:
            repo = hg.repository(ui.ui(), path=self.root)
            self.repo = repo
        except error.RepoError:
            self.repo = None
            return

        def getfromaddr(ui):
            """Get sender address in the same manner as patchbomb"""
            addr = ui.config('email', 'from') or ui.config('patchbomb', 'from')
            if addr:
                return addr
            try:
                return repo.ui.username()
            except error.Abort:
                return ''

        if initial:
            # Only zap these fields at startup
            self._tobox.child.set_text(hglib.fromutf(repo.ui.config('email', 'to', '')))
            self._ccbox.child.set_text(hglib.fromutf(repo.ui.config('email', 'cc', '')))
            self._frombox.child.set_text(hglib.fromutf(getfromaddr(repo.ui)))
            self._subjbox.child.set_text(hglib.fromutf(repo.ui.config('email', 'subject', '')))
            self.tips.set_tip(self._eventbox,
                    _('Patch series description is sent in initial summary '
                      'email with [PATCH 0 of N] subject.  It should describe '
                      'the effects of the entire patch series.  When emailing '
                      'a bundle, these fields make up the message subject and '
                      'body. Flags is a comma separated list of tags '
                      'which are inserted into the message subject prefix.')
                    )
            gtklib.addspellcheck(self.descview, self.repo.ui)
        fill_history(history, self._tolist, 'email.to')
        fill_history(history, self._cclist, 'email.cc')
        fill_history(history, self._fromlist, 'email.from')
        fill_history(history, self._subjlist, 'email.subject')
        fill_history(history, self._flaglist, 'email.flags')
        if len(self._flaglist) == 0:
            self._flaglist.append(['STABLE'])
Пример #6
0
    def move_clicked(self, toolbutton, data=None):
        move_list = self.relevant_checked_files('C')
        if move_list:
            # get destination directory to files into
            dlg = gtklib.NativeFolderSelectDialog(
                    title=_('Move files to directory...'),
                    initial=self.repo.root)
            destdir = dlg.run()
            if not destdir:
                return True

            # verify directory
            destroot = paths.find_root(destdir)
            if destroot != self.repo.root:
                gdialog.Prompt(_('Nothing Moved'),
                       _('Cannot move outside repo!'), self).run()
                return True

            # move the files to dest directory
            move_list.append(hglib.fromutf(destdir))
            self.act.hg_move(move_list)
        else:
            gdialog.Prompt(_('Nothing Moved'), _('No movable files selected\n\n'
                    'Note: only clean files can be moved.'), self).run()
        return True
Пример #7
0
    def exec_cmd(self, cmd):
        if self.cmd_running():
            dialog.error_dialog(self, _('Cannot run now'),
                _('Please try again after the previous command has completed'))
            return

        self.stop_button.set_sensitive(True)

        proxy_host = ui.ui().config('http_proxy', 'host', '')
        use_proxy = self.use_proxy.get_active()
        text_entry = self.pathbox.get_child()
        remote_path = hglib.fromutf(text_entry.get_text()).strip()
        remote_path = hglib.validate_synch_path(remote_path, self.repo)

        cmdline = cmd[:]
        cmdline += ['--verbose']
        if proxy_host and not use_proxy:
            cmdline += ["--config", "http_proxy.host="]
        cmdline += ['--', remote_path]
        self.lastcmd = cmdline

        # show command to be executed
        self.write("", False)

        # execute command and show output on text widget
        gobject.timeout_add(10, self.process_queue)
        self.hgthread = hgthread.HgThread(cmdline, parent=self)
        self.hgthread.start()
        self.stbar.begin()
        self.stbar.set_text('hg ' + ' '.join(cmd))

        self.add_src_to_recent(remote_path)
Пример #8
0
 def domerge(self):
     if self.discard.get_active():
         c = self.repo[None]
         if c.modified() or c.added() or c.removed():
             gdialog.Prompt(_('Cannot merge'),
                            _('Uncommitted local changes'), self).run()
             return
         # '.' is safer than self.localrev, in case the user has
         # pulled a fast one on us and updated from the CLI
         ret = gdialog.Confirm(_('Confirm Discard Changes'), [], self,
             _('The changes from revision %s and all unmerged parents '
               'will be discarded.\n\n'
               'Are you sure this is what you want to do?')
                   % (self.otherframe.get_data('revid'))).run()
         if ret != gtk.RESPONSE_YES:
             return
         cmdline = ['hg', 'debugsetparents', '.', self.otherrev]
     else:
         tool = hglib.fromutf(self.mergetool.child.get_text())
         if tool:
             cmdline = ['hg', '--config', 'ui.merge=%s' % tool]
         else:
             cmdline = ['hg']
         cmdline.extend(['merge', '--rev', self.otherrev])
     self.execute_command(cmdline, 'merge')
Пример #9
0
def version(ui, **opts):
    """output version and copyright information"""
    ui.write(_('TortoiseHg Dialogs (version %s), '
               'Mercurial (version %s)\n') %
               (hglib.fromutf(thgversion.version()), hglib.hgversion))
    if not ui.quiet:
        ui.write(shortlicense)
Пример #10
0
        def rundlg(q):
            from win32com.shell import shell, shellcon
            import win32gui, pywintypes

            def BrowseCallbackProc(hwnd, msg, lp, data):
                if msg == shellcon.BFFM_INITIALIZED:
                    win32gui.SendMessage(
                        hwnd, shellcon.BFFM_SETSELECTION, 1, data)
                elif msg == shellcon.BFFM_SELCHANGED:
                    # Set the status text of the
                    # For this message, 'lp' is the address of the PIDL.
                    pidl = shell.AddressAsPIDL(lp)
                    try:
                        path = shell.SHGetPathFromIDList(pidl)
                        win32gui.SendMessage(
                            hwnd, shellcon.BFFM_SETSTATUSTEXT, 0, path)
                    except shell.error:
                        # No path for this PIDL
                        pass

            fname = None
            try: 
                flags = shellcon.BIF_EDITBOX | 0x40 #shellcon.BIF_NEWDIALOGSTYLE
                pidl, _, _ = shell.SHBrowseForFolder(
                   0,
                   None,
                   hglib.fromutf(self.title),
                   flags,
                   BrowseCallbackProc, # callback function
                   self.initial)       # 'data' param for the callback
                if pidl:
                    fname = hglib.toutf(shell.SHGetPathFromIDList(pidl))
            except (pywintypes.error, pywintypes.com_error):
                pass
            q.put(fname)
Пример #11
0
 def rename_file(self, wfile):
     fdir, fname = os.path.split(wfile)
     utf_fname = hglib.toutf(fname)
     newfile = dialog.entry_dialog(self.stat, _('Rename file to:'),
                      True, utf_fname)
     if newfile and newfile != utf_fname:
         self.hg_move([wfile, os.path.join(fdir, hglib.fromutf(newfile))])
     return True
Пример #12
0
    def remove_hg_tag(self, name, message, local, user=None, date=None, english=False):
        lname = hglib.fromutf(name)

        tagtype = self.repo.tagtype(lname)
        if not tagtype:
            raise util.Abort(_("tag '%s' does not exist") % lname)
        if local:
            if tagtype != "local":
                raise util.Abort(_("tag '%s' is not a local tag") % lname)
        else:
            if tagtype != "global":
                raise util.Abort(_("tag '%s' is not a global tag") % lname)

        if not message:
            msgset = keep._("Removed tag %s")
            message = (english and msgset["id"] or msgset["str"]) % name
        r = self.repo[-1].node()
        self.repo.tag(lname, r, hglib.fromutf(message), local, user, date)
Пример #13
0
 def add_glob(self, widget):
     newglob = hglib.fromutf(self.glob_entry.get_text())
     if newglob == '':
         return
     newglob = 'glob:' + newglob
     try:
         match.match(self.repo.root, '', [], [newglob])
     except util.Abort, inst:
         gdialog.Prompt(_('Invalid glob expression'), str(inst),
                        self).run()
         return
Пример #14
0
 def add_regexp(self, widget):
     newregexp = hglib.fromutf(self.regexp_entry.get_text())
     if newregexp == '':
         return
     try:
         match.match(self.repo.root, '', [], ['relre:' + newregexp])
         re.compile(newregexp)
     except (util.Abort, re.error), inst:
         gdialog.Prompt(_('Invalid regexp expression'), str(inst),
                        self).run()
         return
Пример #15
0
 def grep_selection_changed(self, treeview):
     """
     Callback for when the user selects grep output.
     """
     (path, focus) = treeview.get_cursor()
     model = treeview.get_model()
     if path is not None and model is not None:
         iter = model.get_iter(path)
         self.currev = model[iter][GCOL_REVID]
         self.curpath = hglib.fromutf(model[iter][GCOL_PATH])
         self.cslabel.update(model[iter][GCOL_REVID])
Пример #16
0
 def get_rev(self):
     """ Return integer revision number or None """
     revstr = self.revcombo.get_active_text()
     if revstr is None or len(revstr) == 0:
         return None
     if isinstance(revstr, basestring):
         revstr = hglib.fromutf(revstr)
     try:
         revnum = self.repo[revstr].rev()
     except (error.RepoError, error.LookupError):
         return None
     return revnum
Пример #17
0
def agettext(message, context=''):
    """Translate message and convert to local encoding
    such as 'ascii' before being returned.

    Only use this if you need to output translated messages
    to command-line interface (ie: Windows Command Prompt).
    """
    try:
        from tortoisehg.util import hglib
        u = _(message, context)
        return hglib.fromutf(u)
    except (LookupError, UnicodeEncodeError):
        return message
Пример #18
0
def agettext(message, context=''):
    """Translate message and convert to local encoding
    such as 'ascii' before being returned.

    Only use this if you need to output translated messages
    to command-line interface (ie: Windows Command Prompt).
    """
    try:
        from tortoisehg.util import hglib
        u = _(message, context)
        return hglib.fromutf(u)
    except (LookupError, UnicodeEncodeError):
        return message
Пример #19
0
    def backout(self):
        # do not auto-close when finished
        self.set_after_done(False)

        # prepare command line
        cmdline = ['hg', 'backout', '--rev', self.rev]
        if self.merge_button.get_active():
            start, end = self.buf.get_bounds()
            msg = self.buf.get_text(start, end)
            cmdline += ['--merge']
            cmdline += ['--message', hglib.fromutf(msg)]

        # start backing out
        self.execute_command(cmdline)
Пример #20
0
 def email_clicked(self, toolbutton, data=None):
     opts = []
     path = hglib.fromutf(self.pathtext.get_text()).strip()
     rev = self.get_advanced_options().get('rev')
     if path:
         opts.extend(['--outgoing', path])
     elif not rev:
         dialog.info_dialog(self, _('No repository selected'),
                     _('Select a peer repository to compare with'))
         self.pathbox.grab_focus()
         return
     if rev:
         opts.extend(rev)
     dlg = hgemail.EmailDialog(self.root, opts)
     self.show_dialog(dlg)
Пример #21
0
def rename_resp(dlg, response):
    if response != gtk.RESPONSE_OK:
        dlg.destroy()
        return
    try:
        root = paths.find_root()
        repo = hg.repository(ui.ui(), root)
    except (ImportError, error.RepoError):
        dlg.destroy()
        return

    new_name = hglib.fromutf(dlg.entry.get_text())
    opts = {}
    opts['force'] = False # Checkbox? Nah.
    opts['after'] = True
    opts['dry_run'] = False

    saved = sys.stderr
    errors = cStringIO.StringIO()
    toquit = False
    try:
        sys.stderr = errors
        repo.ui.pushbuffer()
        repo.ui.quiet = True
        try:
            new_name = util.canonpath(root, root, new_name)
            targetdir = os.path.dirname(new_name) or '.'
            if dlg.orig.lower() == new_name.lower() and os.path.isdir(dlg.orig):
                os.rename(dlg.orig, new_name)
            else:
                if not os.path.isdir(targetdir):
                    os.makedirs(targetdir)
                shutil.move(dlg.orig, new_name)
            commands.rename(repo.ui, repo, dlg.orig, new_name, **opts)
            toquit = True
        except (OSError, IOError, util.Abort, error.RepoError), inst:
            dialog.error_dialog(None, _('rename error'), str(inst))
            toquit = False
    finally:
        sys.stderr = saved
        textout = errors.getvalue() + repo.ui.popbuffer()
        errors.close()
        if len(textout) > 1:
            dialog.error_dialog(None, _('rename error'), textout)
        elif toquit:
            dlg.destroy()
Пример #22
0
 def conf_clicked(self, toolbutton, data=None):
     newpath = hglib.fromutf(self.pathtext.get_text()).strip()
     for alias, path in self.paths:
         if newpath in (path, url.hidepassword(path)):
             newpath = None
             break
     dlg = thgconfig.ConfigDialog(True)
     dlg.show_all()
     if newpath:
         dlg.new_path(newpath, 'default')
     else:
         dlg.focus_field('tortoisehg.postpull')
     dlg.run()
     dlg.hide()
     self.paths = self.get_paths()
     self.fill_path_combo()
     self.update_pull_setting()
Пример #23
0
    def launch(self, st, fname):
        fname = hglib.fromutf(fname)
        source = self.copies.get(fname, None)
        dir1a, dir1b, dir2 = self.dirs
        rev1a, rev1b, rev2 = self.revs
        ctx1a, ctx1b, ctx2 = self.ctxs

        def getfile(ctx, dir, fname, source):
            m = ctx.manifest()
            if fname in m:
                path = os.path.join(dir, util.localpath(fname))
                return fname, path
            elif source and source in m:
                path = os.path.join(dir, util.localpath(source))
                return source, path
            else:
                nullfile = os.path.join(self.tmproot, 'empty')
                fp = open(nullfile, 'w')
                fp.close()
                return _nonexistant, nullfile

        local, file1a = getfile(ctx1a, dir1a, fname, source)
        if ctx1b:
            other, file1b = getfile(ctx1b, dir1b, fname, source)
        else:
            other = fname
            file1b = None
        fname, file2 = getfile(ctx2, dir2, fname, None)

        label1a = local+rev1a
        label1b = other+rev1b
        label2 = fname+rev2
        if ctx1b:
            label1a += '[local]'
            label1b += '[other]'
            label2 += '[merged]'

        # Function to quote file/dir names in the argument string
        replace = dict(parent=file1a, parent1=file1a, plabel1=label1a,
                       parent2=file1b, plabel2=label1b,
                       repo=self.reponame,
                       phash1=str(ctx1a), phash2=str(ctx1b), chash=str(ctx2),
                       clabel=label2, child=file2)
        args = ctx1b and self.mergeopts or self.diffopts
        launchtool(self.diffpath, args, replace, False)
Пример #24
0
def get_files_from_listfile():
    global _lines
    global _linesutf8
    lines = []
    need_to_utf8 = False
    if os.name == 'nt':
        try:
            fixutf8 = extensions.find("fixutf8")
            if fixutf8:
                need_to_utf8 = True
        except KeyError:
            pass

    if need_to_utf8:
        lines += _linesutf8
        for l in _lines:
            lines.append(hglib.toutf(l))
    else:
        lines += _lines
        for l in _linesutf8:
            lines.append(hglib.fromutf(l))

    # Convert absolute file paths to repo/cwd canonical
    cwd = os.getcwd()
    root = paths.find_root(cwd)
    if not root:
        return lines
    if cwd == root:
        cwd_rel = ''
    else:
        cwd_rel = cwd[len(root + os.sep):] + os.sep
    files = []
    for f in lines:
        try:
            cpath = scmutil.canonpath(root, cwd, f)
            # canonpath will abort on .hg/ paths
        except util.Abort:
            continue
        if cpath.startswith(cwd_rel):
            cpath = cpath[len(cwd_rel):]
            files.append(cpath)
        else:
            files.append(f)
    return files
Пример #25
0
def get_files_from_listfile():
    global _lines
    global _linesutf8
    lines = []
    need_to_utf8 = False
    if os.name == 'nt':
        try:
            fixutf8 = extensions.find("fixutf8")
            if fixutf8:
                need_to_utf8 = True
        except KeyError:
            pass

    if need_to_utf8:
        lines += _linesutf8
        for l in _lines:
            lines.append(hglib.toutf(l))
    else:
        lines += _lines
        for l in _linesutf8:
            lines.append(hglib.fromutf(l))

    # Convert absolute file paths to repo/cwd canonical
    cwd = os.getcwd()
    root = paths.find_root(cwd)
    if not root:
        return lines
    if cwd == root:
        cwd_rel = ''
    else:
        cwd_rel = cwd[len(root+os.sep):] + os.sep
    files = []
    for f in lines:
        try:
            cpath = hglib.canonpath(root, cwd, f)
            # canonpath will abort on .hg/ paths
        except util.Abort:
            continue
        if cpath.startswith(cwd_rel):
            cpath = cpath[len(cwd_rel):]
            files.append(cpath)
        else:
            files.append(f)
    return files
Пример #26
0
 def save_file_rev(self, menuitem):
     wfile = util.localpath(self.curfile)
     wfile, ext = os.path.splitext(os.path.basename(wfile))
     if wfile:
         filename = "%s@%d%s" % (wfile, self.currev, ext)
     else:
         filename = "%s@%d" % (ext, self.currev)
     result = gtklib.NativeSaveFileDialogWrapper(title=_("Save file to"),
                                                 initial=self.cwd,
                                                 filename=filename).run()
     if not result:
         return
     try:
         q = Queue.Queue()
         hglib.hgcmd_toq(q, False, ('cat', '--rev',
                         str(self.currev), '--output', hglib.fromutf(result),
                         self.curfile))
     except (util.Abort, IOError), e:
         gdialog.Prompt(_('Unable to save file'), str(e), self).run()
Пример #27
0
 def update_summaries(self):
     ctxs = self.ctxs
     self.parent1_label.update(ctxs[0])
     merge = len(ctxs) == 2
     if merge:
         self.parent2_label.update(ctxs[1])
     newrev = hglib.fromutf(self.revcombo.get_active_text())
     try:
         new_ctx = self.repo[newrev]
         if not merge and new_ctx.rev() == ctxs[0].rev():
             self.target_label.set_label(_('(same as parent)'))
             clean = self.opt_clean.get_active()
             self.buttons['update'].set_sensitive(clean)
         else:
             self.target_label.update(self.repo[newrev])
             self.buttons['update'].set_sensitive(True)
     except (error.LookupError, error.RepoLookupError, error.RepoError):
         self.target_label.set_label(_('unknown revision!'))
         self.buttons['update'].set_sensitive(False)
Пример #28
0
 def browse_clicked(self, button):
     """Select the destination directory or file"""
     dest = hglib.fromutf(self.destentry.get_text())
     if not os.path.exists(dest):
         dest = os.path.dirname(dest)
     select = self.get_selected_archive_type()
     if select['type'] == 'files':
         response = gtklib.NativeFolderSelectDialog(
                         initial=dest,
                         title=_('Select Destination Folder')).run()
     else:
         ext = '*' + select['ext']
         label = '%s (%s)' % (select['label'], ext)
         response = gtklib.NativeSaveFileDialogWrapper(
                         initial=dest, 
                         title=_('Select Destination File'),
                         filter=((label, ext),
                                 (_('All Files (*.*)'), '*.*'))).run()
     if response:
         self.destentry.set_text(response)
Пример #29
0
    def archive(self):
        # verify input
        type = self.get_selected_archive_type()['type']
        dest = self.destentry.get_text()
        if os.path.exists(dest):
            if type != 'files':
                ret = gdialog.Confirm(_('Confirm Overwrite'), [], self,
                            _('The destination "%s" already exists!\n\n'
                              'Do you want to overwrite it?') % dest).run()
                if ret != gtk.RESPONSE_YES:
                    return False
            elif len(os.listdir(dest)) > 0:
                ret = gdialog.Confirm(_('Confirm Overwrite'), [], self,
                            _('The directory "%s" isn\'t empty!\n\n'
                              'Do you want to overwrite it?') % dest).run()
                if ret != gtk.RESPONSE_YES:
                    return False

        # prepare command line
        cmdline = ['hg', 'archive', '--verbose']
        rev = self.combo.get_active_text()
        if rev != WD_PARENT:
            cmdline.append('--rev')
            cmdline.append(rev)
        cmdline.append('-t')
        cmdline.append(type)
        if self.opt_files_in_rev.get_active():
            ctx = self.repo[rev]
            for f in ctx.files():
                cmdline.append('-I')
                cmdline.append(f)
        cmdline.append('--')
        cmdline.append(hglib.fromutf(dest))

        # start archiving
        self.execute_command(cmdline)
Пример #30
0
def test_fromutf_fallback():
    assert_equals(JAPANESE_KANA_I.encode('euc-jp'),
                  hglib.fromutf(JAPANESE_KANA_I.encode('utf-8')))
Пример #31
0
def test_fromutf_fallback():
    assert_equals(JAPANESE_KANA_I.encode('euc-jp'),
                  hglib.fromutf(JAPANESE_KANA_I.encode('utf-8')))
Пример #32
0
 def file_selected(self, combo):
     'select another ignore file'
     self.ignorefile = hglib.fromutf(combo.get_active_text())
     self.refresh()
Пример #33
0
def test_fromutf_replace():
    assert_equals('?', hglib.fromutf(JAPANESE_KANA_I.encode('utf-8')))
Пример #34
0
def test_fromutf_replace():
    assert_equals('?', hglib.fromutf(JAPANESE_KANA_I.encode('utf-8')))
Пример #35
0
def test_lossless_utf_cannot_roundtrip():
    u = JAPANESE_KANA_I.encode('cp932')  # bad encoding
    l = hglib.fromutf(u)
    assert_not_equals(u, hglib.toutf(l))
Пример #36
0
def test_lossless_utf_replaced():
    u = JAPANESE_KANA_I.encode('utf-8')
    l = hglib.fromutf(u)
    assert_equals('?', l)
    assert_equals(u, hglib.toutf(l))