internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: sopel-irc/sopel

Issue:
Exceptions with empty messages produce opaque error reports
### Description

Error reports issued by [`Sopel.error`](https://github.com/sopel-irc/sopel/blob/4e0a3868da1b6b350b761395fe627ac0a5978ae3/sopel/bot.py#L932-L933) format the exception as a string, which for most exception types will report only the message. For exceptions with an empty message, this leads to a fairly confusing report, e.g.

```
19:33 <terribot> Unexpected error () from SnoopJ at 2022-10-06 23:33:52.388980. Message was: !u:no-ascii 😹
```

### Reproduction steps

`raise NotImplementedError()` in a command was how I discovered this, but raising pretty much any empty exception should reproduce it

### Expected behavior

The error report could use the `repr()` of the exception instead

### Relevant logs

_No response_

### Notes

_No response_

### Sopel version

7.1.9

### Installation method

`pip install`

### Python version

3.9.4

### Operating system

Ubuntu 20.04

### IRCd

_No response_

### Relevant plugins

_No response_


Discussion:

Resolving patch:
diff --git a/sopel/bot.py b/sopel/bot.py
--- a/sopel/bot.py
+++ b/sopel/bot.py
@@ -930,7 +930,8 @@ def error(
         """
         message = 'Unexpected error'
         if exception:
-            message = '{} ({})'.format(message, exception)
+            detail = ' ({})'.format(exception) if str(exception) else ''
+            message = 'Unexpected {}{}'.format(type(exception).__name__, detail)
 
         if trigger:
             message = '{} from {} at {}. Message was: {}'.format(


Test patch:
Repository: sopel-irc/sopel

Issue:
RFC: Make `require_privilege` imply `require_chanmsg`
This is an idea that I keep thinking of, briefly, every so often. I always forget about it again before getting around to opening an issue though. Tonight I finally decided, enough.

I think it's a bit of a potential foot-gun to have `@plugin.require_privilege` be ignored in PMs, even though it's documented. Seems like it would make more sense to make `@plugin.require_privilege` imply `@plugin.require_chanmsg`.

We could also raise an error during plugin loading if a callable is decorated with both `@plugin.require_privmsg` and either of `@plugin.require_chanmsg` or `@plugin.require_privilege`.

Any thoughts from other maintainers about this? Am I failing to consider some obscure but very useful edge case where it would be useful to do this on purpose?

_Note: 8.0.0 milestone for attention, since it's a breaking change that would have to wait another who-knows-how-many-years until 9.0 if not done in v8._


Discussion:
I think it's safe to enforce require chanmsg when requiring privileges.

As for the other problem: developers are humans, they will make mistakes. The question is: is that really a problem?
They'll probably discover that they can't use their command with both decorator, so we shouldn't bother that much.



Resolving patch:
diff --git a/sopel/plugin.py b/sopel/plugin.py
--- a/sopel/plugin.py
+++ b/sopel/plugin.py
@@ -1200,17 +1200,20 @@ def require_privilege(
     <.bot.Sopel.say>`, but when ``reply`` is true, then it uses
     :meth:`bot.reply() <.bot.Sopel.reply>` instead.
 
-    Privilege requirements are ignored in private messages.
+    Use of ``require_privilege()`` implies :func:`require_chanmsg`.
 
     .. versionchanged:: 7.0
         Added the ``reply`` parameter.
+
+    .. versionchanged:: 8.0
+        Decorated callables no longer run in response to private messages.
     """
     def actual_decorator(function):
         @functools.wraps(function)
         def guarded(bot, trigger, *args, **kwargs):
-            # If this is a privmsg, ignore privilege requirements
+            # If this is a privmsg, do not trigger
             if trigger.is_privmsg:
-                return function(bot, trigger, *args, **kwargs)
+                return
             channel_privs = bot.channels[trigger.sender].privileges
             allowed = channel_privs.get(trigger.nick, 0) >= level
             if not trigger.is_privmsg and not allowed:


Test patch:
diff --git a/test/test_module.py b/test/test_module.py
--- a/test/test_module.py
+++ b/test/test_module.py
@@ -400,11 +400,12 @@ def mock_(bot, trigger, match=None):
     assert mock_(bot, trigger_account) is True
 
 
-def test_require_privilege(bot, trigger):
+def test_require_privilege(bot, trigger, trigger_pm):
     @module.require_privilege(module.VOICE)
     def mock_v(bot, trigger, match=None):
         return True
     assert mock_v(bot, trigger) is True
+    assert mock_v(bot, trigger_pm) is not True
 
     @module.require_privilege(module.OP, 'You must be at least opped!')
     def mock_o(bot, trigger, match=None):
Repository: sopel-irc/sopel

Issue:
reddit: annoyance factor of expanding slash-references
### The problem
If people talk about Reddit stuff enough, they could find the automatic info about in-text references to `r/` and `u/` names annoying. At present, this feature can be disabled only on a per-channel basis via the relevant global configuration functions.

### The solution
`reddit` should have a plugin setting to suppress this behavior everywhere.

### Notes
Mentioned by @xnaas on IRC, who said it's "a non-issue". Well it's an issue now, bud! 🙃


Discussion:

Resolving patch:
diff --git a/sopel/cli/utils.py b/sopel/cli/utils.py
--- a/sopel/cli/utils.py
+++ b/sopel/cli/utils.py
@@ -232,6 +232,7 @@ def find_config(config_dir: str, name: str, extension: str = '.cfg') -> str:
         '/home/username/.sopel/extra.ini'
 
     .. versionchanged:: 8.0
+
         Files in the ``config_dir`` are now preferred, and files without the
         requested extension are no longer returned.
 
diff --git a/sopel/modules/reddit.py b/sopel/modules/reddit.py
--- a/sopel/modules/reddit.py
+++ b/sopel/modules/reddit.py
@@ -18,6 +18,7 @@
 import requests
 
 from sopel import plugin
+from sopel.config import types
 from sopel.formatting import bold, color, colors
 from sopel.tools import time
 from sopel.tools.web import USER_AGENT
@@ -39,6 +40,11 @@
 gallery_url = r'https?://(?:www\.)?reddit\.com/gallery/([\w-]+)'
 
 
+class RedditSection(types.StaticSection):
+    slash_info = types.BooleanAttribute('slash_info', True)
+    """Expand inline references to users (u/someone) and subreddits (r/subname) in chat."""
+
+
 def setup(bot):
     if 'reddit_praw' not in bot.memory:
         # Create a PRAW instance just once, at load time
@@ -48,6 +54,19 @@ def setup(bot):
             client_secret=None,
             check_for_updates=False,
         )
+    bot.config.define_section('reddit', RedditSection)
+
+
+def configure(config):
+    """
+    | name | example | purpose |
+    | ---- | ------- | ------- |
+    | slash\\_info | off | Whether the bot should expand inline references to users (`u/someone`) or subreddits (`r/subname`) |
+    """
+    config.define_section('reddit', RedditSection)
+    config.reddit.configure_setting(
+        'slash_info', "Expand references like u/someone or r/subname in chat?"
+    )
 
 
 def shutdown(bot):
@@ -457,6 +476,10 @@ def get_channel_spoiler_free(bot, trigger):
 def reddit_slash_info(bot, trigger):
     searchtype = trigger.group('prefix').lower()
     match = trigger.group('id')
+
+    if not bot.config.reddit.slash_info:
+        return
+
     if searchtype == "r":
         return subreddit_info(bot, trigger, match, commanded=False)
     elif searchtype == "u":


Test patch:
Repository: sopel-irc/sopel

Issue:
url: Unexpected error on nonexistent domains
The following code line raises an unhandled `dns.resolver.NXDOMAIN` for URLs at nonexistent domains:

https://github.com/sopel-irc/sopel/blob/eff60e9b49a14e1f3c0c4dab5bb4d2ddbf0098a5/sopel/modules/url.py#L377

Some variant of this operation has been in the code for a while, but the context has changed so much during 8.x that I decided not to follow `git blame` all the way back to the first addition of `dns.resolver`. Seemed like a waste of time.


Discussion:
I created this just to track it, but didn't dive into the code yet. Might be good that I didn't spend any more time because #2285 might just get rid of the cause entirely.
Stumbled into a decent reproducer for this error: a message that contains a URL terminated by a backtick ``` ` ```, e.g.

```
09:52 <+SnoopJ> does it happen for `hypothetical_language_variable = https://github.com` too
09:52 <+Sopel> Unexpected NXDOMAIN (The DNS query name does not exist: github.com`.) from SnoopJ at 2023-03-20 13:52:13.198849. Message was: does it happen for `hypothetical_language_variable = https://github.com` too
```

Resolving patch:
diff --git a/sopel/modules/url.py b/sopel/modules/url.py
--- a/sopel/modules/url.py
+++ b/sopel/modules/url.py
@@ -406,7 +406,18 @@ def process_urls(
             try:
                 ips = [ip_address(parsed_url.hostname)]
             except ValueError:
-                ips = [ip_address(ip) for ip in dns.resolver.resolve(parsed_url.hostname)]
+                # Extra try/except here in case the DNS resolution fails, see #2348
+                try:
+                    ips = [ip_address(ip) for ip in dns.resolver.resolve(parsed_url.hostname)]
+                except Exception as exc:
+                    LOGGER.debug(
+                        "Cannot resolve hostname %s, ignoring URL %s"
+                        " (exception was: %r)",
+                        parsed_url.hostname,
+                        url,
+                        exc,
+                    )
+                    continue
 
             private = False
             for ip in ips:


Test patch:
Repository: sopel-irc/sopel

Issue:
Root module description is a mini-rant about LC_ALL rather than a description of the library
### Description

Looking at the `sopel` module with `pydoc` in an interactive prompt) exposes the user to [a short rant](https://github.com/sopel-irc/sopel/blob/c26914b68913bc25bdd1f5fed9c5942a87fdfee6/sopel/__init__.py#L1-L4) about the behavior of `LC_ALL` and instructions to use only ASCII in this module.

I'm sympathetic to the frustration over #984 that led to this, but it will be an improvement to add a docstring to the module with a short description.

### Reproduction steps

Run `python3 -m pydoc sopel` or `import sopel; help(sopel)` in an interactive prompt.

### Expected behavior

The user should see a short description of Sopel

### Relevant logs

_No response_

### Notes

_No response_

### Sopel version

c26914b

### Installation method

`pip install`

### Python version

_No response_

### Operating system

_No response_

### IRCd

_No response_

### Relevant plugins

_No response_


Discussion:

Resolving patch:
diff --git a/sopel/__init__.py b/sopel/__init__.py
--- a/sopel/__init__.py
+++ b/sopel/__init__.py
@@ -1,8 +1,9 @@
-# ASCII ONLY IN THIS FILE THOUGH!!!!!!!
-# Python does some stupid bullshit of respecting LC_ALL over the encoding on the
-# file, so in order to undo Python's ridiculous fucking idiocy, we have to have
-# our own check.
+"""
+Sopel is a simple, easy-to-use, open-source IRC utility bot, written in Python.
 
+It’s designed to be easy to use, easy to run, and easy to extend.
+"""
+#
 # Copyright 2008, Sean B. Palmer, inamidst.com
 # Copyright 2012, Elsie Powell, http://embolalia.com
 # Copyright 2012, Elad Alfassa <elad@fedoraproject.org>
@@ -37,9 +38,8 @@
 
 loc = locale.getlocale()
 if not loc[1] or ('UTF-8' not in loc[1] and 'utf8' not in loc[1]):
-    print('WARNING!!! You are running with a non-UTF8 locale environment '
-          'variable (e.g. LC_ALL is set to "C"), which makes Python 3 do '
-          'stupid things. If you get strange errors, please set it to '
+    print('Warning: Running with a non-UTF8 locale. If you see strange '
+          'encoding errors, try setting the LC_ALL environment variable to '
           'something like "en_US.UTF-8".', file=sys.stderr)
 
 


Test patch:
Repository: sopel-irc/sopel

Issue:
docs: include how-to information for getting help/reporting bugs
### Requested Feature

It's common for errors reported in a reply by a Sopel instance to be inadequate for debugging what went wrong, so that the first step in getting a user the assistance they need is helping them locate and share the logs for their instance. It would be handy to have more of a formal "how to get help" narrative to make the experience more consistent for both users and helpers, and there may be other common advice/procedures that could be laid out in a document like that.

### Problems Solved

_No response_

### Alternatives

_No response_

### Notes

There's [some notes in `CONTRIBUTING.md`](https://github.com/sopel-irc/sopel/blob/master/CONTRIBUTING.md?plain=1#L1-L12) and [some information about logger configuration in the docs](https://sopel.chat/docs/configuration.html#logging) that are good starting points for this request.

Some 'prior art' in other projects:
* The Littlest JupyterHub's [Looking at Logs](https://tljh.jupyter.org/en/latest/troubleshooting/logs.html)
* PyInstaller's [When Things Go Wrong](https://pyinstaller.org/en/stable/when-things-go-wrong.html)


Discussion:
The FAQ added in #2533 (https://unstable.docs.sopel.chat/faq) covers this topic.

Resolving patch:
diff --git a/sopel/config/core_section.py b/sopel/config/core_section.py
--- a/sopel/config/core_section.py
+++ b/sopel/config/core_section.py
@@ -756,8 +756,11 @@ class CoreSection(StaticSection):
     def homedir(self):
         """The directory in which various files are stored at runtime.
 
-        By default, this is the same directory as the config file. It cannot be
-        changed at runtime.
+        Specifying the ``homedir`` option is useful for e.g. :doc:`running Sopel
+        as a system service </run/service>`.
+
+        If not set, the config file's parent directory will be used. This value
+        cannot be changed at runtime.
         """
         return self._parent.homedir
 
@@ -824,7 +827,7 @@ def homedir(self):
     :default: ``logs``
 
     If the given value is not an absolute path, it will be interpreted relative
-    to the directory containing the config file with which Sopel was started.
+    to the :attr:`homedir` of the config file with which Sopel was started.
 
     .. seealso::
 


Test patch:
Repository: pyjanitor-devs/pyjanitor

Issue:
Case Sensitive True/False kwarg on clean_names
Using pyjanitor again today I realised I didn't want to change capitals to lowercase. I think a case sensitive kwarg (default on) would be good.

Happy to do PR for this if you think it is a good idea. One Q on this, what would should the kwarg be called?

Some ideas:
`lower`, `remove_upper`, `drop_case`, `case_sensitive`,...


Discussion:

Resolving patch:
diff --git a/janitor/functions.py b/janitor/functions.py
--- a/janitor/functions.py
+++ b/janitor/functions.py
@@ -40,7 +40,7 @@ def _strip_underscores(df, strip_underscores=None):
     return df
 
 
-def clean_names(df, strip_underscores=None):
+def clean_names(df, strip_underscores=None, preserve_case=False):
     """
     Clean column names.
 
@@ -65,11 +65,18 @@ def clean_names(df, strip_underscores=None):
         column names. Default None keeps outer underscores. Values can be
         either 'left', 'right' or 'both' or the respective shorthand 'l', 'r'
         and True.
+    :param preserve_case: (optional) Allows you to choose whether to make all
+    column names lowercase, or to preserve current cases. Default False makes
+    all characters lowercase.
     :returns: A pandas DataFrame.
     """
+    if preserve_case is False:
+        df = df.rename(
+            columns=lambda x: x.lower()
+        )
+
     df = df.rename(
-        columns=lambda x: x.lower()
-                           .replace(' ', '_')
+        columns=lambda x: x.replace(' ', '_')
                            .replace('/', '_')
                            .replace(':', '_')
                            .replace("'", '')
@@ -111,7 +118,6 @@ def remove_empty(df):
     :param df: The pandas DataFrame object.
     :returns: A pandas DataFrame.
     """
-
     nanrows = df.index[df.isnull().all(axis=1)]
     df.drop(index=nanrows, inplace=True)
 


Test patch:
diff --git a/tests/test_functions.py b/tests/test_functions.py
--- a/tests/test_functions.py
+++ b/tests/test_functions.py
@@ -247,3 +247,18 @@ def test_clean_names_strip_underscores_l(multiindex_dataframe):
 
     expected_columns = pd.MultiIndex(levels=levels, labels=labels)
     assert set(df.columns) == set(expected_columns)
+
+
+def test_clean_names_preserve_case_true(multiindex_dataframe):
+    df = multiindex_dataframe.rename(columns=lambda x: '_' + x)
+    df = clean_names(multiindex_dataframe, preserve_case=True)
+
+    levels = [
+        ['a', 'Bell_Chart', 'decorated_elephant'],
+        ['b', 'Normal_Distribution', 'r_i_p_rhino_']
+    ]
+
+    labels = [[1, 0, 2], [1, 0, 2]]
+
+    expected_columns = pd.MultiIndex(levels=levels, labels=labels)
+    assert set(df.columns) == set(expected_columns)
Repository: pyjanitor-devs/pyjanitor

Issue:
add_column sanity checking broken for strings
There's a sanity check I put in there where if the supplied value is a sequence, it makes sure that the length is the same as the number of rows in the `DataFrame` as long as `fill_remaining` is false. This is done by checking for the existence of `__len__`. I need to add logic to exclude this checking for `str` objects. Fixing now.


Discussion:

Resolving patch:
diff --git a/janitor/functions.py b/janitor/functions.py
--- a/janitor/functions.py
+++ b/janitor/functions.py
@@ -964,7 +964,9 @@ def add_column(df, col_name: str, value, fill_remaining: bool = False):
 
     nrows = df.shape[0]
 
-    if hasattr(value, "__len__"):
+    if hasattr(value, "__len__") and not isinstance(
+        value, (str, bytes, bytearray)
+    ):
         # if `value` is a list, ndarray, etc.
         if len(value) > nrows:
             raise ValueError(


Test patch:
diff --git a/tests/test_functions.py b/tests/test_functions.py
--- a/tests/test_functions.py
+++ b/tests/test_functions.py
@@ -530,6 +530,14 @@ def test_add_column(dataframe):
     series.name = 'fortytwo'
     pd.testing.assert_series_equal(df['fortytwo'], series)
 
+    # scalar values are correct for strings
+    # also, verify sanity check excludes strings, which have a length:
+
+    df = dataframe.add_column("fortythousand", "test string")
+    series = pd.Series(["test string"] * len(dataframe))
+    series.name = "fortythousand"
+    pd.testing.assert_series_equal(df["fortythousand"], series)
+
     # values are correct in dataframe for iterable
     vals = np.linspace(0, 43, len(dataframe))
     df = dataframe.add_column('fortythree', vals)
Repository: pyjanitor-devs/pyjanitor

Issue:
"then" function
I had an idea for a function that allows for users to run any arbitrary function in the method chain.

For example, I think it's annoying if someone has their own logic and needs to do this:

```python
def custom_logic(df):
    ...
    return df

df = (df.clean_names()
    .add_column('a_column'))

df = custom_logic(df)
```

Instead, people should be able to do the following:

```python
def custom_logic(df):
    ...
    return df

df = (df.clean_names()
    .then(custom_logic)
    .add_column('a_column')
```


Discussion:

Resolving patch:
diff --git a/janitor/functions.py b/janitor/functions.py
--- a/janitor/functions.py
+++ b/janitor/functions.py
@@ -2408,3 +2408,21 @@ def impute(df, column: str, value=None, statistic=None):
     if value is not None:
         df[column] = df[column].fillna(value)
     return df
+
+
+@pf.register_dataframe_method
+def then(df: pd.DataFrame, func) -> pd.DataFrame:
+    """
+    :Description:
+
+    Add an arbitrary function to run in the pyJanitor method chain.
+
+    :param df: A pandas dataframe.
+    :param func: A function you would like to run in the method chain.\
+    It should take one parameter and return one parameter, each being the\
+    DataFrame object. After that, do whatever you want in the middle.\
+    Go crazy.
+    """
+
+    df = func(df)
+    return df


Test patch:
diff --git a/tests/functions/test_then.py b/tests/functions/test_then.py
new file mode 100644
--- /dev/null
+++ b/tests/functions/test_then.py
@@ -0,0 +1,29 @@
+import pandas as pd
+import pytest
+
+
+def remove_first_two_letters_from_col_names(df):
+    col_names = df.columns
+    col_names = [name[2:] for name in col_names]
+    df.columns = col_names
+    return df
+
+
+def remove_rows_3_and_4(df):
+    df = df.drop(3, axis=0)
+    df = df.drop(4, axis=0)
+    return df
+
+
+@pytest.mark.functions
+def test_then_column_names(dataframe):
+    df = dataframe.then(remove_first_two_letters_from_col_names)
+    cols = tuple(df.columns)
+    assert cols == ("", "ll__Chart", "corated-elephant", "imals@#$%^", "ties")
+
+
+@pytest.mark.functions
+def test_then_remove_rows(dataframe):
+    df = dataframe.then(remove_rows_3_and_4)
+    rows = tuple(df.index)
+    assert rows == (0, 1, 2, 5, 6, 7, 8)
Repository: pyjanitor-devs/pyjanitor

Issue:
Add the `pd.to_datetime` method so that it is chainable
It would be nice to have this function being chainable.


Discussion:

Resolving patch:
diff --git a/janitor/functions.py b/janitor/functions.py
--- a/janitor/functions.py
+++ b/janitor/functions.py
@@ -2599,3 +2599,34 @@ def update_where(
     """
     df.loc[conditions, target_col] = target_val
     return df
+
+
+@pf.register_dataframe_method
+def to_datetime(df: pd.DataFrame, column: str, **kwargs) -> pd.DataFrame:
+    """
+
+    Makes the pandas to_datetime method work as a chainable method.
+
+    Functional usage example:
+
+    .. code-block:: python
+
+        df = to_datetime(df, 'col1', format='%Y%m%d')
+
+    Method chaining example:
+
+    .. code-block:: python
+
+        import pandas as pd
+        import janitor
+        df = pd.DataFrame(...).to_datetime('col1', format='%Y%m%d')
+
+    :param df: A pandas DataFrame.
+    :param column: Column name.
+    :param kwargs: provide any kwargs that pd.to_datetime can take.
+    :returns: A pandas DataFrame.
+    """
+
+    df[column] = pd.to_datetime(df[column], **kwargs)
+
+    return df


Test patch:
diff --git a/tests/functions/test_to_datetime.py b/tests/functions/test_to_datetime.py
new file mode 100644
--- /dev/null
+++ b/tests/functions/test_to_datetime.py
@@ -0,0 +1,16 @@
+import numpy as np
+import pandas as pd
+import pytest
+
+
+@pytest.mark.functions
+def test_to_datetime():
+
+    df = pd.DataFrame({
+        "date1": ['20190101', '20190102', '20190304', np.nan],
+    }).to_datetime(
+        "date1",
+        format='%Y%m%d'
+    )
+    assert df["date1"].dtype == pd.np.dtype('datetime64[ns]')
+    assert df["date1"].iloc[0].isoformat() == '2019-01-01T00:00:00'