Skip to content

Commit

Permalink
Replace finger with pinky (#688)
Browse files Browse the repository at this point in the history
* Replace finger with pinky
* Handle case with no fullname
  • Loading branch information
alifbe authored Apr 18, 2024
1 parent a1ddb06 commit 132e372
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 33 deletions.
55 changes: 31 additions & 24 deletions src/subscript/bjobsusers/bjobsusers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
DESCRIPTION = """
Print list of users running on cluster, sorted by number of jobs.
This is statistics derived from the system command `bjobs` and `finger`.
This is statistics derived from the system command `bjobs` and `pinky`.
"""


Expand Down Expand Up @@ -77,55 +77,62 @@ def get_jobs(status: str, bjobs_function: Callable) -> pd.DataFrame:
)


def call_finger(username: str) -> str:
"""Call the system utility 'finger' on a specific username
def call_pinky(username: str) -> str:
"""Call the system utility 'pinky' on a specific username
Returns:
Unicode string with the first line of output from 'finger'
Unicode string with the first line of output from 'pinky'
Example return value::
Login: foobert Name: Foo Barrer (FOO BAR COM)"
Login name: foobert In real life: Foo Barrer (FOO BAR COM)"
"""
cmd = f"finger -m {username} | head -n 1"
finger_output = None
cmd = f"pinky -l {username} | head -n 1"
pinky_output = None
try:
with open(os.devnull, "w", encoding="utf8") as devnull:
finger_output = (
pinky_output = (
subprocess.check_output(cmd, shell=True, stderr=devnull)
.strip()
.decode("utf-8")
)
except AttributeError:
pass
if finger_output:
return finger_output
# When finger fails, return something similar and usable
return f"Login: {username} Name: ?? ()"
if pinky_output:
return pinky_output
# When pinky fails, return something similar and usable
return f"Login name: {username} In real life: ?? ()"


def userinfo(username: str, finger_function: Callable) -> str:
def userinfo(username: str, pinky_function: Callable) -> str:
"""Get information on a user based on the username
Args:
username: user shortname/loginname
finger_function: Function handle that can provide output
from the system finger program (/usr/bin/finger).
pinky_function: Function handle that can provide output
from the system pinky program (/usr/bin/pinky).
The output must be a Unicode string
Returns:
str: String with full user name, organization from finger output and
str: String with full user name, organization from pinky output and
the shortname
"""
finger_output = finger_function(username)
rex_with_org = re.compile(r".*Login:\s+(.*)\s+Name:\s+(.*)\s+\((.*)\).*")
rex_no_org = re.compile(r".*Login:\s+(.*)\s+Name:\s+(.*)")
if rex_with_org.match(finger_output):
matches = rex_with_org.match(finger_output).groups() # type: ignore
pinky_output = pinky_function(username)
rex_with_org = re.compile(
r".*Login name:\s+(.*)\s+In real life:\s+(.*)\s+\((.*)\).*"
)
rex_no_org = re.compile(r".*Login name:\s+(.*)\s+In real life:\s+(.*)")
if rex_with_org.match(pinky_output):
matches = rex_with_org.match(pinky_output).groups() # type: ignore
fullname = matches[1].strip()
org = matches[2].strip()
elif rex_no_org.match(pinky_output):
matches = rex_no_org.match(pinky_output).groups() # type: ignore
fullname = matches[1].strip()
org = ""
else:
matches = rex_no_org.match(finger_output).groups() # type: ignore
fullname = username
org = ""
fullname = matches[1].strip()

return f"{fullname} ({org}) ({username})"


Expand All @@ -138,7 +145,7 @@ def show_status(status: str = "RUN", title: str = "Running", umax: int = 10) ->
print(
count[0],
userinfo( # lgtm [py/clear-text-logging-sensitive-data]
str(user), call_finger
str(user), call_pinky
),
)
print("- - - - - - - - - - -")
Expand Down
18 changes: 9 additions & 9 deletions tests/test_bjobsusers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ def bjobs_errors(status):
return "LIM not responding"


class FakeFinger:
"""Emulate the Linux finger utility"""
class FakePinky:
"""Emulate the Linux pinky utility"""

# pylint: disable=too-few-public-methods
def __init__(self, name):
self._name = name

def __call__(self, username):
"""Emulate the Linux finger utility"""
result = "Login: {} Name: " + self._name
"""Emulate the Linux pinky utility"""
result = "Login name: {} In real life: " + self._name
return subprocess.check_output(("echo", result)).decode("utf-8")


Expand Down Expand Up @@ -72,20 +72,20 @@ def test_userinfo():
"",
)

# assert isinstance(fake_finger(''), unicode) # only relevant for Python 2
# assert isinstance(fake_pinky(''), unicode) # only relevant for Python 2
for name in names:
usersummary = bjobsusers.userinfo("foobar", FakeFinger(name))
usersummary = bjobsusers.userinfo("foobar", FakePinky(name))
assert isinstance(usersummary, str)
assert "Login" not in usersummary
assert name in usersummary


def test_systemfinger():
"""Test the real system finger utility"""
def test_systempinky():
"""Test the real system pinky utility"""
currentuser = getpass.getuser()
if not currentuser:
return
usersummary = bjobsusers.userinfo(currentuser, bjobsusers.call_finger)
usersummary = bjobsusers.userinfo(currentuser, bjobsusers.call_pinky)
assert isinstance(usersummary, str)
print("Myself is: " + usersummary)
assert "Login" not in usersummary
Expand Down

0 comments on commit 132e372

Please sign in to comment.