[Merge] ~rs2009/unity:master into unity:master

Dmitry Shachnev mp+437213 at code.launchpad.net
Sat Feb 18 14:07:06 UTC 2023


Review: Needs Fixing



Diff comments:

> diff --git a/CMakeLists.txt b/CMakeLists.txt
> index 1d58a46..03be190 100644
> --- a/CMakeLists.txt
> +++ b/CMakeLists.txt
> @@ -29,7 +29,7 @@ option(
>  option(
>    ENABLE_UNIT_TESTS
>    "Enable Unity Unit Tests"
> -  ON
> +  OFF

Disabling auto-tests is usually a bad idea.

Ideally, fix them. Or disable just the failing test(s), with a comment why they can't be fixed.

>  )
>  
>  # This is due to bug lp:668799 - qemu-arm segfaults executing msgmerge
> diff --git a/debian/control b/debian/control
> index c61edb5..b24c845 100644
> --- a/debian/control
> +++ b/debian/control
> @@ -59,6 +59,12 @@ Build-Depends: cmake (>= 3.17.0),
>                 xserver-xorg-video-dummy,
>                 xsltproc,
>                 yaru-theme-icon,
> +               xorg,
> +               libxinerama-dev,
> +               libcairo2-dev,
> +               python3-gi,
> +               gir1.2-gtk-3.0,
> +               gir1.2-glib-2.0

Please keep the list of build-deps sorted.

>  Standards-Version: 3.9.5
>  Homepage: https://launchpad.net/unity
>  # If you aren't a member of ~unity-team but need to upload packaging changes,
> diff --git a/debian/rules b/debian/rules
> index 4b29c43..24136bb 100755
> --- a/debian/rules
> +++ b/debian/rules
> @@ -42,7 +42,13 @@ override_dh_install:
>  	cd $(CURDIR)
>  	find debian/tmp/usr/lib -name \*.*a -exec rm {} \;
>  	rm -rf debian/tmp/usr/share/gconf/schemas
> -	dh_install --fail-missing
> +	# install uwidgets
> +	cd uwidgets; \
> +	set -ex; for python in $(shell py3versions -r); do \

Installing just for the default Python version (python3) is enough, unless it's a public Python module.

> +        $$python setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb; \
> +	done;
> +	install -Dm755 $(CURDIR)/debian/tmp/usr/etc/xdg/autostart/uwidgets-runner.desktop $(CURDIR)/debian/tmp/etc/xdg/autostart/uwidgets-runner.desktop
> +	cd $(CURDIR); dh_install --fail-missing
>  
>  override_dh_gencontrol:
>  	dh_gencontrol -- -Vcoreabiversion=$(CORE_ABIVERSION) -Vnuxabiversion=$(NUX_ABIVERSION) -Vunity-default-masterscopes="$(SCOPES_RECOMMENDS)"
> @@ -51,7 +57,7 @@ override_dh_makeshlibs:
>  	dh_makeshlibs -plibunity-core-6.0-9 -V 'libunity-core-6.0-9 (>= 7.0.0)'
>  
>  override_dh_shlibdeps:
> -	dh_shlibdeps -l$(LIBUNITY_PRIVATE) -O--parallel
> +	echo hello

What? Please revert this.

>  
>  override_dh_auto_test:
>  ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
> diff --git a/uwidgets/official-widgets/clock/clock.py b/uwidgets/official-widgets/clock/clock.py
> new file mode 100755
> index 0000000..09041af
> --- /dev/null
> +++ b/uwidgets/official-widgets/clock/clock.py
> @@ -0,0 +1,104 @@
> +#!/usr/bin/env python3
> +
> +"""
> +This file is part of "blighty" and "uwidgets" which is released under GPL.
> +
> +See file LICENCE or go to http://www.gnu.org/licenses/ for full license

You meant LICENSE.md, not LICENCE? (here and in other files)

> +details.
> +
> +uwidgets is a desktop widget creation and management library for Python 3.
> +
> +Copyright (c) 2022 Rudra Saraswat <rs2009 at ubuntu.com>.
> +Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987 at gmail.com>.
> +All rights reserved.
> +
> +This program is free software: you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation, either version 3 of the License, or
> +(at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +You should have received a copy of the GNU General Public License
> +along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +"""
> +
> +from uwidgets import CanvasGravity, brush
> +from uwidgets.x11 import Canvas, start_event_loop
> +
> +import datetime
> +import subprocess
> +import configparser
> +
> +from math import pi as PI
> +
> +
> +class Clock(Canvas):
> +    def on_button_pressed(self, button, state, x, y):
> +        if button == 3:    # Right button
> +            subprocess.run(['unity-control-center', 'datetime'])
> +
> +    def draw_circle_background(ctx):
> +        ctx.arc(2, 1, 90, 0, 2*PI)
> +        ctx.set_source_rgba(0, 0, 0, 0.6)
> +        ctx.fill()
> +
> +    def draw_rect_background(ctx):
> +        ctx.rectangle(-180, -180, 360, 360)
> +        ctx.set_source_rgba(0, 0, 0, 0.6)
> +        ctx.fill()
> +
> +        ctx.rectangle(-180, -100, 360, 3)
> +        ctx.set_source_rgba(1, 1, 1, 1)
> +        ctx.fill()
> +
> +    @brush
> +    def hand(ctx, angle, length, thickness):
> +        ctx.save()
> +        ctx.set_source_rgba(1, 1, 1, 1)
> +        ctx.set_line_width(thickness)
> +        ctx.rotate(angle)
> +        ctx.move_to(0, length * .2)
> +        ctx.line_to(0, -length)
> +        ctx.stroke()
> +        ctx.restore()
> +
> +    def on_draw(self, ctx):
> +        now = datetime.datetime.now()
> +
> +        ctx.translate(self.width >> 1, self.height >> 1)
> +
> +        eval(f"ctx.draw_{config.get('settings', 'clock_style')}_background()")

eval is not necessary here, getattr should be enough:

getattr(ctx, f"draw_{config.get('settings', 'clock_style')}_background")()

> +
> +        ctx.hand(
> +            angle = now.second / 30 * PI,
> +            length = ((self.height >> 1) * .9) - 20,
> +            thickness = 1
> +        )
> +
> +        mins = now.minute + now.second / 60
> +        ctx.hand(
> +            angle = mins / 30 * PI,
> +            length = ((self.height >> 1) * .8) - 20,
> +            thickness = 3
> +        )
> +
> +        hours = (now.hour % 12) + mins / 60
> +        ctx.hand(
> +            angle = hours / 6 * PI,
> +            length = ((self.height >> 1) * .5) - 20,
> +            thickness = 4.5
> +        )
> +
> +if __name__ == "__main__":
> +    config = configparser.ConfigParser()
> +    config.read('settings.ini')
> +    clock = Clock(eval(config.get('settings', 'margin_x')),
> +                  eval(config.get('settings', 'margin_y')),

Is this need just to cast text to int, or you want to allow arithmetical expressions in config files?

I would avoid it, as it puts a security hole — an attacker with access to your config file can execute random code.

> +                  200,
> +                  200,
> +                  gravity = eval('CanvasGravity.' + config.get('settings', 'gravity')))

Here getattr should work too.

> +    clock.show()
> +    start_event_loop()
> diff --git a/uwidgets/official-widgets/cpu/cpu.py b/uwidgets/official-widgets/cpu/cpu.py
> new file mode 100755
> index 0000000..fa4d5cf
> --- /dev/null
> +++ b/uwidgets/official-widgets/cpu/cpu.py
> @@ -0,0 +1,169 @@
> +#!/usr/bin/env python3
> +
> +from math import pi as PI
> +
> +import configparser
> +import psutil
> +import cairo
> +import os
> +from uwidgets import CanvasGravity, TextAlign
> +from uwidgets.legacy import Graph
> +from uwidgets.x11 import Canvas, start_event_loop
> +
> +
> +class AttrDict(dict):
> +    def __init__(self, *args, **kwargs):
> +        super(AttrDict, self).__init__(*args, **kwargs)
> +        self.__dict__ = self
> +
> +class Fonts(type):

There is no point in inheriting from type (here and in other files).

Just "class Fonts:".

> +    UBUNTU_NORMAL = "Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL
> +
> +
> +class Cpu(Canvas):
> +    SIZE = (256, 256)
> +    CORE_POLYGON = AttrDict({"height": 30, "length": 20})
> +
> +    def __init__(self, *args, **kwargs):
> +        super().__init__(*args, **kwargs)
> +
> +        with open('/proc/cpuinfo', 'r') as fin:
> +            raw_cpuinfo = fin.read().strip()
> +
> +        self.coreinfo = [
> +            {
> +                k.strip(): v
> +                for k, v in [p.split(":") for p in core.split('\n')]
> +            }
> +            for core in raw_cpuinfo.split('\n\n')
> +        ]
> +
> +        self.graph = Graph(0, 110, self.width, 40)
> +
> +    @staticmethod
> +    def build(x = 0, y = 0, gravity = CanvasGravity.CENTER):
> +        return Cpu(x, y, *Cpu.SIZE, gravity = gravity, interval = 2000)
> +
> +    def on_button_pressed(self, button, *args):
> +        os.system('stacer')
> +
> +    def draw_polygon(c, n, x, y, size):
> +        a = 2 * PI / n
> +
> +        c.save()
> +
> +        c.translate(x, y)
> +        c.move_to(size, 0)
> +        for i in range(n):
> +            c.rotate(a)
> +            c.line_to(size, 0)
> +        c.stroke()
> +
> +        c.restore()
> +
> +    def draw_core_polygon(c, x, y):
> +        size = Cpu.CORE_POLYGON.height
> +        length = Cpu.CORE_POLYGON.length
> +
> +        c.save()
> +
> +        c.translate(x, y)
> +
> +        c.set_source_rgb(.8, .8, .8)
> +
> +        cpus = psutil.cpu_percent(0.1, percpu = True)
> +        n = len(cpus)
> +        a = 2 * PI / n
> +
> +        c.set_line_width(1)
> +        c.draw_polygon(n, 0, 0, size)
> +
> +        c.set_line_width(2)
> +        c.set_source_rgb(1, 1, 1)
> +        c.move_to(size + length * cpus[-1] / 100, 0)
> +        for i in range(n):
> +            c.rotate(a)
> +            c.line_to(size + length * cpus[i] / 100, 0)
> +        c.stroke()
> +
> +        value = int(sum(cpus) / n)
> +        c.canvas.graph.push_value(value)
> +
> +        c.set_font_size(18)
> +        c.write_text(0, 0, '{}%'.format(value), TextAlign.CENTER_MIDDLE)
> +
> +        c.restore()
> +
> +        return value
> +
> +    def draw_processes(c):
> +        ps = [
> +            p.info
> +            for p in psutil.process_iter(attrs=['pid', 'name', 'cpu_percent'])
> +        ]
> +
> +        ps = sorted(ps, key=lambda p: p["cpu_percent"], reverse=True)[:5]
> +
> +        y = 170
> +        c.save()
> +        c.select_font_face(*Fonts.UBUNTU_NORMAL)
> +        c.set_font_size(12)
> +        for p in ps:
> +            c.write_text(48, y, str(p["pid"]), align = TextAlign.TOP_RIGHT)
> +            c.write_text(52, y, p["name"][:24])
> +            c.write_text(
> +                c.canvas.width - 15, y, "{}%".format(p["cpu_percent"]),
> +                align=TextAlign.TOP_RIGHT
> +            )
> +            y += 18
> +
> +        c.restore()
> +
> +    def draw_cpu_name(c):
> +        c.save()
> +        c.set_font_size(12)
> +        c.write_text(
> +            15, 110,
> +            c.canvas.coreinfo[0]["model name"].strip()
> +            .replace("(TM)", "™")
> +            .replace("(R)", "©")
> +        )
> +        c.restore()
> +
> +    def draw_background(c):
> +        size = c.canvas.get_size()
> +        c.rectangle(0, 0, *size)
> +        c.set_source_rgba(0, 0, 0, 0.6)
> +        c.fill()
> +
> +        c.rectangle(0, 0, c.canvas.width, 3)
> +        c.set_source_rgba(1, 1, 1, 1)
> +        c.fill()
> +
> +    def on_draw(self, c):
> +        c.draw_background()
> +
> +        c.select_font_face(*Fonts.UBUNTU_NORMAL)
> +        c.set_font_size(36)
> +        c.set_source_rgb(1, 1, 1)
> +
> +        w, h = Cpu.SIZE
> +
> +        y_poly = (Cpu.CORE_POLYGON.height + Cpu.CORE_POLYGON.length)
> +
> +        c.write_text(15, y_poly, "CPU", align = TextAlign.TOP_LEFT)
> +        c.draw_core_polygon(w - y_poly, y_poly)
> +        c.draw_processes()
> +        c.draw_cpu_name()
> +
> +        c.set_source_rgb(1, 1, 1)
> +        self.graph.draw(c)
> +
> +
> +if __name__ == "__main__":
> +    config = configparser.ConfigParser()
> +    config.read('settings.ini')
> +    Cpu.build(eval(config.get('settings', 'margin_x')),
> +              eval(config.get('settings', 'margin_y')),

Same concerns about getattr.

> +              gravity = eval('CanvasGravity.' + config.get('settings', 'gravity'))).show()
> +    start_event_loop()
> diff --git a/uwidgets/official-widgets/spotify/spotify.py b/uwidgets/official-widgets/spotify/spotify.py
> new file mode 100755
> index 0000000..a6ab7ca
> --- /dev/null
> +++ b/uwidgets/official-widgets/spotify/spotify.py
> @@ -0,0 +1,176 @@
> +#!/usr/bin/env python3
> +
> +"""
> +This file is part of "blighty" and "uwidgets" which is released under GPL.
> +
> +See file LICENCE or go to http://www.gnu.org/licenses/ for full license
> +details.
> +
> +uwidgets is a desktop widget creation and management library for Python 3.
> +
> +Copyright (c) 2022 Rudra Saraswat <rs2009 at ubuntu.com>.
> +Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987 at gmail.com>.
> +All rights reserved.
> +
> +This program is free software: you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation, either version 3 of the License, or
> +(at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +You should have received a copy of the GNU General Public License
> +along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +"""
> +
> +from uwidgets import CanvasGravity
> +from uwidgets.x11 import Canvas, start_event_loop
> +from uwidgets import CanvasType
> +
> +import cairo
> +import shutil
> +import requests
> +import subprocess
> +import configparser
> +
> +from gi.repository import GLib
> +
> +from PIL import Image
> +from pydbus import SessionBus
> +
> +
> +class Fonts(type):
> +    UBUNTU_NORMAL = "Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL
> +
> +
> +class SpotifyDBus:
> +    def __init__(self):
> +        self.proxy = SessionBus().get(
> +            'org.mpris.MediaPlayer2.spotify',
> +            '/org/mpris/MediaPlayer2'
> +        )
> +
> +    def get_metadata(self):
> +        return {k.split(':')[1]: v for k, v in self.proxy.Metadata.items()}
> +
> +    def toggle_play(self):
> +        self.proxy.PlayPause()
> +
> +    def is_paused(self):
> +        return self.proxy.PlaybackStatus == "Paused"
> +
> +
> +class Spotify(Canvas):
> +    def __init__(self, *args, **kwargs):
> +        super().__init__(*args, **kwargs)
> +
> +        self.init_dbus()
> +
> +    def init_dbus(self):
> +        try:
> +            self.spotify = SpotifyDBus()
> +        except GLib.Error:
> +            self.spotify = None
> +
> +        self.last_art_url = ""
> +
> +    def on_button_pressed(self, button, state, x, y):
> +        if button == 1:    # Left button
> +            self.spotify.toggle_play()
> +        elif button == 3:  # Right button
> +            subprocess.run(['spotify'])
> +
> +    def draw_background(ctx):
> +        size = ctx.canvas.get_size()
> +        ctx.rectangle(0, 0, *size)
> +        ctx.set_source_rgba(0, 0, 0, 0.6)
> +        ctx.fill()
> +
> +    def draw_decoration(ctx):
> +        ctx.rectangle(0, 0, ctx.canvas.width, 3)
> +        ctx.set_source_rgba(1, 1, 1, 1)
> +        ctx.fill()
> +
> +    def draw_art(ctx, url, pause):
> +        temp_file = "/tmp/spotify_art"
> +        temp_img = temp_file + ".png"
> +
> +        if ctx.canvas.last_art_url != url:
> +            response = requests.get(url, stream=True)
> +            with open(temp_file, 'wb') as out_file:
> +                shutil.copyfileobj(response.raw, out_file)
> +            del response
> +            ctx.canvas.last_art_url = url
> +
> +        # Ensure it is a PNG image
> +        size = min(ctx.canvas.width, ctx.canvas.height)
> +        image = Image.open(temp_file)
> +        image.thumbnail((size, size), Image.ANTIALIAS)
> +        image.save(temp_img)
> +
> +        surface = cairo.ImageSurface.create_from_png(temp_img)
> +        ctx.set_source_surface(surface, 0, 0)
> +        ctx.paint()
> +
> +        if pause:
> +            ctx.set_source_rgba(0, 0, 0, 0.75)
> +            ctx.rectangle(0, 0, size, size)
> +            ctx.fill()
> +            ctx.set_source_rgba(.8, 0.8, 0.8, 0.5)
> +            size2 = size >> 1
> +            size4 = size2 >> 1
> +            size5 = size // 5
> +            ctx.rectangle(size4, size4, size5, size2)
> +            ctx.rectangle(size - size4 - size5, size4, size5, size2)
> +            ctx.fill()
> +
> +    def draw_metadata(ctx, metadata):
> +        ctx.set_source_rgb(0.9, 0.9, 0.9)
> +
> +        ctx.select_font_face(*Fonts.UBUNTU_NORMAL)
> +        ctx.set_font_size(24)
> +        ctx.move_to(112, 42)
> +        ctx.show_text(metadata["title"])
> +
> +        ctx.set_source_rgb(0.5, 0.5, 0.5)
> +        ctx.set_font_size(15)
> +        ctx.move_to(112, 72)
> +        ctx.show_text("{artists} ({album})".format(
> +            artists = ", ".join(metadata["artist"]),
> +            album = metadata["album"]
> +        ))
> +
> +    def on_draw(self, ctx):
> +        if self.spotify is None:
> +            self.init_dbus()
> +            return
> +
> +        try:
> +            metadata = self.spotify.get_metadata()
> +        except GLib.Error:
> +            self.spotify = None
> +            return
> +
> +        _ctx = ctx
> +        ctx.draw_background()
> +        ctx.draw_art(metadata["artUrl"], self.spotify.is_paused())
> +        ctx.draw_metadata(metadata)
> +        ctx.draw_decoration()
> +
> +
> +if __name__ == "__main__":
> +    config = configparser.ConfigParser()
> +    config.read('settings.ini')
> +    spotify = Spotify(
> +        x = eval(config.get('settings', 'margin_x')),
> +        y = eval(config.get('settings', 'margin_y')),

Same concerns about eval.

> +        width = 540,
> +        height = 96,
> +        gravity = eval('CanvasGravity.' + config.get('settings', 'gravity')),
> +        interval = 1000
> +    )
> +
> +    spotify.show()
> +    start_event_loop()
> diff --git a/uwidgets/official-widgets/unsplash-background/unsplash-background.py b/uwidgets/official-widgets/unsplash-background/unsplash-background.py
> new file mode 100755
> index 0000000..5fc2b52
> --- /dev/null
> +++ b/uwidgets/official-widgets/unsplash-background/unsplash-background.py
> @@ -0,0 +1,96 @@
> +#!/usr/bin/env python3
> +
> +"""
> +This file is part of "blighty" and "uwidgets" which is released under GPL.
> +
> +See file LICENCE or go to http://www.gnu.org/licenses/ for full license
> +details.
> +
> +uwidgets is a desktop widget creation and management library for Python 3.
> +
> +Copyright (c) 2022 Rudra Saraswat <rs2009 at ubuntu.com>.
> +Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987 at gmail.com>.
> +All rights reserved.
> +
> +This program is free software: you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation, either version 3 of the License, or
> +(at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +You should have received a copy of the GNU General Public License
> +along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +"""
> +
> +from uwidgets import CanvasGravity
> +from uwidgets.x11 import Canvas, start_event_loop
> +from uwidgets.settings import UnityWallpaper
> +
> +import cairo
> +import subprocess
> +import configparser
> +
> +from gi.repository import GLib
> +
> +
> +class Fonts(type):
> +    UBUNTU_NORMAL = "Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL
> +
> +
> +class UnBackground(Canvas):
> +    def on_button_pressed(self, button, state, x, y):
> +        if button == 1:    # Left button
> +            self.change_wallpaper()
> +        elif button == 3:  # Right button
> +            subprocess.run(['unity-control-center', 'appearance'])
> +
> +    def change_wallpaper(ctx):
> +        UnityWallpaper().set_wallpaper_from_url("https://source.unsplash.com/random/3840x2160")
> +
> +    def draw_background(ctx):
> +        size = ctx.canvas.get_size()
> +        ctx.rectangle(0, 0, *size)
> +        ctx.set_source_rgba(0, 0, 0, 0.6)
> +        ctx.fill()
> +
> +    def draw_decoration(ctx):
> +        ctx.rectangle(0, 0, ctx.canvas.width, 3)
> +        ctx.set_source_rgba(1, 1, 1, 1)
> +        ctx.fill()
> +
> +    def draw_info(ctx):
> +        ctx.set_source_rgb(0.9, 0.9, 0.9)
> +
> +        ctx.select_font_face(*Fonts.UBUNTU_NORMAL)
> +        ctx.set_font_size(24)
> +        ctx.move_to(20, 42)
> +        ctx.show_text('Unsplash | Random Background')
> +
> +        ctx.set_source_rgb(0.5, 0.5, 0.5)
> +        ctx.set_font_size(15)
> +        ctx.move_to(20, 64)
> +        ctx.show_text('Click this to set a random Unsplash background (requires internet).')
> +
> +    def on_draw(self, ctx):
> +        ctx.draw_background()
> +        ctx.draw_decoration()
> +        ctx.draw_info()
> +
> +
> +if __name__ == "__main__":
> +    config = configparser.ConfigParser()
> +    config.read('settings.ini')
> +    unbg = UnBackground(
> +        x = eval(config.get('settings', 'margin_x')),
> +        y = eval(config.get('settings', 'margin_y')),

Same concerns about eval.

> +        width = 540,
> +        height = 80,
> +        gravity = eval('CanvasGravity.' + config.get('settings', 'gravity')),
> +        interval = 1000
> +    )
> +
> +    unbg.show()
> +    start_event_loop()
> diff --git a/uwidgets/setup.py b/uwidgets/setup.py
> new file mode 100755
> index 0000000..34ca713
> --- /dev/null
> +++ b/uwidgets/setup.py
> @@ -0,0 +1,69 @@
> +#!/usr/bin/env python3
> +
> +"""
> +This file is part of "uwidgets" which is released under GPL.
> +
> +See file LICENCE or go to http://www.gnu.org/licenses/ for full license
> +details.
> +
> +uwidgets is a desktop widget creation and management library for Python 3.
> +
> +Copyright (c) 2022 Rudra Saraswat <rs2009 at ubuntu.com>.
> +Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987 at gmail.com>.
> +
> +This program is free software: you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation, either version 3 of the License, or
> +(at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +You should have received a copy of the GNU General Public License
> +along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +"""
> +
> +from setuptools import Extension, find_packages, setup
> +
> +x11 = Extension('uwidgets._x11',
> +    include_dirs       = ['/usr/include/cairo/'],
> +    libraries          = ['cairo', 'X11', 'Xinerama'],
> +    extra_compile_args = ['-std=c99'],
> +    sources            = [
> +        'uwidgets/x11/_x11module.c',
> +        'uwidgets/x11/atelier.c',
> +        'uwidgets/x11/base_canvas.c',
> +    ]
> +)
> +
> +
> +setup(
> +    name             = 'uwidgets',
> +    version          = '1.0.0',
> +    description      = 'Desktop Widget Manager for Unity, based on Blighty.',
> +    author           = 'Rudra Saraswat',
> +    author_email     = 'rs2009 at ubuntu.com',
> +    url              = 'https://unityd.org',
> +    classifiers=[
> +        'Development Status :: 1 - Production/Stable',

Production/Stable is 5, not 1.

> +
> +        'Intended Audience :: Developers',
> +        'Topic :: Software Development :: Build Tools',
> +
> +        'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
> +
> +        'Programming Language :: Python :: 3',
> +        'Programming Language :: Python :: 3.4',
> +        'Programming Language :: Python :: 3.5',
> +        'Programming Language :: Python :: 3.6',

These versions look to old, Ubuntu Lunar will have 3.11 (only).

> +    ],
> +    keywords         = 'desklet widget infotainment',
> +    packages         = find_packages(exclude=['contrib', 'docs']),
> +    ext_modules      = [x11],
> +    install_requires = ['pycairo'],
> +    scripts          = ['uwidgets-runner'],
> +    extras_require   = {
> +        'test': ['pytest-xvfb', 'numpy', 'matplotlib', 'psutil'],

Why do you need numpy and matplotlib here?

> +    },
> +)
> diff --git a/uwidgets/uwidgets-runner b/uwidgets/uwidgets-runner
> new file mode 100755
> index 0000000..3c5092f
> --- /dev/null
> +++ b/uwidgets/uwidgets-runner
> @@ -0,0 +1,19 @@
> +#!/usr/bin/env python3
> +
> +import os
> +import configparser
> +
> +widgets=[]
> +widgets_dir=os.path.expanduser('~/.local/share/unity/widgets')
> +
> +if os.path.exists(widgets_dir):
> +    for widget in [f.path for f in os.scandir(widgets_dir) if f.is_dir() and os.path.exists(os.path.join(f, 'widget.ini'))]:
> +        try:
> +            os.chdir(widget)
> +            config = configparser.ConfigParser()
> +            config.read(os.path.join(widget, 'widget.ini'))
> +            if config.get('widget', 'enabled') == 'true':
> +                os.popen(config.get('widget', 'exec'))
> +        except:

Bare except: is discouraged practice. Catch the exceptions you want to catch explicitly.

> +            print(f'uwidget-runner: error occurred when attempting to run {widget}')
> +
> diff --git a/uwidgets/uwidgets/__init__.py b/uwidgets/uwidgets/__init__.py
> new file mode 100644
> index 0000000..a310622
> --- /dev/null
> +++ b/uwidgets/uwidgets/__init__.py
> @@ -0,0 +1,77 @@
> +# This file is part of "blighty" and "uwidgets" which is released under GPL.
> +#
> +# See file LICENCE or go to http://www.gnu.org/licenses/ for full license
> +# details.
> +#
> +# uwidgets is a desktop widget creation and management library for Python 3.
> +#
> +# Copyright (c) 2018 Gabriele N. Tornetta <phoenix1987 at gmail.com>.
> +# All rights reserved.
> +#
> +# This program is free software: you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation, either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +"""
> +This module contains the common objects and types for the different kind of
> +canvases provided by ``uwidgets``.
> +"""
> +
> +# XWayland fix
> +import os
> +os.environ["GDK_BACKEND"] = "x11"
> +
> +from . _extended_context import ExtendedContext
> +
> +from . _brush import brush, TextAlign
> +
> +
> +class CanvasType(type):

The same type is declared in canvastype.py, why do we need to duplicate it in two places?

> +    """The Canvas type.
> +
> +    The canvas types enumerated in this Python type reflect the same window
> +    types that one can request to the window manager via the `Extended
> +    Window Manager Hints <https://standards.freedesktop.org/wm-spec/wm-spec-1.3.html>`_.
> +
> +    - ``NORMAL`` is a normal top-level window.
> +    - ``DESKTOP`` is a window drawn directly on the desktop.
> +    - ``DOCK`` indicates a dock or panel window that will usually stay on top
> +      of other windows.
> +    - ``UNDECORATED`` is a type of window that behaves as a toolbar. As such,
> +      it is undecorated.
> +    """
> +
> +    NORMAL = 0         # _NET_WM_WINDOW_TYPE_NORMAL
> +    DESKTOP = 1        # _NET_WM_WINDOW_TYPE_DESKTOP
> +    DOCK = 2           # _NET_WM_WINDOW_TYPE_DOCK
> +    UNDECORATED = 3    # _NET_WM_WINDOW_TYPE_TOOLBAR
> +
> +
> +class CanvasGravity(type):
> +    """Window gravity control type.
> +
> +    The positioning of a canvas on the screen is controlled by its gravity.
> +    By default, a window is positioned in a coordinate system where the origin
> +    is located in the top-left corner of the screen, with the *x* axis running
> +    horizontally from left to right, and the *y* from top to bottom. To change
> +    the location of the origin, use one of the following values.
> +    """
> +
> +    NORTH_WEST = 1
> +    NORTH = 2
> +    NORTH_EAST = 3
> +    WEST = 4
> +    CENTER = 5
> +    EAST = 6
> +    SOUTH_WEST = 7
> +    SOUTH = 8
> +    SOUTH_EAST = 9
> +    STATIC = 10
> diff --git a/uwidgets/uwidgets/canvastype.py b/uwidgets/uwidgets/canvastype.py
> new file mode 100644
> index 0000000..c5cd030
> --- /dev/null
> +++ b/uwidgets/uwidgets/canvastype.py
> @@ -0,0 +1,19 @@
> +class CanvasType(type):

Again no need to inherit from type, but you may want to inherit from enum.Enum:
https://docs.python.org/3/library/enum.html

> +    """The Canvas type.
> +
> +    The canvas types enumerated in this Python type reflect the same window
> +    types that one can request to the window manager via the `Extended
> +    Window Manager Hints <https://standards.freedesktop.org/wm-spec/wm-spec-1.3.html>`_.
> +
> +    - ``NORMAL`` is a normal top-level window.
> +    - ``DESKTOP`` is a window drawn directly on the desktop.
> +    - ``DOCK`` indicates a dock or panel window that will usually stay on top
> +      of other windows.
> +    - ``UNDECORATED`` is a type of window that behaves as a toolbar. As such,
> +      it is undecorated.
> +    """
> +
> +    NORMAL = 0         # _NET_WM_WINDOW_TYPE_NORMAL
> +    DESKTOP = 1        # _NET_WM_WINDOW_TYPE_DESKTOP
> +    DOCK = 2           # _NET_WM_WINDOW_TYPE_DOCK
> +    UNDECORATED = 3    # _NET_WM_WINDOW_TYPE_TOOLBAR
> \ No newline at end of file


-- 
https://code.launchpad.net/~rs2009/unity/+git/unity/+merge/437213
Your team Unity Team is subscribed to branch unity:master.




More information about the Ubuntu-reviews mailing list