Python Forum
Matching multiple parts in string
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Matching multiple parts in string
#31
(Jun-12-2022, 12:10 AM)fozz Wrote: I'm on multiple networks and the script triggers on all networks ive joined , how can I specify to do the job only for one particulair network and channel?

In the user_join_callback is the network object, which could be used to differ between different networks. For example you can put a network in a str variable and compare it with the network variable in the user_join_callback. If it's not equal, you can just return with weechat.WEECHAT_RC_OK. I think a weechat requires that the callback always return a valid object. Forgetting the return anything, will return implicit a None.

The weechat.info_get_hashtable function can parse different types of messages.
The info_name "irc_message_parse" returns a hash table, which is like a Python dict.

https://weechat.org/files/doc/stable/wee..._hashtable
Quote:Name: irc_message_parse
Description: parse an IRC message
Hash table input: {"message": IRC message, "server": "server name (optional)"}

Output: "tags": tags, "tag_xxx": unescaped value of tag "xxx" (one key per tag), "message_without_tags": message without the tags, "nick": nick, "user": user, "host": host, "command": command, "channel": channel, "arguments": arguments (includes channel), "text": text (for example user message), "param1" …​ "paramN": parsed command parameters, "num_params": number of parsed command parameters, "pos_command": index of "command" message ("-1" if "command" was not found), "pos_arguments": index of "arguments" message ("-1" if "arguments" was not found), "pos_channel": index of "channel" message ("-1" if "channel" was not found), "pos_text": index of "text" message ("-1" if "text" was not found)

The resulting object from the weechat.get_info_hashtable function maybe a dict.
If it's a dict, you should be able to access it directly:
msg = weechat.info_get_hashtable("irc_message_parse", {"message": signal_data})
channel = msg["channel"]
# not sure if this works
Yes, it seem to work.
The example from the last post with modification:
from __future__ import annotations
 
import time
from fnmatch import fnmatch
from pathlib import Path
 
import weechat
 
# get the directory where the script is running
APPDIR = Path(__file__).absolute().parent
 
# userlist.txt should be next to script (same directory)
USER_FILE = APPDIR / "userlist.txt"
 
# max age of cache in secods
MAX_CACHE_AGE = 5 * 60

# the networks do only consist of the name
# not the whole domain
NETWORKS = ("libera",)
CHANNELS = ("#python-test",)

# dict to cache the userlist entries
cache : dict = {"age": None, "userlist": []}
 
 
def get_user_list() -> list[str]:
    """
    Retrieve cached userlist from userlist.txt
    If the age is older than 5 minutes, the cache is refreshed.
    """
 
    def read() -> list[str]:
        """
        Read the userlist.txt and return the lines stripped in a list
        """
        with USER_FILE.open() as fd:
            return [user for user in map(str.strip, fd) if user]
 
    if cache["age"] is None or not cache["userlist"] or cache["age"] > time.time():
        cache["userlist"] = read()
        cache["age"] = time.time() + MAX_CACHE_AGE
 
    return cache["userlist"]
 
 
def is_op(user: str) -> bool:
    """
    Checking user against each line of userlist.txt for a match.
    The userlist is take from get_user_list(), which caches
    the content for 5 minutes. Then the file is read again.
    """
    return any(fnmatch(user, pattern) for pattern in get_user_list())
 
 
def user_join_callback(data, signal, signal_data):
    network = signal.split(",", maxsplit=1)[0]
    address = signal_data.split(maxsplit=1)[0].removeprefix(":")
    nick = address.split("!", maxsplit=1)[0]
 
    msg = weechat.info_get_hashtable("irc_message_parse", {"message": signal_data})
    channel = msg["channel"]

    # print debugging
    weechat.prnt("", f'Network "{network}"')
    # condition to give not op
    if network not in NETWORKS or channel not in CHANNELS:
        return weechat.WEECHAT_RC_OK

    buffer = weechat.info_get("irc_buffer", f"{network},{msg['channel']}") 

    if is_op(address):
        weechat.prnt("", f"User {address} is recognized as OP")
        weechat.command(buffer, f"/wait 1 /mode {CHANNEL} +o {nick}")
    else:
        weechat.prnt("", f"User {address} is not an OP")
 
    return weechat.WEECHAT_RC_OK
 
 
CHANNEL = "#python-test"
weechat.register("op_script", "DeaD_EyE", "0.0.1", "BSD-0", "Auto OP script", "", "")
weechat.hook_signal("*,irc_in2_join", "user_join_callback", "")
Look at line 20 and 21 carefully. I used tuples, but a tuple with only one element inside requires a tailing comma. Lists with the square-brackets do not require this.

The networks seem only consist of the name. If I'm on irc.libera.chat, the network is libera.
What here is missing, is the possibility to manage for each network individual channels.
If you want to do this also, you can provide instead of a tuple, a dict where the keys are the allowed network names and the values are lists or tuples with allowed channels for each network.

networks = {
    "libera": ["#python-test", "#python-test2"],
    "quakenet": ["#python-test3", "#python-test4"],
}

# later inside the callback function:
if not network in networks.get(network, []):
    return weechat.WEECHAT_RC_OK

# networks is a dict
# the get function does not raise a KeyError if the key from network
# does not exist. Instead it returns by default a None. In this case,
# a None is useless because the in operator requires a sequence/collection check for existence.
# In this case we deliver an empty list, if the key does not exist,
# where the lookup fails because the list is empty.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#32
Amazing! And thank you for the comments and explanation DeaD_EyE :)
So I can replace:
NETWORKS = ("libera",)
CHANNELS = ("#python-test",)
With:
networks = {
    "libera": ["#python-test", "#python-test2"],
    "quakenet": ["#python-test3", "#python-test4"],
}
And:
    if network not in NETWORKS or channel not in CHANNELS:
        return weechat.WEECHAT_RC_OK
With:
if not network in networks.get(network, []):
    return weechat.WEECHAT_RC_OK
? Also can i remove the line:
CHANNEL = "#python-test"
But what to do with this line?:
weechat.command(buffer, f"/wait 1 /mode {CHANNEL} +o {nick}")
Do i need to change CHANNEL into channel or network variable?
I'm not sure how to implement this questions correctly in the script :/
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Matching string from a file tester_V 5 433 Mar-05-2024, 05:46 AM
Last Post: Danishhafeez
  splitting file into multiple files by searching for string AlphaInc 2 889 Jul-01-2023, 10:35 PM
Last Post: Pedroski55
  Save multiple Parts of Bytearray to File ? lastyle 1 941 Dec-10-2022, 08:09 AM
Last Post: Gribouillis
  matching a repeating string Skaperen 2 1,239 Jun-23-2022, 10:34 PM
Last Post: Skaperen
  Extract parts of multiple log-files and put it in a dataframe hasiro 4 2,083 Apr-27-2022, 12:44 PM
Last Post: hasiro
  Search multiple CSV files for a string or strings cubangt 7 8,006 Feb-23-2022, 12:53 AM
Last Post: Pedroski55
  Matching Exact String(s) Extra 4 1,907 Jan-12-2022, 04:06 PM
Last Post: Extra
  Replace String in multiple text-files [SOLVED] AlphaInc 5 8,103 Aug-08-2021, 04:59 PM
Last Post: Axel_Erfurt
Question How to extract multiple text from a string? chatguy 2 2,359 Feb-28-2021, 07:39 AM
Last Post: bowlofred
  How to print string multiple times on new line ace19887 7 5,730 Sep-30-2020, 02:53 PM
Last Post: buran

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020