nebius/SWE-bench-extra huggingface dataset:
Repository: aymanizz/smalld-click

Issue:
Send messages in 2K characters chunks to avoid hitting message length limit
There is a limit of 2K characters for messages sent through discord.

Comments:

Patch:
diff --git a/README.md b/README.md
index 0eef38e..54ca7ed 100644
--- a/README.md
+++ b/README.md
@@ -97,7 +97,10 @@ prompts that are hidden, using `hide_input=True`, are sent to the user DM, and c
 
 Note that, echo and prompt will send a message in the same channel as the message that triggered the command invocation.
 
-Calls to echo are buffered, the buffer is flushed either when there is a prompt or when the command finishes execution.
+Calls to echo are buffered. When the buffer is flushed, its content is sent in 2K chunks (limit set by discord.)
+The buffer can be flushed automatically when there is a prompt, or the command finishes execution, or the content
+in the buffer exceeds the 2K limit.
+
 It's also possible to flush the buffer by passing `flush=True` to `click.echo` call.
 
 ## Acknowledgements
diff --git a/smalld_click/conversation.py b/smalld_click/conversation.py
index fcacfb1..a094244 100644
--- a/smalld_click/conversation.py
+++ b/smalld_click/conversation.py
@@ -6,6 +6,9 @@ click_prompt = click.prompt
 click_echo = click.echo
 
 
+MESSAGE_CHARACTERS_LIMIT = 2000
+
+
 class Conversation:
     def __init__(self, runner, message, timeout):
         self.runner = runner
@@ -44,11 +47,11 @@ class Conversation:
     def flush(self):
         content = self.echo_buffer.getvalue()
         self.echo_buffer = io.StringIO()
-        if not content.strip():
-            return
 
         smalld, channel_id = self.runner.smalld, self.channel_id
-        smalld.post(f"/channels/{channel_id}/messages", {"content": content})
+        for message in chunked(content, MESSAGE_CHARACTERS_LIMIT):
+            if message.strip():
+                smalld.post(f"/channels/{channel_id}/messages", {"content": message})
 
     def wait_for_message(self):
         handle = self.runner.add_listener(self.user_id, self.channel_id)
@@ -72,3 +75,8 @@ class Conversation:
 
 def get_conversation():
     return click.get_current_context().find_object(Conversation)
+
+
+def chunked(it, n):
+    for i in range(0, len(it), n):
+        yield it[i : i + n]


Test patch:
diff --git a/test/test_smalld_click.py b/test/test_smalld_click.py
index ac4461f..bdecef9 100644
--- a/test/test_smalld_click.py
+++ b/test/test_smalld_click.py
@@ -251,3 +251,21 @@ def test_patches_click_functions_in_context_only(smalld):
 
     assert click.echo is click_echo
     assert click.prompt is click_prompt
+
+
+def test_sends_chunked_messages_not_exceeding_message_length_limit(subject, smalld):
+    @click.command()
+    def command():
+        click.echo("a" * 3000)
+
+    subject.cli = command
+
+    subject.on_message(make_message("command"))
+
+    assert smalld.post.call_count == 2
+    smalld.post.assert_has_calls(
+        [
+            call(POST_MESSAGE_ROUTE, {"content": "a" * 2000}),
+            call(POST_MESSAGE_ROUTE, {"content": "a" * 1000 + "\n"}),
+        ]
+    )
Repository: barrust/pyspellchecker

Issue:
load_words is not prioritized
Looks like the functionality load_words is not prioritized in the spellchecking.

```
from spellchecker import SpellChecker

known_words = ['covid', 'Covid19']

spell = SpellChecker(language='en')
spell.word_frequency.load_words(known_words)


word = 'coved'
misspelled = spell.unknown(word)
print(spell.correction(allwords))
```

the output of this is `loved`

Comments:

Patch:
diff --git a/spellchecker/spellchecker.py b/spellchecker/spellchecker.py
index 760b9c2..7c2fb8e 100644
--- a/spellchecker/spellchecker.py
+++ b/spellchecker/spellchecker.py
@@ -471,13 +471,14 @@ class WordFrequency(object):
         self._dictionary.update([word if self._case_sensitive else word.lower() for word in words])
         self._update_dictionary()
 
-    def add(self, word: KeyT) -> None:
+    def add(self, word: KeyT, val: int = 1) -> None:
         """Add a word to the word frequency list
 
         Args:
-            word (str): The word to add"""
+            word (str): The word to add
+            val (int): The number of times to insert the word"""
         word = ensure_unicode(word)
-        self.load_words([word])
+        self.load_json({word if self._case_sensitive else word.lower(): val})
 
     def remove_words(self, words: typing.Iterable[KeyT]) -> None:
         """Remove a list of words from the word frequency list


Test patch:
diff --git a/tests/spellchecker_test.py b/tests/spellchecker_test.py
index 2e3ee57..e9db470 100644
--- a/tests/spellchecker_test.py
+++ b/tests/spellchecker_test.py
@@ -269,6 +269,13 @@ class TestSpellChecker(unittest.TestCase):
         spell.word_frequency.add("appt")
         self.assertEqual(spell["appt"], 1)
 
+    def test_add_word_priority(self):
+        """test adding a word with larger priority"""
+        spell = SpellChecker()
+        self.assertEqual(spell["appt"], 0)
+        spell.word_frequency.add("appt", 5000)
+        self.assertEqual(spell["appt"], 5000)
+
     def test_checking_odd_word(self):
         """test checking a word that is really a number"""
         spell = SpellChecker()
@@ -334,7 +341,7 @@ class TestSpellChecker(unittest.TestCase):
     def test_large_words(self):
         """test checking for words that are clearly larger than the largest dictionary word"""
         spell = SpellChecker(language=None, distance=2)
-        spell.word_frequency.add("Bob")
+        spell.word_frequency.add("Bob", 1)
 
         words = ["Bb", "bb", "BB"]
         self.assertEqual(spell.unknown(words), {"bb"})
Repository: beetbox/beets

Issue:
"the" plugin uses incorrect regex
### Problem

Running this command:

```sh
~ ❯ beet move artist:trance -p
Moving 40 items.
M:\TET - Travailleur En Trance\[2008] Cobra Coded Escalation\01-01 - Cobra Reporting In.mp3
  -> M:\‒ Travailleur En Trance, TET\[2008] Cobra Coded Escalation\01-01 - Cobra Reporting In.mp3
```

Led to this problem:

"TET" is recognized by the "the" plugin as something it should move. This is because the regex used in the.py, line 26, is
```
PATTERN_THE = u'^[the]{3}\\s'
```
which matches "TET". It should probably be:
```
PATTERN_THE = u'^the\\s'
```

### Setup

* OS: Windows 10 2004
* Python version: 3.8
* beets version: latest trunk
* Turning off plugins made problem go away (yes/no): obviously, if I disable 'the' it no longer does this


Comments:

Patch:
diff --git a/beetsplug/the.py b/beetsplug/the.py
index 238aec32..dfc58817 100644
--- a/beetsplug/the.py
+++ b/beetsplug/the.py
@@ -23,7 +23,7 @@ from beets.plugins import BeetsPlugin
 __author__ = 'baobab@heresiarch.info'
 __version__ = '1.1'
 
-PATTERN_THE = u'^[the]{3}\\s'
+PATTERN_THE = u'^the\\s'
 PATTERN_A = u'^[a][n]?\\s'
 FORMAT = u'{0}, {1}'
 
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 64e6ab85..4a87f7f0 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -145,6 +145,9 @@ New features:
 
 Fixes:
 
+* :doc:`/plugins/the`: Fixed incorrect regex for 'the' that matched any
+  3-letter combination of the letters t, h, e.
+  :bug:`3701`
 * :doc:`/plugins/fetchart`: Fixed a bug that caused fetchart to not take
   environment variables such as proxy servers into account when making requests
   :bug:`3450`


Test patch:
diff --git a/test/test_the.py b/test/test_the.py
index 263446b9..1fc48895 100644
--- a/test/test_the.py
+++ b/test/test_the.py
@@ -36,6 +36,8 @@ class ThePluginTest(_common.TestCase):
                          u'A Thing, An')
         self.assertEqual(ThePlugin().unthe(u'the An Arse', PATTERN_A),
                          u'the An Arse')
+        self.assertEqual(ThePlugin().unthe(u'TET - Travailleur', PATTERN_THE),
+                         u'TET - Travailleur')
 
     def test_unthe_with_strip(self):
         config['the']['strip'] = True
Repository: beetbox/confuse

Issue:
as_template does not convert float
If it encounters an integer, it will convert it to an integer type validator
https://github.com/beetbox/confuse/blob/5528e7ae70850be07ecaca25826c972c195ee90b/confuse.py#L1666-L1669

If it encounters a float, it throws an error
https://github.com/beetbox/confuse/blob/5528e7ae70850be07ecaca25826c972c195ee90b/confuse.py#L1682-L1683
```
  File "/usr/local/lib/python3.7/dist-packages/confuse.py", line 1665, in as_template
    return MappingTemplate(value)
  File "/usr/local/lib/python3.7/dist-packages/confuse.py", line 1209, in __init__
    subtemplates[key] = as_template(typ)
  File "/usr/local/lib/python3.7/dist-packages/confuse.py", line 1665, in as_template
    return MappingTemplate(value)
  File "/usr/local/lib/python3.7/dist-packages/confuse.py", line 1209, in __init__
    subtemplates[key] = as_template(typ)
  File "/usr/local/lib/python3.7/dist-packages/confuse.py", line 1665, in as_template
    return MappingTemplate(value)
  File "/usr/local/lib/python3.7/dist-packages/confuse.py", line 1209, in __init__
    subtemplates[key] = as_template(typ)
  File "/usr/local/lib/python3.7/dist-packages/confuse.py", line 1693, in as_template
    raise ValueError(u'cannot convert to template: {0!r}'.format(value))
ValueError: cannot convert to template: 0.5
```

Comments:

Patch:
diff --git a/confuse.py b/confuse.py
index 8d5d875..5ec3936 100644
--- a/confuse.py
+++ b/confuse.py
@@ -1681,6 +1681,8 @@ def as_template(value):
         return OneOf(value)
     elif value is float:
         return Number()
+    elif isinstance(value, float):
+        return Number(value)
     elif value is None:
         return Template()
     elif value is dict:


Test patch:
diff --git a/test/test_valid.py b/test/test_valid.py
index f1452f3..f5a520f 100644
--- a/test/test_valid.py
+++ b/test/test_valid.py
@@ -163,6 +163,11 @@ class AsTemplateTest(unittest.TestCase):
         self.assertIsInstance(typ, confuse.Number)
         self.assertEqual(typ.default, confuse.REQUIRED)
 
+    def test_concrete_float_as_template(self):
+        typ = confuse.as_template(2.)
+        self.assertIsInstance(typ, confuse.Number)
+        self.assertEqual(typ.default, 2.)
+
     def test_none_as_template(self):
         typ = confuse.as_template(None)
         self.assertIs(type(typ), confuse.Template)
Repository: beetbox/confuse

Issue:
None as Template should use None as default
When I do this for a key that doesn't exist in `config_default.yaml`, I would expect the key to contain `None` by default.
```python
config['something'].get({
    'key': None
})
```

But instead, I get:
```
confuse.NotFoundError: something.key not found
```

This is because of this line in `as_template`:
https://github.com/beetbox/confuse/blob/b82d3faacb972b8964487a648805c3d0e06c0212/confuse.py#L1718-L1719

What I would propose:
```python
# throws NotFoundError - '...' is often used to denote a missing value
config['something'].get({
    'key': ...
})

# returns None
config['something'].get({
    'key': None
})
```

Comments:

Patch:
diff --git a/confuse/core.py b/confuse/core.py
index 193bfc3..5015705 100644
--- a/confuse/core.py
+++ b/confuse/core.py
@@ -335,7 +335,7 @@ class ConfigView(object):
                     od[key] = view.get()
         return od
 
-    def get(self, template=None):
+    def get(self, template=templates.REQUIRED):
         """Retrieve the value for this view according to the template.
 
         The `template` against which the values are checked can be
diff --git a/confuse/templates.py b/confuse/templates.py
index 640ba66..984c341 100644
--- a/confuse/templates.py
+++ b/confuse/templates.py
@@ -626,6 +626,8 @@ def as_template(value):
     elif isinstance(value, float):
         return Number(value)
     elif value is None:
+        return Template(None)
+    elif value is REQUIRED:
         return Template()
     elif value is dict:
         return TypeTemplate(abc.Mapping)
diff --git a/docs/index.rst b/docs/index.rst
index 64f9d69..b8ac11b 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -393,6 +393,10 @@ v1.3.0
 
 - Break up the `confuse` module into a package. (All names should still be
   importable from `confuse`.)
+- When using `None` as a template, the result is a value whose default is
+  `None`. Previously, this was equivalent to leaving the key off entirely,
+  i.e., a template with no default. To get the same effect now, use
+  `confuse.REQUIRED` in the template.
 
 v1.2.0
 ''''''


Test patch:
diff --git a/test/test_valid.py b/test/test_valid.py
index ec7cf6b..4ba8125 100644
--- a/test/test_valid.py
+++ b/test/test_valid.py
@@ -171,6 +171,11 @@ class AsTemplateTest(unittest.TestCase):
     def test_none_as_template(self):
         typ = confuse.as_template(None)
         self.assertIs(type(typ), confuse.Template)
+        self.assertEqual(typ.default, None)
+
+    def test_required_as_template(self):
+        typ = confuse.as_template(confuse.REQUIRED)
+        self.assertIs(type(typ), confuse.Template)
         self.assertEqual(typ.default, confuse.REQUIRED)
 
     def test_dict_type_as_template(self):
Repository: benjamincorcoran/sasdocs

Issue:
datasteps without a set or merge statement
# Issue

Currently only datasteps with a `set` or `merge` statement are parsed. However this does not account for `datalines` and `cards` statements, as well as `infile` statements

```sas
data a;
    input a;
    datalines;
1
;
run;
```
Should produce `dataStep` object with single output of `dataObject: a`

Comments:

Patch:
diff --git a/sasdocs/objects.py b/sasdocs/objects.py
index 122120d..8b954ba 100644
--- a/sasdocs/objects.py
+++ b/sasdocs/objects.py
@@ -718,8 +718,8 @@ dataLine = dataObj.sep_by(spc)
 
 datastep = ps.seq(
     outputs = (ps.regex(r'data', flags=re.IGNORECASE) + spc) >> dataLine << col,
-    header = ps.regex(r'.*?(?=set|merge)', flags=reFlags),
-    inputs = (opspc + ps.regex(r'set|merge',flags=re.IGNORECASE) + opspc) >> dataLine << col,
+    header = (ps.regex(r'.*?(?=set|merge)', flags=reFlags)).optional(),
+    inputs = ((opspc + ps.regex(r'set|merge',flags=re.IGNORECASE) + opspc) >> dataLine << col).optional(),
     body = ps.regex(r'.*?(?=run)', flags=reFlags),
     _run = run + opspc + col
 ).combine_dict(dataStep)


Test patch:
diff --git a/tests/test_objects.py b/tests/test_objects.py
index ece6658..8e46ebf 100644
--- a/tests/test_objects.py
+++ b/tests/test_objects.py
@@ -51,7 +51,8 @@ def test_dataLine_parse(case, expected):
     assert dataLine.parse(case) == expected
 
 testcases = [
-    ("data test.test lib2.test(where=(ax=b) rename=(a=b)); format a; set test; a = 1; b = 2; output; run;", dataStep(outputs=[dataObject(library=['test'], dataset=['test'], options=None), dataObject(library=['lib2'], dataset=['test'], options=[dataArg(option=['where'], setting='(ax=b)'), dataArg(option=['rename'], setting='(a=b)')])], header=' format a; ', inputs=[dataObject(library=None, dataset=['test'], options=None)], body=' a = 1; b = 2; output; '))
+    ("data test.test lib2.test(where=(ax=b) rename=(a=b)); format a; set test; a = 1; b = 2; output; run;", dataStep(outputs=[dataObject(library=['test'], dataset=['test'], options=None), dataObject(library=['lib2'], dataset=['test'], options=[dataArg(option=['where'], setting='(ax=b)'), dataArg(option=['rename'], setting='(a=b)')])], header=' format a; ', inputs=[dataObject(library=None, dataset=['test'], options=None)], body=' a = 1; b = 2; output; ')),
+    ("data out; input a; datalines; 1; run;", dataStep(outputs=[dataObject(library=None,dataset=['out'],options=None)],inputs=None,header=None,body=' input a; datalines; 1; '))
 ]
 
 @pytest.mark.parametrize("case,expected", testcases)
Repository: benjamincorcoran/sasdocs

Issue:
Parse calls to macros
# Issue

Call to macros are not parsed and so drop the over all parsed percentage for the sasProgram. Must be careful not to capture macro language as macro calls 

```sas
/*This*/
%runMacro;

/*Not this*/
%put;
```

Comments:

Patch:
diff --git a/sasdocs/objects.py b/sasdocs/objects.py
index 3958f48..0ec2506 100644
--- a/sasdocs/objects.py
+++ b/sasdocs/objects.py
@@ -650,6 +650,33 @@ class macro(baseSASObject):
         self.shortDesc = re.sub(r'\s+',' ',self.shortDesc)       
 
 
+@attr.s
+class macroCall(baseSASObject):
+    """
+    Abstracted python class for SAS macro call.
+    
+    This class parses a SAS macro call. 
+
+    .. code-block:: sas
+
+        %runMacro;
+        
+        /*and*/
+
+        %runMacro(arg1=A);
+
+
+    Attributes
+    ----------
+    name : str 
+        Name of the marco
+    arguments : list, optional
+        List of macroarguments parsed from the macro defintion
+    """
+    name = attr.ib()
+    arguments = attr.ib()
+
+
 # Parsy Objects
 # Define reFlags as ignorecase and dotall to capture new lines
 reFlags = re.IGNORECASE|re.DOTALL
@@ -845,6 +872,12 @@ mcroStart = ps.seq(
 
 mcroEnd = (ps.regex(r'%mend.*?;',flags=re.IGNORECASE)).map(macroEnd)
 
+mcroCall = ps.seq(
+    name = ps.regex(r'%') >> sasName,
+    arguments = (opspc >> mcroargline).optional(),
+    _col = opspc + col
+).combine_dict(macroCall)
+
 # fullprogram: multiple SAS objects including macros
-fullprogram =  (nl|mcvDef|cmnt|datastep|proc|sql|lbnm|icld|mcroStart|mcroEnd).optional()
+fullprogram =  (nl|mcvDef|cmnt|datastep|proc|sql|lbnm|icld|mcroStart|mcroEnd|mcroCall).optional()
 


Test patch:
diff --git a/tests/test_objects.py b/tests/test_objects.py
index 352ad42..03e1f5f 100644
--- a/tests/test_objects.py
+++ b/tests/test_objects.py
@@ -224,6 +224,18 @@ def test_macro_children_parse(case, expected):
     assert force_partial_parse(fullprogram, case)[0].contents == expected
 
 
+testcases = [
+    (r'%runMacro;',macroCall(name=['runMacro'], arguments=None)),
+    (r"%runMacro(A=B, C=D);",macroCall(name=['runMacro'], arguments=[macroargument(arg=['A'],default=["B"],doc=None),macroargument(arg=['C'],default=["D"],doc=None)]))
+]
+
+@pytest.mark.parametrize("case,expected", testcases)
+def test_macro_call_parse(case, expected):
+    assert mcroCall.parse(case) == expected
+
+
+
+
 testcases = [("""
 libname a "path/to/folder";
 %let a = 1;
Repository: benjamincorcoran/sasdocs

Issue:
Multiple outputs in procedures 
# Issue 

Current parser does not capture multiple outputs in procedures.
```sas
proc summary data=test;
    class a;
    var b;
    output out=sum sum=;
    output out=cnt n=;
run;
```




Comments:

Patch:
diff --git a/sasdocs/objects.py b/sasdocs/objects.py
index 0271f3c..59edb38 100644
--- a/sasdocs/objects.py
+++ b/sasdocs/objects.py
@@ -812,7 +812,7 @@ proc = ps.seq(
     _h1 = ps.regex(r'.*?(?=data)', flags=reFlags),
     inputs = (ps.regex(r'data', flags=re.IGNORECASE) + opspc + eq + opspc) >> dataObj,
     _h2 = ps.regex(r'.*?(?=out\s*=)', flags=reFlags).optional(),
-    outputs = ((ps.regex(r'out', flags=re.IGNORECASE) + opspc + eq + opspc) >> dataObj).optional(),
+    outputs = ((ps.regex(r'out', flags=re.IGNORECASE) + opspc + eq + opspc) >> dataObj).sep_by(ps.regex(r'(?:(?!run|quit).)*?(?=out\s*=)', flags=reFlags)).optional(),
     _h3 = ps.regex(r'.*?(?=run|quit)', flags=reFlags),
     _run = (run|qt) + opspc + col
 ).combine_dict(procedure)


Test patch:
diff --git a/tests/test_objects.py b/tests/test_objects.py
index 2eeba96..1b82569 100644
--- a/tests/test_objects.py
+++ b/tests/test_objects.py
@@ -69,7 +69,9 @@ def test_dataStep_parse(case, expected):
 
 
 testcases = [
-    ("proc summary data=lib2.test(where=(ax=b) rename=(a=b)); by x; output out=lib3.test2; run;", procedure(outputs=dataObject(library=['lib3'], dataset=['test2'], options=None), inputs=dataObject(library=['lib2'], dataset=['test'], options=[dataArg(option=['where'], setting='(ax=b)'), dataArg(option=['rename'], setting='(a=b)')]), type='summary'))
+    ("proc summary data=lib2.test(where=(ax=b) rename=(a=b)); by x; output out=lib3.test2; run;", procedure(outputs=dataObject(library=['lib3'], dataset=['test2'], options=None), inputs=dataObject(library=['lib2'], dataset=['test'], options=[dataArg(option=['where'], setting='(ax=b)'), dataArg(option=['rename'], setting='(a=b)')]), type='summary')),
+    ("proc summary data=lib2.test(where=(ax=b) rename=(a=b)); by x; output out=lib3.test2; out=lib4.test2; run;", procedure(outputs=[dataObject(library=['lib3'], dataset=['test2'], options=None), dataObject(library=['lib4'], dataset=['test2'], options=None)], inputs=dataObject(library=['lib2'], dataset=['test'], options=[dataArg(option=['where'], setting='(ax=b)'), dataArg(option=['rename'], setting='(a=b)')]), type='summary')),
+    ("proc summary data=lib2.test(where=(ax=b) rename=(a=b)); by x; output out=lib3.test2 sum=; out=lib4.test2 n=; run;", procedure(outputs=[dataObject(library=['lib3'], dataset=['test2'], options=None), dataObject(library=['lib4'], dataset=['test2'], options=None)], inputs=dataObject(library=['lib2'], dataset=['test'], options=[dataArg(option=['where'], setting='(ax=b)'), dataArg(option=['rename'], setting='(a=b)')]), type='summary'))
 ]
 
 @pytest.mark.parametrize("case,expected", testcases)
Repository: benjamincorcoran/sasdocs

Issue:
Give Macro object an about attribute
# Issue

Macro object needs an `about` attribute capturing the documentation of the macro variable. This should be the first set of comments *inside* the macro. The comments need to be collapsed into a single string object. 

Comments:

Patch:
diff --git a/sasdocs/objects.py b/sasdocs/objects.py
index b625e6e..5208195 100644
--- a/sasdocs/objects.py
+++ b/sasdocs/objects.py
@@ -507,6 +507,19 @@ class macro:
 
     def __attrs_post_init__(self):
         self.contents = [obj for obj in self.contents if obj != '\n']
+        about = []
+        for obj in self.contents:
+            if type(obj).__name__ == 'comment':
+                about.append(obj)
+            else:
+                break
+        if len(about) == 0:
+            self.about = 'No docstring found.'
+            self.documented = False
+        else:
+            self.about = '\n'.join([comment.text for comment in about])
+            self.documented = True
+        
 
 
 # Parsy Objects


Test patch:
diff --git a/tests/test_objects.py b/tests/test_objects.py
index 7249a1f..515899d 100644
--- a/tests/test_objects.py
+++ b/tests/test_objects.py
@@ -149,10 +149,20 @@ testcases = [
 ]
 
 @pytest.mark.parametrize("case,expected", testcases)
-def test_macro_parse(case, expected):
-
+def test_macro_about_parse(case, expected):
     assert force_partial_parse(fullprogram, case) == [expected]
 
+testcases = [
+    ('%macro test; /*This is the test macro*/ %mend;', 'This is the test macro'),
+    ('%macro test; /*This is the test macro*/\n/*This is the second line*/%mend;', 'This is the test macro\nThis is the second line'),
+    ('%macro test; data a; set b; run; /*This is the test macro*/ %mend;', 'No docstring found.'),
+]
+
+@pytest.mark.parametrize("case,expected", testcases)
+def test_macro_parse(case, expected):
+    macro = force_partial_parse(fullprogram,case)[0]
+    assert macro.about == expected
+
 testcases = [
     ('%macro test; data a; set b; run; %mend;', [dataStep(outputs=[dataObject(library=None, dataset=['a'], options=None)], header=' ', inputs=[dataObject(library=None, dataset=['b'], options=None)], body=' ')]),
     ('%macro test(a=1/*Doc A*/,b/*Doc B*/); data a; set b; run; %mend;', [dataStep(outputs=[dataObject(library=None, dataset=['a'], options=None)], header=' ', inputs=[dataObject(library='work', dataset=['b'])], body=' ')]),