We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Incorrect packaging of the `/etc` directory
**Information**
<!-- Do not bother opening an issue for version 0.9.2 or older, it is extremely outdated. Please update to the latest one and see if your issue persists. -->
- Solaar version (`git describe --tags` if cloned from Solaar repository): `master`

**Describe the bug**
A Solaar wheel contains the following.
```tree
.install-cache/pkg/
├── etc
│   ├── udev
│   │   └── rules.d
│   │       └── 42-logitech-unify-permissions.rules
│   └── xdg
│       └── autostart
│           └── solaar.desktop
├── hidapi
│   ├── hidconsole.py
│   ├── __init__.py
│   └── udev.py
├── logitech_receiver
│   ├── base.py
│   ├── base_usb.py
│   ├── common.py
│   ├── descriptors.py
│   ├── hidpp10.py
│   ├── hidpp20.py
│   ├── i18n.py
│   ├── __init__.py
│   ├── listener.py
│   ├── notifications.py
│   ├── receiver.py
│   ├── settings.py
│   ├── settings_templates.py
│   ├── special_keys.py
│   └── status.py
├── solaar
│   ├── cli
│   │   ├── config.py
│   │   ├── __init__.py
│   │   ├── pair.py
│   │   ├── probe.py
│   │   ├── show.py
│   │   └── unpair.py
│   ├── configuration.py
│   ├── gtk.py
│   ├── i18n.py
│   ├── __init__.py
│   ├── listener.py
│   ├── tasks.py
│   ├── ui
│   │   ├── about.py
│   │   ├── action.py
│   │   ├── config_panel.py
│   │   ├── icons.py
│   │   ├── __init__.py
│   │   ├── notify.py
│   │   ├── pair_window.py
│   │   ├── tray.py
│   │   └── window.py
│   └── upower.py
├── solaar-1.0.2.data
│   ├── data
│   │   └── share
│   │       ├── applications
│   │       │   └── solaar.desktop
│   │       ├── icons
│   │       │   └── hicolor
│   │       │       └── scalable
│   │       │           └── apps
│   │       │               └── solaar.svg
│   │       └── solaar
│   │           └── icons
│   │               ├── light_000.png
│   │               ├── light_020.png
│   │               ├── light_040.png
│   │               ├── light_060.png
│   │               ├── light_080.png
│   │               ├── light_100.png
│   │               ├── light_unknown.png
│   │               ├── solaar-attention.svg
│   │               ├── solaar-init.svg
│   │               └── solaar.svg
│   └── scripts
│       ├── solaar
│       └── solaar-cli
└── solaar-1.0.2.dist-info
    ├── COPYING
    ├── METADATA
    ├── RECORD
    ├── top_level.txt
    └── WHEEL

22 directories, 61 files
```

`/etc` is wrongfully present at the top level, it shouldn't be there. Using a correct (follows the spec) installer, it would result in the file being installed to the python modules directory. Unfortunately, [PEP427](https://www.python.org/dev/peps/pep-0427/) does not specify any way of installing to `sysconfdir`, we should put it under `data` and copy it at runtime if not present.

Another thing, I don't think we should be shipping `hidapi` and `logitech_receiver` as top-level modules.

**To Reproduce**
Steps to reproduce the behavior:
`python setup.py bdist_wheel`


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/solaar/gtk.py`
Content:
```
1 #!/usr/bin/env python3
2 # -*- python-mode -*-
3 # -*- coding: UTF-8 -*-
4 
5 ## Copyright (C) 2012-2013  Daniel Pavel
6 ##
7 ## This program is free software; you can redistribute it and/or modify
8 ## it under the terms of the GNU General Public License as published by
9 ## the Free Software Foundation; either version 2 of the License, or
10 ## (at your option) any later version.
11 ##
12 ## This program is distributed in the hope that it will be useful,
13 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ## GNU General Public License for more details.
16 ##
17 ## You should have received a copy of the GNU General Public License along
18 ## with this program; if not, write to the Free Software Foundation, Inc.,
19 ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 
21 from __future__ import absolute_import, division, print_function, unicode_literals
22 
23 import importlib
24 
25 from logging import INFO as _INFO
26 from logging import getLogger
27 
28 import solaar.cli as _cli
29 import solaar.i18n as _i18n
30 
31 from solaar import NAME, __version__
32 
33 _log = getLogger(__name__)
34 del getLogger
35 
36 #
37 #
38 #
39 
40 
41 def _require(module, os_package, gi=None, gi_package=None, gi_version=None):
42     try:
43         if gi is not None:
44             gi.require_version(gi_package, gi_version)
45         return importlib.import_module(module)
46     except (ImportError, ValueError):
47         import sys
48         sys.exit('%s: missing required system package %s' % (NAME, os_package))
49 
50 
51 prefer_symbolic_battery_icons = False
52 
53 
54 def _parse_arguments():
55     import argparse
56     arg_parser = argparse.ArgumentParser(prog=NAME.lower())
57     arg_parser.add_argument(
58         '-d',
59         '--debug',
60         action='count',
61         default=0,
62         help='print logging messages, for debugging purposes (may be repeated for extra verbosity)'
63     )
64     arg_parser.add_argument(
65         '-D',
66         '--hidraw',
67         action='store',
68         dest='hidraw_path',
69         metavar='PATH',
70         help='unifying receiver to use; the first detected receiver if unspecified. Example: /dev/hidraw2'
71     )
72     arg_parser.add_argument('--restart-on-wake-up', action='store_true', help='restart Solaar on sleep wake-up (experimental)')
73     arg_parser.add_argument(
74         '-w', '--window', choices=('show', 'hide', 'only'), help='start with window showing / hidden / only (no tray icon)'
75     )
76     arg_parser.add_argument('-b', '--battery-icons', choices=('regular', 'symbolic'), help='prefer regular / symbolic icons')
77     arg_parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__)
78     arg_parser.add_argument('--help-actions', action='store_true', help='print help for the optional actions')
79     arg_parser.add_argument('action', nargs=argparse.REMAINDER, choices=_cli.actions, help='optional actions to perform')
80 
81     args = arg_parser.parse_args()
82 
83     if args.help_actions:
84         _cli.print_help()
85         return
86 
87     if args.window is None:
88         args.window = 'show'  # default behaviour is to show main window
89 
90     global prefer_symbolic_battery_icons
91     prefer_symbolic_battery_icons = True if args.battery_icons == 'symbolic' else False
92 
93     import logging
94     if args.debug > 0:
95         log_level = logging.WARNING - 10 * args.debug
96         log_format = '%(asctime)s,%(msecs)03d %(levelname)8s [%(threadName)s] %(name)s: %(message)s'
97         logging.basicConfig(level=max(log_level, logging.DEBUG), format=log_format, datefmt='%H:%M:%S')
98     else:
99         logging.root.addHandler(logging.NullHandler())
100         logging.root.setLevel(logging.ERROR)
101 
102     if not args.action:
103         if logging.root.isEnabledFor(logging.INFO):
104             logging.info('language %s (%s), translations path %s', _i18n.language, _i18n.encoding, _i18n.path)
105 
106     return args
107 
108 
109 # On first SIGINT, dump threads to stderr; on second, exit
110 def _handlesigint(signal, stack):
111     import signal
112     import sys
113     import faulthandler
114     signal.signal(signal.SIGINT, signal.SIG_DFL)
115 
116     if _log.isEnabledFor(_INFO):
117         faulthandler.dump_traceback()
118 
119     sys.exit('%s: exit due to keyboard interrupt' % (NAME.lower()))
120 
121 
122 def main():
123     _require('pyudev', 'python3-pyudev')
124 
125     # handle ^C in console
126     import signal
127     signal.signal(signal.SIGINT, signal.SIG_DFL)
128     signal.signal(signal.SIGINT, _handlesigint)
129 
130     args = _parse_arguments()
131     if not args:
132         return
133     if args.action:
134         # if any argument, run comandline and exit
135         return _cli.run(args.action, args.hidraw_path)
136 
137     gi = _require('gi', 'python3-gi or python3-gobject')
138     _require('gi.repository.Gtk', 'gir1.2-gtk-3.0', gi, 'Gtk', '3.0')
139 
140     try:
141         import solaar.ui as ui
142         import solaar.listener as listener
143         listener.setup_scanner(ui.status_changed, ui.error_dialog)
144 
145         import solaar.upower as _upower
146         if args.restart_on_wake_up:
147             _upower.watch(listener.start_all, listener.stop_all)
148         else:
149             _upower.watch(lambda: listener.ping_all(True))
150 
151         # main UI event loop
152         ui.run_loop(listener.start_all, listener.stop_all, args.window != 'only', args.window != 'hide')
153     except Exception:
154         import sys
155         from traceback import format_exc
156         sys.exit('%s: error: %s' % (NAME.lower(), format_exc()))
157 
158 
159 if __name__ == '__main__':
160     main()
161
```

Path: `lib/solaar/__init__.py`
Content:
```
1 # -*- python-mode -*-
2 # -*- coding: UTF-8 -*-
3 
4 ## Copyright (C) 2012-2013  Daniel Pavel
5 ##
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
10 ##
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ## GNU General Public License for more details.
15 ##
16 ## You should have received a copy of the GNU General Public License along
17 ## with this program; if not, write to the Free Software Foundation, Inc.,
18 ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20 from __future__ import absolute_import, division, print_function, unicode_literals
21 
22 __version__ = '1.0.2'
23 NAME = 'Solaar'
24
```

Path: `setup.py`
Content:
```
1 #!/usr/bin/env python3
2 
3 from glob import glob as _glob
4 
5 try:
6     from setuptools import setup
7 except ImportError:
8     from distutils.core import setup
9 
10 autostart_path = '/etc/xdg/autostart'
11 
12 # from solaar import NAME, __version__
13 __version__ = '1.0.2'
14 NAME = 'Solaar'
15 
16 
17 def _data_files():
18     from os.path import dirname as _dirname
19 
20     yield 'share/solaar/icons', _glob('share/solaar/icons/solaar*.svg')
21     yield 'share/solaar/icons', _glob('share/solaar/icons/light_*.png')
22     yield 'share/icons/hicolor/scalable/apps', ['share/solaar/icons/solaar.svg']
23 
24     for mo in _glob('share/locale/*/LC_MESSAGES/solaar.mo'):
25         yield _dirname(mo), [mo]
26 
27     yield 'share/applications', ['share/applications/solaar.desktop']
28     yield autostart_path, ['share/autostart/solaar.desktop']
29     yield '/etc/udev/rules.d', ['rules.d/42-logitech-unify-permissions.rules']
30 
31     del _dirname
32 
33 
34 setup(
35     name=NAME.lower(),
36     version=__version__,
37     description='Linux devices manager for the Logitech Unifying Receiver.',
38     long_description='''
39 Solaar is a Linux device manager for Logitech's Unifying Receiver peripherals.
40 It is able to pair/unpair devices with the receiver, for many devices show
41 battery status, and show and modify some of the modifiable features of devices.
42 '''.strip(),
43     author='Daniel Pavel',
44     license='GPLv2',
45     url='http://pwr-solaar.github.io/Solaar/',
46     classifiers=[
47         'Development Status :: 4 - Beta',
48         'Environment :: X11 Applications :: GTK',
49         'Environment :: Console',
50         'Intended Audience :: End Users/Desktop',
51         'License :: DFSG approved',
52         'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
53         'Natural Language :: English',
54         'Programming Language :: Python :: 3 :: Only',
55         'Operating System :: POSIX :: Linux',
56         'Topic :: Utilities',
57     ],
58     platforms=['linux'],
59 
60     # sudo apt install python-gi python3-gi \
61     #        gir1.2-gtk-3.0 gir1.2-notify-0.7 gir1.2-ayatanaappindicator3-0.1
62     # os_requires=['gi.repository.GObject (>= 2.0)', 'gi.repository.Gtk (>= 3.0)'],
63     python_requires='>=3.5',
64     install_requires=[
65         'pyudev (>= 0.13)',
66     ],
67     package_dir={'': 'lib'},
68     packages=['hidapi', 'logitech_receiver', 'solaar', 'solaar.ui', 'solaar.cli'],
69     data_files=list(_data_files()),
70     scripts=_glob('bin/*'),
71 )
72
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lib/solaar/__init__.py b/lib/solaar/__init__.py
--- a/lib/solaar/__init__.py
+++ b/lib/solaar/__init__.py
@@ -19,5 +19,5 @@
 
 from __future__ import absolute_import, division, print_function, unicode_literals
 
-__version__ = '1.0.2'
+__version__ = '1.0.3rc1'
 NAME = 'Solaar'
diff --git a/lib/solaar/gtk.py b/lib/solaar/gtk.py
--- a/lib/solaar/gtk.py
+++ b/lib/solaar/gtk.py
@@ -21,6 +21,7 @@
 from __future__ import absolute_import, division, print_function, unicode_literals
 
 import importlib
+import os.path
 
 from logging import INFO as _INFO
 from logging import getLogger
@@ -137,6 +138,16 @@
     gi = _require('gi', 'python3-gi or python3-gobject')
     _require('gi.repository.Gtk', 'gir1.2-gtk-3.0', gi, 'Gtk', '3.0')
 
+    udev_file = '42-logitech-unify-permissions.rules'
+    if not os.path.isfile('/etc/udev/rules.d/' + udev_file) and not os.path.isfile('/lib/udev/rules.d/' + udev_file):
+        print(_i18n._('Solaar depends on a udev file that is not present'))
+        print(
+            _i18n._(
+                'For more information see the Solaar installation directions\n'
+                'at https://pwr-solaar.github.io/Solaar/installation'
+            )
+        )
+
     try:
         import solaar.ui as ui
         import solaar.listener as listener
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -7,10 +7,8 @@
 except ImportError:
     from distutils.core import setup
 
-autostart_path = '/etc/xdg/autostart'
-
 # from solaar import NAME, __version__
-__version__ = '1.0.2'
+__version__ = '1.0.3rc1'
 NAME = 'Solaar'
 
 
@@ -25,8 +23,7 @@
         yield _dirname(mo), [mo]
 
     yield 'share/applications', ['share/applications/solaar.desktop']
-    yield autostart_path, ['share/autostart/solaar.desktop']
-    yield '/etc/udev/rules.d', ['rules.d/42-logitech-unify-permissions.rules']
+    yield 'share/solaar/udev-rules.d', ['rules.d/42-logitech-unify-permissions.rules']
 
     del _dirname
 
@@ -60,7 +57,7 @@
     # sudo apt install python-gi python3-gi \
     #        gir1.2-gtk-3.0 gir1.2-notify-0.7 gir1.2-ayatanaappindicator3-0.1
     # os_requires=['gi.repository.GObject (>= 2.0)', 'gi.repository.Gtk (>= 3.0)'],
-    python_requires='>=3.5',
+    python_requires='>=3.6',
     install_requires=[
         'pyudev (>= 0.13)',
     ],

{"golden_diff": "diff --git a/lib/solaar/__init__.py b/lib/solaar/__init__.py\n--- a/lib/solaar/__init__.py\n+++ b/lib/solaar/__init__.py\n@@ -19,5 +19,5 @@\n \n from __future__ import absolute_import, division, print_function, unicode_literals\n \n-__version__ = '1.0.2'\n+__version__ = '1.0.3rc1'\n NAME = 'Solaar'\ndiff --git a/lib/solaar/gtk.py b/lib/solaar/gtk.py\n--- a/lib/solaar/gtk.py\n+++ b/lib/solaar/gtk.py\n@@ -21,6 +21,7 @@\n from __future__ import absolute_import, division, print_function, unicode_literals\n \n import importlib\n+import os.path\n \n from logging import INFO as _INFO\n from logging import getLogger\n@@ -137,6 +138,16 @@\n     gi = _require('gi', 'python3-gi or python3-gobject')\n     _require('gi.repository.Gtk', 'gir1.2-gtk-3.0', gi, 'Gtk', '3.0')\n \n+    udev_file = '42-logitech-unify-permissions.rules'\n+    if not os.path.isfile('/etc/udev/rules.d/' + udev_file) and not os.path.isfile('/lib/udev/rules.d/' + udev_file):\n+        print(_i18n._('Solaar depends on a udev file that is not present'))\n+        print(\n+            _i18n._(\n+                'For more information see the Solaar installation directions\\n'\n+                'at https://pwr-solaar.github.io/Solaar/installation'\n+            )\n+        )\n+\n     try:\n         import solaar.ui as ui\n         import solaar.listener as listener\ndiff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -7,10 +7,8 @@\n except ImportError:\n     from distutils.core import setup\n \n-autostart_path = '/etc/xdg/autostart'\n-\n # from solaar import NAME, __version__\n-__version__ = '1.0.2'\n+__version__ = '1.0.3rc1'\n NAME = 'Solaar'\n \n \n@@ -25,8 +23,7 @@\n         yield _dirname(mo), [mo]\n \n     yield 'share/applications', ['share/applications/solaar.desktop']\n-    yield autostart_path, ['share/autostart/solaar.desktop']\n-    yield '/etc/udev/rules.d', ['rules.d/42-logitech-unify-permissions.rules']\n+    yield 'share/solaar/udev-rules.d', ['rules.d/42-logitech-unify-permissions.rules']\n \n     del _dirname\n \n@@ -60,7 +57,7 @@\n     # sudo apt install python-gi python3-gi \\\n     #        gir1.2-gtk-3.0 gir1.2-notify-0.7 gir1.2-ayatanaappindicator3-0.1\n     # os_requires=['gi.repository.GObject (>= 2.0)', 'gi.repository.Gtk (>= 3.0)'],\n-    python_requires='>=3.5',\n+    python_requires='>=3.6',\n     install_requires=[\n         'pyudev (>= 0.13)',\n     ],\n", "issue": "Incorrect packaging of the `/etc` directory\n**Information**\r\n<!-- Do not bother opening an issue for version 0.9.2 or older, it is extremely outdated. Please update to the latest one and see if your issue persists. -->\r\n- Solaar version (`git describe --tags` if cloned from Solaar repository): `master`\r\n\r\n**Describe the bug**\r\nA Solaar wheel contains the following.\r\n```tree\r\n.install-cache/pkg/\r\n\u251c\u2500\u2500 etc\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 udev\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 rules.d\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u2514\u2500\u2500 42-logitech-unify-permissions.rules\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 xdg\r\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 autostart\r\n\u2502\u00a0\u00a0         \u2514\u2500\u2500 solaar.desktop\r\n\u251c\u2500\u2500 hidapi\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 hidconsole.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 udev.py\r\n\u251c\u2500\u2500 logitech_receiver\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 base.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 base_usb.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 common.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 descriptors.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 hidpp10.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 hidpp20.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 i18n.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 listener.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 notifications.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 receiver.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 settings.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 settings_templates.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 special_keys.py\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 status.py\r\n\u251c\u2500\u2500 solaar\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 cli\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 config.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 pair.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 probe.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 show.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 unpair.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 configuration.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 gtk.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 i18n.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 listener.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 tasks.py\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 ui\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 about.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 action.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 config_panel.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 icons.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 notify.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 pair_window.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 tray.py\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 window.py\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 upower.py\r\n\u251c\u2500\u2500 solaar-1.0.2.data\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 data\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 share\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u251c\u2500\u2500 applications\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u2502\u00a0\u00a0 \u2514\u2500\u2500 solaar.desktop\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u251c\u2500\u2500 icons\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u2502\u00a0\u00a0 \u2514\u2500\u2500 hicolor\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u2502\u00a0\u00a0     \u2514\u2500\u2500 scalable\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u2502\u00a0\u00a0         \u2514\u2500\u2500 apps\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u2502\u00a0\u00a0             \u2514\u2500\u2500 solaar.svg\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u2514\u2500\u2500 solaar\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0         \u2514\u2500\u2500 icons\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u251c\u2500\u2500 light_000.png\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u251c\u2500\u2500 light_020.png\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u251c\u2500\u2500 light_040.png\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u251c\u2500\u2500 light_060.png\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u251c\u2500\u2500 light_080.png\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u251c\u2500\u2500 light_100.png\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u251c\u2500\u2500 light_unknown.png\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u251c\u2500\u2500 solaar-attention.svg\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u251c\u2500\u2500 solaar-init.svg\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0             \u2514\u2500\u2500 solaar.svg\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 scripts\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 solaar\r\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 solaar-cli\r\n\u2514\u2500\u2500 solaar-1.0.2.dist-info\r\n    \u251c\u2500\u2500 COPYING\r\n    \u251c\u2500\u2500 METADATA\r\n    \u251c\u2500\u2500 RECORD\r\n    \u251c\u2500\u2500 top_level.txt\r\n    \u2514\u2500\u2500 WHEEL\r\n\r\n22 directories, 61 files\r\n```\r\n\r\n`/etc` is wrongfully present at the top level, it shouldn't be there. Using a correct (follows the spec) installer, it would result in the file being installed to the python modules directory. Unfortunately, [PEP427](https://www.python.org/dev/peps/pep-0427/) does not specify any way of installing to `sysconfdir`, we should put it under `data` and copy it at runtime if not present.\r\n\r\nAnother thing, I don't think we should be shipping `hidapi` and `logitech_receiver` as top-level modules.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n`python setup.py bdist_wheel`\r\n\n", "before_files": [{"content": "#!/usr/bin/env python3\n# -*- python-mode -*-\n# -*- coding: UTF-8 -*-\n\n## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport importlib\n\nfrom logging import INFO as _INFO\nfrom logging import getLogger\n\nimport solaar.cli as _cli\nimport solaar.i18n as _i18n\n\nfrom solaar import NAME, __version__\n\n_log = getLogger(__name__)\ndel getLogger\n\n#\n#\n#\n\n\ndef _require(module, os_package, gi=None, gi_package=None, gi_version=None):\n    try:\n        if gi is not None:\n            gi.require_version(gi_package, gi_version)\n        return importlib.import_module(module)\n    except (ImportError, ValueError):\n        import sys\n        sys.exit('%s: missing required system package %s' % (NAME, os_package))\n\n\nprefer_symbolic_battery_icons = False\n\n\ndef _parse_arguments():\n    import argparse\n    arg_parser = argparse.ArgumentParser(prog=NAME.lower())\n    arg_parser.add_argument(\n        '-d',\n        '--debug',\n        action='count',\n        default=0,\n        help='print logging messages, for debugging purposes (may be repeated for extra verbosity)'\n    )\n    arg_parser.add_argument(\n        '-D',\n        '--hidraw',\n        action='store',\n        dest='hidraw_path',\n        metavar='PATH',\n        help='unifying receiver to use; the first detected receiver if unspecified. Example: /dev/hidraw2'\n    )\n    arg_parser.add_argument('--restart-on-wake-up', action='store_true', help='restart Solaar on sleep wake-up (experimental)')\n    arg_parser.add_argument(\n        '-w', '--window', choices=('show', 'hide', 'only'), help='start with window showing / hidden / only (no tray icon)'\n    )\n    arg_parser.add_argument('-b', '--battery-icons', choices=('regular', 'symbolic'), help='prefer regular / symbolic icons')\n    arg_parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__)\n    arg_parser.add_argument('--help-actions', action='store_true', help='print help for the optional actions')\n    arg_parser.add_argument('action', nargs=argparse.REMAINDER, choices=_cli.actions, help='optional actions to perform')\n\n    args = arg_parser.parse_args()\n\n    if args.help_actions:\n        _cli.print_help()\n        return\n\n    if args.window is None:\n        args.window = 'show'  # default behaviour is to show main window\n\n    global prefer_symbolic_battery_icons\n    prefer_symbolic_battery_icons = True if args.battery_icons == 'symbolic' else False\n\n    import logging\n    if args.debug > 0:\n        log_level = logging.WARNING - 10 * args.debug\n        log_format = '%(asctime)s,%(msecs)03d %(levelname)8s [%(threadName)s] %(name)s: %(message)s'\n        logging.basicConfig(level=max(log_level, logging.DEBUG), format=log_format, datefmt='%H:%M:%S')\n    else:\n        logging.root.addHandler(logging.NullHandler())\n        logging.root.setLevel(logging.ERROR)\n\n    if not args.action:\n        if logging.root.isEnabledFor(logging.INFO):\n            logging.info('language %s (%s), translations path %s', _i18n.language, _i18n.encoding, _i18n.path)\n\n    return args\n\n\n# On first SIGINT, dump threads to stderr; on second, exit\ndef _handlesigint(signal, stack):\n    import signal\n    import sys\n    import faulthandler\n    signal.signal(signal.SIGINT, signal.SIG_DFL)\n\n    if _log.isEnabledFor(_INFO):\n        faulthandler.dump_traceback()\n\n    sys.exit('%s: exit due to keyboard interrupt' % (NAME.lower()))\n\n\ndef main():\n    _require('pyudev', 'python3-pyudev')\n\n    # handle ^C in console\n    import signal\n    signal.signal(signal.SIGINT, signal.SIG_DFL)\n    signal.signal(signal.SIGINT, _handlesigint)\n\n    args = _parse_arguments()\n    if not args:\n        return\n    if args.action:\n        # if any argument, run comandline and exit\n        return _cli.run(args.action, args.hidraw_path)\n\n    gi = _require('gi', 'python3-gi or python3-gobject')\n    _require('gi.repository.Gtk', 'gir1.2-gtk-3.0', gi, 'Gtk', '3.0')\n\n    try:\n        import solaar.ui as ui\n        import solaar.listener as listener\n        listener.setup_scanner(ui.status_changed, ui.error_dialog)\n\n        import solaar.upower as _upower\n        if args.restart_on_wake_up:\n            _upower.watch(listener.start_all, listener.stop_all)\n        else:\n            _upower.watch(lambda: listener.ping_all(True))\n\n        # main UI event loop\n        ui.run_loop(listener.start_all, listener.stop_all, args.window != 'only', args.window != 'hide')\n    except Exception:\n        import sys\n        from traceback import format_exc\n        sys.exit('%s: error: %s' % (NAME.lower(), format_exc()))\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/solaar/gtk.py"}, {"content": "# -*- python-mode -*-\n# -*- coding: UTF-8 -*-\n\n## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\n__version__ = '1.0.2'\nNAME = 'Solaar'\n", "path": "lib/solaar/__init__.py"}, {"content": "#!/usr/bin/env python3\n\nfrom glob import glob as _glob\n\ntry:\n    from setuptools import setup\nexcept ImportError:\n    from distutils.core import setup\n\nautostart_path = '/etc/xdg/autostart'\n\n# from solaar import NAME, __version__\n__version__ = '1.0.2'\nNAME = 'Solaar'\n\n\ndef _data_files():\n    from os.path import dirname as _dirname\n\n    yield 'share/solaar/icons', _glob('share/solaar/icons/solaar*.svg')\n    yield 'share/solaar/icons', _glob('share/solaar/icons/light_*.png')\n    yield 'share/icons/hicolor/scalable/apps', ['share/solaar/icons/solaar.svg']\n\n    for mo in _glob('share/locale/*/LC_MESSAGES/solaar.mo'):\n        yield _dirname(mo), [mo]\n\n    yield 'share/applications', ['share/applications/solaar.desktop']\n    yield autostart_path, ['share/autostart/solaar.desktop']\n    yield '/etc/udev/rules.d', ['rules.d/42-logitech-unify-permissions.rules']\n\n    del _dirname\n\n\nsetup(\n    name=NAME.lower(),\n    version=__version__,\n    description='Linux devices manager for the Logitech Unifying Receiver.',\n    long_description='''\nSolaar is a Linux device manager for Logitech's Unifying Receiver peripherals.\nIt is able to pair/unpair devices with the receiver, for many devices show\nbattery status, and show and modify some of the modifiable features of devices.\n'''.strip(),\n    author='Daniel Pavel',\n    license='GPLv2',\n    url='http://pwr-solaar.github.io/Solaar/',\n    classifiers=[\n        'Development Status :: 4 - Beta',\n        'Environment :: X11 Applications :: GTK',\n        'Environment :: Console',\n        'Intended Audience :: End Users/Desktop',\n        'License :: DFSG approved',\n        'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',\n        'Natural Language :: English',\n        'Programming Language :: Python :: 3 :: Only',\n        'Operating System :: POSIX :: Linux',\n        'Topic :: Utilities',\n    ],\n    platforms=['linux'],\n\n    # sudo apt install python-gi python3-gi \\\n    #        gir1.2-gtk-3.0 gir1.2-notify-0.7 gir1.2-ayatanaappindicator3-0.1\n    # os_requires=['gi.repository.GObject (>= 2.0)', 'gi.repository.Gtk (>= 3.0)'],\n    python_requires='>=3.5',\n    install_requires=[\n        'pyudev (>= 0.13)',\n    ],\n    package_dir={'': 'lib'},\n    packages=['hidapi', 'logitech_receiver', 'solaar', 'solaar.ui', 'solaar.cli'],\n    data_files=list(_data_files()),\n    scripts=_glob('bin/*'),\n)\n", "path": "setup.py"}], "after_files": [{"content": "#!/usr/bin/env python3\n# -*- python-mode -*-\n# -*- coding: UTF-8 -*-\n\n## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport importlib\nimport os.path\n\nfrom logging import INFO as _INFO\nfrom logging import getLogger\n\nimport solaar.cli as _cli\nimport solaar.i18n as _i18n\n\nfrom solaar import NAME, __version__\n\n_log = getLogger(__name__)\ndel getLogger\n\n#\n#\n#\n\n\ndef _require(module, os_package, gi=None, gi_package=None, gi_version=None):\n    try:\n        if gi is not None:\n            gi.require_version(gi_package, gi_version)\n        return importlib.import_module(module)\n    except (ImportError, ValueError):\n        import sys\n        sys.exit('%s: missing required system package %s' % (NAME, os_package))\n\n\nprefer_symbolic_battery_icons = False\n\n\ndef _parse_arguments():\n    import argparse\n    arg_parser = argparse.ArgumentParser(prog=NAME.lower())\n    arg_parser.add_argument(\n        '-d',\n        '--debug',\n        action='count',\n        default=0,\n        help='print logging messages, for debugging purposes (may be repeated for extra verbosity)'\n    )\n    arg_parser.add_argument(\n        '-D',\n        '--hidraw',\n        action='store',\n        dest='hidraw_path',\n        metavar='PATH',\n        help='unifying receiver to use; the first detected receiver if unspecified. Example: /dev/hidraw2'\n    )\n    arg_parser.add_argument('--restart-on-wake-up', action='store_true', help='restart Solaar on sleep wake-up (experimental)')\n    arg_parser.add_argument(\n        '-w', '--window', choices=('show', 'hide', 'only'), help='start with window showing / hidden / only (no tray icon)'\n    )\n    arg_parser.add_argument('-b', '--battery-icons', choices=('regular', 'symbolic'), help='prefer regular / symbolic icons')\n    arg_parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__)\n    arg_parser.add_argument('--help-actions', action='store_true', help='print help for the optional actions')\n    arg_parser.add_argument('action', nargs=argparse.REMAINDER, choices=_cli.actions, help='optional actions to perform')\n\n    args = arg_parser.parse_args()\n\n    if args.help_actions:\n        _cli.print_help()\n        return\n\n    if args.window is None:\n        args.window = 'show'  # default behaviour is to show main window\n\n    global prefer_symbolic_battery_icons\n    prefer_symbolic_battery_icons = True if args.battery_icons == 'symbolic' else False\n\n    import logging\n    if args.debug > 0:\n        log_level = logging.WARNING - 10 * args.debug\n        log_format = '%(asctime)s,%(msecs)03d %(levelname)8s [%(threadName)s] %(name)s: %(message)s'\n        logging.basicConfig(level=max(log_level, logging.DEBUG), format=log_format, datefmt='%H:%M:%S')\n    else:\n        logging.root.addHandler(logging.NullHandler())\n        logging.root.setLevel(logging.ERROR)\n\n    if not args.action:\n        if logging.root.isEnabledFor(logging.INFO):\n            logging.info('language %s (%s), translations path %s', _i18n.language, _i18n.encoding, _i18n.path)\n\n    return args\n\n\n# On first SIGINT, dump threads to stderr; on second, exit\ndef _handlesigint(signal, stack):\n    import signal\n    import sys\n    import faulthandler\n    signal.signal(signal.SIGINT, signal.SIG_DFL)\n\n    if _log.isEnabledFor(_INFO):\n        faulthandler.dump_traceback()\n\n    sys.exit('%s: exit due to keyboard interrupt' % (NAME.lower()))\n\n\ndef main():\n    _require('pyudev', 'python3-pyudev')\n\n    # handle ^C in console\n    import signal\n    signal.signal(signal.SIGINT, signal.SIG_DFL)\n    signal.signal(signal.SIGINT, _handlesigint)\n\n    args = _parse_arguments()\n    if not args:\n        return\n    if args.action:\n        # if any argument, run comandline and exit\n        return _cli.run(args.action, args.hidraw_path)\n\n    gi = _require('gi', 'python3-gi or python3-gobject')\n    _require('gi.repository.Gtk', 'gir1.2-gtk-3.0', gi, 'Gtk', '3.0')\n\n    udev_file = '42-logitech-unify-permissions.rules'\n    if not os.path.isfile('/etc/udev/rules.d/' + udev_file) and not os.path.isfile('/lib/udev/rules.d/' + udev_file):\n        print(_i18n._('Solaar depends on a udev file that is not present'))\n        print(\n            _i18n._(\n                'For more information see the Solaar installation directions\\n'\n                'at https://pwr-solaar.github.io/Solaar/installation'\n            )\n        )\n\n    try:\n        import solaar.ui as ui\n        import solaar.listener as listener\n        listener.setup_scanner(ui.status_changed, ui.error_dialog)\n\n        import solaar.upower as _upower\n        if args.restart_on_wake_up:\n            _upower.watch(listener.start_all, listener.stop_all)\n        else:\n            _upower.watch(lambda: listener.ping_all(True))\n\n        # main UI event loop\n        ui.run_loop(listener.start_all, listener.stop_all, args.window != 'only', args.window != 'hide')\n    except Exception:\n        import sys\n        from traceback import format_exc\n        sys.exit('%s: error: %s' % (NAME.lower(), format_exc()))\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/solaar/gtk.py"}, {"content": "# -*- python-mode -*-\n# -*- coding: UTF-8 -*-\n\n## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\n__version__ = '1.0.3rc1'\nNAME = 'Solaar'\n", "path": "lib/solaar/__init__.py"}, {"content": "#!/usr/bin/env python3\n\nfrom glob import glob as _glob\n\ntry:\n    from setuptools import setup\nexcept ImportError:\n    from distutils.core import setup\n\n# from solaar import NAME, __version__\n__version__ = '1.0.3rc1'\nNAME = 'Solaar'\n\n\ndef _data_files():\n    from os.path import dirname as _dirname\n\n    yield 'share/solaar/icons', _glob('share/solaar/icons/solaar*.svg')\n    yield 'share/solaar/icons', _glob('share/solaar/icons/light_*.png')\n    yield 'share/icons/hicolor/scalable/apps', ['share/solaar/icons/solaar.svg']\n\n    for mo in _glob('share/locale/*/LC_MESSAGES/solaar.mo'):\n        yield _dirname(mo), [mo]\n\n    yield 'share/applications', ['share/applications/solaar.desktop']\n    yield 'share/solaar/udev-rules.d', ['rules.d/42-logitech-unify-permissions.rules']\n\n    del _dirname\n\n\nsetup(\n    name=NAME.lower(),\n    version=__version__,\n    description='Linux devices manager for the Logitech Unifying Receiver.',\n    long_description='''\nSolaar is a Linux device manager for Logitech's Unifying Receiver peripherals.\nIt is able to pair/unpair devices with the receiver, for many devices show\nbattery status, and show and modify some of the modifiable features of devices.\n'''.strip(),\n    author='Daniel Pavel',\n    license='GPLv2',\n    url='http://pwr-solaar.github.io/Solaar/',\n    classifiers=[\n        'Development Status :: 4 - Beta',\n        'Environment :: X11 Applications :: GTK',\n        'Environment :: Console',\n        'Intended Audience :: End Users/Desktop',\n        'License :: DFSG approved',\n        'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',\n        'Natural Language :: English',\n        'Programming Language :: Python :: 3 :: Only',\n        'Operating System :: POSIX :: Linux',\n        'Topic :: Utilities',\n    ],\n    platforms=['linux'],\n\n    # sudo apt install python-gi python3-gi \\\n    #        gir1.2-gtk-3.0 gir1.2-notify-0.7 gir1.2-ayatanaappindicator3-0.1\n    # os_requires=['gi.repository.GObject (>= 2.0)', 'gi.repository.Gtk (>= 3.0)'],\n    python_requires='>=3.6',\n    install_requires=[\n        'pyudev (>= 0.13)',\n    ],\n    package_dir={'': 'lib'},\n    packages=['hidapi', 'logitech_receiver', 'solaar', 'solaar.ui', 'solaar.cli'],\n    data_files=list(_data_files()),\n    scripts=_glob('bin/*'),\n)\n", "path": "setup.py"}]}