Skip to content

Commit e0fc6d1

Browse files
committed
flake8 tests, check-manifest, safety
1 parent 716653d commit e0fc6d1

File tree

13 files changed

+156
-116
lines changed

13 files changed

+156
-116
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ jobs:
1616
python3 -m pip install --upgrade pip
1717
pip3 install tox
1818
- name: Test with tox
19-
run: tox -e py39
19+
run: tox -e py39,style

example.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
"""
3-
Example script showing how to install and remove plist based launchd jobs
3+
Example script showing how to install and remove plist based launchd jobs.
44
"""
55

66
import sys
@@ -10,64 +10,64 @@
1010

1111

1212
def install(label, plist):
13-
'''
14-
Utility function to store a new .plist file and load it
13+
"""
14+
Store a new .plist file and load it.
1515
1616
:param label: job label
1717
:param plist: a property list dictionary
18-
'''
18+
"""
1919
fname = launchd.plist.write(label, plist)
2020
launchd.load(fname)
2121

2222

2323
def uninstall(label):
24-
'''
25-
Utility function to remove a .plist file and unload it
24+
"""
25+
Remove a .plist file and unload it.
2626
2727
:param label: job label
28-
'''
28+
"""
2929
if launchd.LaunchdJob(label).exists():
3030
fname = launchd.plist.discover_filename(label)
3131
launchd.unload(fname)
3232
os.unlink(fname)
3333

3434

3535
def main():
36-
myplist = dict(
37-
Disabled=False,
38-
Label="testlaunchdwrapper_python",
39-
Nice=-15,
40-
OnDemand=True,
41-
ProgramArguments=["/bin/bash", "-c", "sleep 1 && echo 'Hello World' && exit 0"],
42-
RunAtLoad=True,
43-
ServiceDescription="runs a sample command",
44-
ServiceIPC=False,
45-
)
36+
myplist = {
37+
"Disabled": False,
38+
"Label": "testlaunchdwrapper_python",
39+
"Nice": -15,
40+
"OnDemand": True,
41+
"ProgramArguments": ["/bin/bash", "-c", "sleep 1 && echo 'Hello World' && exit 0"],
42+
"RunAtLoad": True,
43+
"ServiceDescription": "runs a sample command",
44+
"ServiceIPC": False,
45+
}
4646

4747
import time
48-
label = myplist['Label']
48+
label = myplist["Label"]
4949
job = launchd.LaunchdJob(label)
5050
if not job.exists():
51-
print("'%s' is not loaded in launchd. Installing..." % (label))
51+
print("'%s' is not loaded in launchd. Installing..." % (label)) # noqa: T001
5252
install(label, myplist)
5353
while job.pid is not None:
54-
print("Alive! PID = %s" % job.pid)
54+
print("Alive! PID = %s" % job.pid) # noqa: T001
5555
job.refresh()
5656
time.sleep(0.2)
5757
else:
5858
if job.pid is None:
59-
print("'%s' is loaded but not currently running" % (job.label))
59+
print("'%s' is loaded but not currently running" % (job.label)) # noqa: T001
6060
else:
61-
print("'%s' is loaded and currently running: PID = %s" % (job.label, job.pid))
61+
print("'%s' is loaded and currently running: PID = %s" % (job.label, job.pid)) # noqa: T001
6262
while job.pid is not None:
63-
print("Alive! PID = %s" % job.pid)
63+
print("Alive! PID = %s" % job.pid) # noqa: T001
6464
job.refresh()
6565
time.sleep(0.2)
6666

67-
print("Uninstalling again...")
67+
print("Uninstalling again...") # noqa: T001
6868
uninstall(label)
6969
return 0
7070

7171

72-
if __name__ == '__main__':
72+
if __name__ == "__main__":
7373
sys.exit(main())

launchd/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# -*- coding: utf-8 -*-
22

3-
__author__ = 'Paul Kremer'
4-
__email__ = 'paul@spurious.biz'
5-
__version__ = '0.2.0'
3+
__author__ = "Paul Kremer"
4+
__email__ = "paul@spurious.biz"
5+
__version__ = "0.2.0"
66

7-
from .launchctl import jobs, LaunchdJob, load, unload
8-
from . import plist
9-
from . import util
7+
from .launchctl import jobs, LaunchdJob, load, unload # noqa: F401
8+
from . import plist # noqa: F401
9+
from . import util # noqa: F401

launchd/cmd.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
# -*- coding: utf-8 -*-
22

3-
import subprocess
3+
import subprocess # noqa: S404
44

55
import six
66

77

88
def launchctl(subcommand, *args):
9-
'''
10-
A minimal wrapper to call the launchctl binary and capture the output
9+
"""
10+
Call the launchctl binary and capture the output.
11+
1112
:param subcommand: string
12-
'''
13+
"""
1314
if not isinstance(subcommand, six.string_types):
1415
raise ValueError("Argument is invalid: %r" % repr(subcommand))
1516
if isinstance(subcommand, six.text_type):
16-
subcommand = subcommand.encode('utf-8')
17+
subcommand = subcommand.encode("utf-8")
1718

1819
cmd = ["launchctl", subcommand]
1920
for arg in args:
2021
if isinstance(arg, six.string_types):
2122
if isinstance(arg, six.text_type):
22-
cmd.append(arg.encode('utf-8'))
23+
cmd.append(arg.encode("utf-8"))
2324
else:
2425
cmd.append(arg)
2526
else:
2627
raise ValueError("Argument is invalid: %r" % repr(arg))
27-
return subprocess.check_output(cmd, stdin=None, stderr=subprocess.STDOUT, shell=False)
28+
return subprocess.check_output(cmd, stdin=None, stderr=subprocess.STDOUT, shell=False) # noqa: S603

launchd/launchctl.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,23 @@
88

99

1010
class LaunchdJob(object):
11-
'''
12-
Custom class that allows us to lazily query the properties
13-
of the LaunchdJob when accessed.
14-
'''
15-
def __init__(self, label, pid=-1, laststatus=''):
16-
'''
11+
"""
12+
Class to lazily query the properties of the LaunchdJob when accessed.
13+
"""
14+
def __init__(self, label, pid=-1, laststatus=""):
15+
"""
1716
Instantiate a LaunchdJob instance. Only the label is required.
1817
If no pid or laststatus are specified, they will be queried when
1918
accessed.
2019
2120
:param label: required string job label
2221
:param pid: optional int, if known. Can be None.
2322
:param laststatus: optional int, if known. Can be None.
24-
'''
23+
"""
2524
self._label = label
2625
if pid != -1: # -1 indicates no value specified
2726
self._pid = pid
28-
if laststatus != '':
27+
if laststatus != "":
2928
self._laststatus = laststatus
3029
self._properties = None
3130
self._plist_fname = None
@@ -53,15 +52,15 @@ def laststatus(self):
5352

5453
@property
5554
def properties(self):
56-
'''
57-
This is a lazily loaded dictionary containing the launchd runtime
58-
information of the job in question. Internally, this is retrieved
59-
using ServiceManagement.SMJobCopyDictionary(). Keep in mind that
60-
some dictionary keys are not always present (for example 'PID').
55+
"""
56+
Lazily load dictionary with launchd runtime information.
57+
58+
Internally, this is retrieved using ServiceManagement.SMJobCopyDictionary().
59+
Keep in mind that some dictionary keys are not always present (for example 'PID').
6160
If the job specified by the label cannot be found in launchd, then
6261
this method raises a ValueError exception.
63-
'''
64-
if hasattr(self, '_nsproperties'):
62+
"""
63+
if hasattr(self, "_nsproperties"):
6564
self._properties = convert_NSDictionary_to_dict(self._nsproperties)
6665
del self._nsproperties
6766
# self._nsproperties = None
@@ -80,36 +79,37 @@ def refresh(self):
8079
self._properties = convert_NSDictionary_to_dict(val)
8180
# update pid and laststatus attributes
8281
try:
83-
self._pid = self._properties['PID']
82+
self._pid = self._properties["PID"]
8483
except KeyError:
8584
self._pid = None
8685
try:
87-
self._laststatus = self._properties['LastExitStatus']
86+
self._laststatus = self._properties["LastExitStatus"]
8887
except KeyError:
8988
self._laststatus = None
9089

9190
@property
9291
def plistfilename(self):
93-
'''
94-
This is a lazily detected absolute filename of the corresponding
95-
property list file (*.plist). None if it doesn't exist.
96-
'''
92+
"""
93+
Lazily detect absolute filename of the property list file.
94+
95+
Return None if it doesn't exist.
96+
"""
9797
if self._plist_fname is None:
9898
self._plist_fname = discover_filename(self.label)
9999
return self._plist_fname
100100

101101

102102
def jobs():
103103
for entry in ServiceManagement.SMCopyAllJobDictionaries(None):
104-
label = entry['Label']
104+
label = entry["Label"]
105105
if label.startswith("0x"):
106106
continue
107107
try:
108-
pid = int(entry['PID'])
108+
pid = int(entry["PID"])
109109
except KeyError:
110110
pid = None
111111
try:
112-
laststatus = int(entry['LastExitStatus'])
112+
laststatus = int(entry["LastExitStatus"])
113113
except KeyError:
114114
laststatus = None
115115
job = LaunchdJob(label, pid, laststatus)

launchd/plist.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
DAEMON_OS = 5
1111

1212
PLIST_LOCATIONS = {
13-
USER: '~/Library/LaunchAgents', # Per-user agents provided by the user.
14-
USER_ADMIN: '/Library/LaunchAgents', # Per-user agents provided by the administrator.
15-
DAEMON_ADMIN: '/Library/LaunchDaemons', # System-wide daemons provided by the administrator.
16-
USER_OS: '/System/Library/LaunchAgents', # Per-user agents provided by Mac OS X.
17-
DAEMON_OS: '/System/Library/LaunchDaemons', # System-wide daemons provided by Mac OS X.
13+
USER: "~/Library/LaunchAgents", # Per-user agents provided by the user.
14+
USER_ADMIN: "/Library/LaunchAgents", # Per-user agents provided by the administrator.
15+
DAEMON_ADMIN: "/Library/LaunchDaemons", # System-wide daemons provided by the administrator.
16+
USER_OS: "/System/Library/LaunchAgents", # Per-user agents provided by Mac OS X.
17+
DAEMON_OS: "/System/Library/LaunchDaemons", # System-wide daemons provided by Mac OS X.
1818
}
1919

2020

@@ -27,15 +27,15 @@ def compute_filename(label, scope):
2727

2828

2929
def discover_filename(label, scopes=None):
30-
'''
30+
"""
3131
Check the filesystem for the existence of a .plist file matching the job label.
3232
Optionally specify one or more scopes to search (default all).
3333
3434
:param label: string
3535
:param scope: tuple or list or oneOf(USER, USER_ADMIN, DAEMON_ADMIN, USER_OS, DAEMON_OS)
36-
'''
36+
"""
3737
if scopes is None:
38-
scopes = [k for k in PLIST_LOCATIONS]
38+
scopes = list(PLIST_LOCATIONS)
3939
elif not isinstance(scopes, (list, tuple)):
4040
scopes = (scopes, )
4141
for thisscope in scopes:
@@ -46,20 +46,19 @@ def discover_filename(label, scopes=None):
4646

4747

4848
def read(label, scope=None):
49-
with open(discover_filename(label, scope), 'rb') as f:
49+
with open(discover_filename(label, scope), "rb") as f:
5050
return plistlib.load(f)
5151

5252

5353
def write(label, plist, scope=USER):
54-
'''
55-
Writes the given property list to the appropriate file on disk and returns
56-
the absolute filename.
54+
"""
55+
Write the property list to file on disk and return filename.
5756
5857
Creates the underlying parent directory structure if missing.
5958
:param plist: dict
6059
:param label: string
6160
:param scope: oneOf(USER, USER_ADMIN, DAEMON_ADMIN, USER_OS, DAEMON_OS)
62-
'''
61+
"""
6362
os.makedirs(compute_directory(scope), mode=0o755, exist_ok=True)
6463
fname = compute_filename(label, scope)
6564
with open(fname, "wb") as f:

launchd/tests/cmd.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def tearDown(self):
1616
unittest.TestCase.tearDown(self)
1717

1818
def testlaunchctl_invalid_args(self):
19-
self.assertRaises(ValueError, cmd.launchctl, ['foo'])
19+
self.assertRaises(ValueError, cmd.launchctl, ["foo"])
2020

2121
def testlaunchctl_list(self):
2222
stdout = cmd.launchctl("list").decode("utf-8")

launchd/tests/launchctl.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@
99
import launchd
1010

1111

12-
launchdtestplist = dict(
13-
Disabled=False,
14-
Label="testlaunchdwrapper_python",
15-
Nice=-15,
16-
OnDemand=True,
17-
ProgramArguments=["/bin/bash", "-c", "echo 'Hello World' && exit 0"],
18-
RunAtLoad=True,
19-
ServiceDescription="runs a sample command",
20-
ServiceIPC=False,
21-
)
12+
launchdtestplist = {
13+
"Disabled": False,
14+
"Label": "testlaunchdwrapper_python",
15+
"Nice": -15,
16+
"OnDemand": True,
17+
"ProgramArguments": ["/bin/bash", "-c", "echo 'Hello World' && exit 0"],
18+
"RunAtLoad": True,
19+
"ServiceDescription": "runs a sample command",
20+
"ServiceIPC": False,
21+
}
2222

2323

2424
class LaunchctlTestCase(unittest.TestCase):
@@ -31,10 +31,10 @@ def tearDown(self):
3131

3232
@unittest.skipUnless(sys.platform.startswith("darwin"), "requires OS X")
3333
def test_examples(self):
34-
activejobs = [job for job in launchd.jobs() if job.pid is not None]
35-
inactivejobs = [job for job in launchd.jobs() if job.pid is None]
36-
errorjobs = [job for job in launchd.jobs() if job.laststatus != 0 and job.laststatus is not None]
37-
ondemandjobs = [job for job in launchd.jobs() if job.properties['OnDemand'] is True]
34+
[job for job in launchd.jobs() if job.pid is not None] # activejobs
35+
[job for job in launchd.jobs() if job.pid is None] # inactivejobs
36+
[job for job in launchd.jobs() if job.laststatus != 0 and job.laststatus is not None] # errorjobs
37+
[job for job in launchd.jobs() if job.properties["OnDemand"] is True] # ondemandjobs
3838

3939
@unittest.skipUnless(sys.platform.startswith("darwin"), "requires OS X")
4040
def test_launchd_jobs(self):
@@ -50,8 +50,8 @@ def test_launchd_jobs(self):
5050
self.assertTrue(job.plistfilename is None or isinstance(job.plistfilename, six.string_types))
5151
# the next 2 fail sometimes due to short lived processes that
5252
# have disappeared by the time we reach this test
53-
self.assertTrue('PID' in job.properties if job.pid is not None else True)
54-
self.assertTrue('PID' not in job.properties if job.pid is None else True)
53+
self.assertTrue("PID" in job.properties if job.pid is not None else True)
54+
self.assertTrue("PID" not in job.properties if job.pid is None else True)
5555
self.assertTrue(count > 0)
5656

5757
@unittest.skipUnless(sys.platform.startswith("darwin"), "requires OS X")
@@ -67,8 +67,8 @@ def test_launchd_lazy_constructor(self):
6767
label = "com.apple.Finder"
6868
job = launchd.LaunchdJob(label)
6969
self.assertTrue(job.exists())
70-
self.assertFalse(hasattr(job, '_pid'))
71-
self.assertFalse(hasattr(job, '_laststatus'))
70+
self.assertFalse(hasattr(job, "_pid"))
71+
self.assertFalse(hasattr(job, "_laststatus"))
7272
self.assertEqual(None, job._properties)
7373
job.refresh()
7474
self.assertNotEqual(None, job._pid)

0 commit comments

Comments
 (0)