changeset f67a6be959d6 in tryton:default
details: https://hg.tryton.org/tryton?cmd=changeset&node=f67a6be959d6
description:
        Support opening non localhost URI based on Windows UNC filenames

        Return PurePath in file_selection to be OS independent.
        Add url_open that supports Windows UNC.

        issue11320
        review388371003
diffstat:

 tryton/common/__init__.py                           |  81 +++++++++++++++++---
 tryton/common/common.py                             |  22 +++++-
 tryton/gui/window/attachment.py                     |   8 +-
 tryton/gui/window/view_form/view/form_gtk/binary.py |   7 +-
 tryton/gui/window/view_form/view/form_gtk/image.py  |   9 +-
 tryton/gui/window/view_form/view/graph.py           |   3 +-
 6 files changed, 98 insertions(+), 32 deletions(-)

diffs (256 lines):

diff -r 43be33d4329c -r f67a6be959d6 tryton/common/__init__.py
--- a/tryton/common/__init__.py Mon Apr 25 23:22:20 2022 +0200
+++ b/tryton/common/__init__.py Sat Apr 30 22:29:38 2022 +0200
@@ -11,7 +11,7 @@
     get_sensible_widget, get_toplevel_window, hex2rgb, highlight_rgb, humanize,
     idle_add, mailto, message, node_attributes, process_exception,
     resize_pixbuf, selection, setup_window, slugify, sur, sur_3b,
-    timezoned_date, to_xml, untimezoned_date, userwarning, warning)
+    timezoned_date, to_xml, untimezoned_date, url_open, userwarning, warning)
 from .domain_inversion import (
     concat, domain_inversion, eval_domain, extract_reference_models,
     filter_leaf, inverse_leaf, localize_domain, merge,
@@ -19,16 +19,69 @@
 from .environment import EvalEnvironment
 
 __all__ = [
-    IconFactory, MODELACCESS, MODELHISTORY, MODELNAME, MODELNOTIFICATION,
-    VIEW_SEARCH, get_toplevel_window, get_sensible_widget, selection,
-    file_selection, slugify, file_write, file_open, mailto, message, warning,
-    userwarning, sur, sur_3b, ask, concurrency, error, to_xml,
-    process_exception, Login, Logout, node_attributes, hex2rgb, highlight_rgb,
-    generateColorscheme, RPCException, RPCProgress, RPCExecute,
-    RPCContextReload, Tooltips, COLOR_SCHEMES, filter_domain, timezoned_date,
-    untimezoned_date, humanize, get_hostname, get_port, resize_pixbuf,
-    data2pixbuf, apply_label_attributes, ellipsize, get_align, date_format,
-    idle_add, domain_inversion, eval_domain, localize_domain, merge,
-    inverse_leaf, filter_leaf, prepare_reference_domain,
-    extract_reference_models, concat, simplify, unique_value, EvalEnvironment,
-    timedelta, check_version, TRYTON_ICON, setup_window]
+    COLOR_SCHEMES,
+    EvalEnvironment,
+    IconFactory,
+    Login,
+    Logout,
+    MODELACCESS,
+    MODELHISTORY,
+    MODELNAME,
+    MODELNOTIFICATION,
+    RPCContextReload,
+    RPCException,
+    RPCExecute,
+    RPCProgress,
+    TRYTON_ICON,
+    Tooltips,
+    VIEW_SEARCH,
+    apply_label_attributes,
+    ask,
+    check_version,
+    concat, simplify,
+    concurrency,
+    data2pixbuf,
+    date_format,
+    domain_inversion,
+    ellipsize,
+    error,
+    eval_domain,
+    extract_reference_models,
+    file_open,
+    file_selection,
+    file_write,
+    filter_domain,
+    filter_leaf,
+    generateColorscheme,
+    get_align,
+    get_hostname,
+    get_port,
+    get_sensible_widget,
+    get_toplevel_window,
+    hex2rgb,
+    highlight_rgb,
+    humanize,
+    idle_add,
+    inverse_leaf,
+    localize_domain,
+    mailto,
+    merge,
+    message,
+    node_attributes,
+    prepare_reference_domain,
+    process_exception,
+    resize_pixbuf,
+    selection,
+    setup_window,
+    slugify,
+    sur,
+    sur_3b,
+    timedelta,
+    timezoned_date,
+    to_xml,
+    unique_value,
+    untimezoned_date,
+    url_open,
+    userwarning,
+    warning,
+    ]
diff -r 43be33d4329c -r f67a6be959d6 tryton/common/common.py
--- a/tryton/common/common.py   Mon Apr 25 23:22:20 2022 +0200
+++ b/tryton/common/common.py   Sat Apr 30 22:29:38 2022 +0200
@@ -14,6 +14,7 @@
 import xml.etree.ElementTree as ET
 from collections import defaultdict
 from decimal import Decimal
+from pathlib import PurePath
 
 try:
     from http import HTTPStatus
@@ -483,9 +484,9 @@
     if button != Gtk.ResponseType.OK:
         result = None
     elif not multi:
-        result = win.get_filename()
+        result = PurePath(win.get_filename())
     else:
-        result = win.get_filenames()
+        result = [PurePath(f) for f in win.get_filenames()]
     parent.present()
     win.destroy()
     return result
@@ -572,6 +573,23 @@
             save()
 
 
+def url_open(uri):
+    try:
+        return urllib.request.urlopen(uri)
+    except urllib.error.URLError:
+        if sys.platform == 'win32' and uri.startswith('file://'):
+            # There are two ways that Windows UNC filenames can be represented:
+            # file://server/folder/data.xml
+            # file:////server/folder/data.xml
+            if uri.startswith('file:////'):
+                uri = uri[len('file://'):]
+            else:
+                uri = uri[len('file:')]
+            return open(uri)
+        else:
+            raise
+
+
 def mailto(to=None, cc=None, subject=None, body=None, attachment=None):
     if CONFIG['client.email']:
         cmd = Template(CONFIG['client.email']).substitute(
diff -r 43be33d4329c -r f67a6be959d6 tryton/gui/window/attachment.py
--- a/tryton/gui/window/attachment.py   Mon Apr 25 23:22:20 2022 +0200
+++ b/tryton/gui/window/attachment.py   Sat Apr 30 22:29:38 2022 +0200
@@ -6,9 +6,9 @@
 import webbrowser
 from functools import partial
 from urllib.parse import unquote, urlparse
-from urllib.request import urlopen
 
-from tryton.common import RPCException, RPCExecute, file_open, file_write
+from tryton.common import (
+    RPCException, RPCExecute, file_open, file_write, url_open)
 from tryton.gui.window.view_form.screen import Screen
 from tryton.gui.window.win_form import WinForm
 
@@ -53,7 +53,7 @@
             file_name = os.path.basename(unquote(parse.path))
             name_field.set_client(new_record, file_name)
             if parse.scheme == 'file':
-                data_field.set_client(new_record, urlopen(uri).read())
+                data_field.set_client(new_record, url_open(uri).read())
                 type_field.set_client(new_record, 'data')
             else:
                 link_field.set_client(new_record, uri)
@@ -61,7 +61,7 @@
         self.screen.display()
 
     def add_file(self, filename):
-        self.add_uri('file:///' + filename)
+        self.add_uri(filename.as_uri())
 
     @staticmethod
     def get_attachments(record):
diff -r 43be33d4329c -r f67a6be959d6 
tryton/gui/window/view_form/view/form_gtk/binary.py
--- a/tryton/gui/window/view_form/view/form_gtk/binary.py       Mon Apr 25 
23:22:20 2022 +0200
+++ b/tryton/gui/window/view_form/view/form_gtk/binary.py       Sat Apr 30 
22:29:38 2022 +0200
@@ -3,12 +3,11 @@
 import gettext
 import os
 from urllib.parse import unquote, urlparse
-from urllib.request import urlopen
 
 from gi.repository import Gdk, Gtk
 
 from tryton.common import (
-    Tooltips, common, file_open, file_selection, file_write)
+    Tooltips, common, file_open, file_selection, file_write, url_open)
 from tryton.common.entry_position import reset_position
 
 from .widget import Widget
@@ -92,7 +91,7 @@
         filename = file_selection(
             _('Select'), preview=self.preview, filters=self.filters)
         if filename:
-            self._set_uri('file:///' + filename)
+            self._set_uri(filename.as_uri())
 
     def select_drag_data_received(
             self, widget, context, x, y, selection, info, timestamp):
@@ -103,7 +102,7 @@
 
     def _set_uri(self, uri):
         uri = unquote(uri)
-        self.field.set_client(self.record, urlopen(uri).read())
+        self.field.set_client(self.record, url_open(uri).read())
         if self.filename_field:
             self.filename_field.set_client(self.record,
                 os.path.basename(urlparse(uri).path))
diff -r 43be33d4329c -r f67a6be959d6 
tryton/gui/window/view_form/view/form_gtk/image.py
--- a/tryton/gui/window/view_form/view/form_gtk/image.py        Mon Apr 25 
23:22:20 2022 +0200
+++ b/tryton/gui/window/view_form/view/form_gtk/image.py        Sat Apr 30 
22:29:38 2022 +0200
@@ -1,11 +1,10 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 import gettext
-import urllib.request
 
 from gi.repository import Gdk, Gtk
 
-from tryton.common import data2pixbuf, resize_pixbuf
+from tryton.common import data2pixbuf, resize_pixbuf, url_open
 from tryton.config import CONFIG
 
 from .binary import BinaryMixin
@@ -82,14 +81,12 @@
         if info == 0:
             uri = selection.get_text().split('\n')[0]
             if uri:
-                self.field.set_client(
-                    self.record, urllib.request.urlopen(uri).read())
+                self.field.set_client(self.record, url_open(uri).read())
             self.update_img()
         elif info == 1:
             uri = selection.data.split('\r\n')[0]
             if uri:
-                self.field.set_client(
-                    self.record, urllib.request.urlopen(uri).read())
+                self.field.set_client(self.record, url_open(uri).read())
             self.update_img()
         elif info == 2:
             data = selection.get_pixbuf()
diff -r 43be33d4329c -r f67a6be959d6 tryton/gui/window/view_form/view/graph.py
--- a/tryton/gui/window/view_form/view/graph.py Mon Apr 25 23:22:20 2022 +0200
+++ b/tryton/gui/window/view_form/view/graph.py Sat Apr 30 22:29:38 2022 +0200
@@ -163,8 +163,7 @@
                     preview=False,
                     filters=[filter])
                 if width and height and filename:
-                    if not filename.endswith('.png'):
-                        filename = filename + '.png'
+                    filename = filename.with_suffix('.png')
                     try:
                         self.widgets['root'].export_png(
                             filename, width, height)

Reply via email to