nebius/SWE-bench-extra huggingface dataset:
Repository: swen128/twitter-text-python

Issue:
[Bug] "\r\n" を2文字としてカウントするバグ
Tweet API を使用していて、ツイッターをブラウザで開いてツイートできる文字数なのに、parse_tweet関数を使用すると文字数オーバーとなる奇妙な現象に遭遇・・・。

おそらく"\r" を改行として取得できていません。
以下のテストコードを見て下さい。

```
from twitter_text import parse_tweet

text1 = '''abc
def
ghi'''
print(text1)
print(parse_tweet(text1))
print()

text2 = 'abc\ndef\nghi'
print(text2)
print(parse_tweet(text2))
print()

text3 = 'abc\rdef\rghi'
print(text3)
print(parse_tweet(text3))
print()

text4 = 'abc\r\ndef\r\nghi'
print(text4)
print(parse_tweet(text4))
```

結果は次のようになります。
```
abc
def
ghi
ParsedResult(valid=True, weightedLength=11, permillage=39, validRangeStart=0, validRangeEnd=10, displayRangeStart=0, displayRangeEnd=10)

abc
def
ghi
ParsedResult(valid=True, weightedLength=11, permillage=39, validRangeStart=0, validRangeEnd=10, displayRangeStart=0, displayRangeEnd=10)

ghi
ParsedResult(valid=True, weightedLength=11, permillage=39, validRangeStart=0, validRangeEnd=10, displayRangeStart=0, displayRangeEnd=10)

abc
def
ghi
ParsedResult(valid=True, weightedLength=13, permillage=46, validRangeStart=0, validRangeEnd=12, displayRangeStart=0, displayRangeEnd=12)
```
改行文字を1文字として取得しているならば、
"weightedLength=11"が正しく、それ以外は間違っています。
修正して下さい。

Comments:

Patch:
diff --git a/twitter_text/parse_tweet.py b/twitter_text/parse_tweet.py
index ffa4f3e..db0d7cb 100644
--- a/twitter_text/parse_tweet.py
+++ b/twitter_text/parse_tweet.py
@@ -1,3 +1,4 @@
+import re
 import unicodedata
 from math import floor
 from typing import List, Dict
@@ -25,6 +26,10 @@ class ParsedResult:
         return attr.asdict(self)
 
 
+def convert_line_ending(string, to="\n"):
+    return re.sub(r'\r\n|\r|\n', to, string)
+
+
 def parse_tweet(text: str, options: dict = config['defaults']) -> ParsedResult:
     """
     Parse a Twitter text according to https://developer.twitter.com/en/docs/developer-utilities/twitter-text
@@ -106,7 +111,7 @@ def parse_tweet(text: str, options: dict = config['defaults']) -> ParsedResult:
     emoji_parsing_enabled = options['emoji_parsing_enabled']
     max_weighted_tweet_length = options['max_weighted_tweet_length']
 
-    normalized_text = unicodedata.normalize('NFC', text)
+    normalized_text = convert_line_ending(unicodedata.normalize('NFC', text))
 
     url_entities_map = transform_entities_to_hash(extract_urls_with_indices(normalized_text))
     emoji_entities_map = transform_entities_to_hash(extract_emojis_with_indices(normalized_text))


Test patch:
diff --git a/tests/cases/added.yml b/tests/cases/added.yml
index b20b36d..1391e2f 100644
--- a/tests/cases/added.yml
+++ b/tests/cases/added.yml
@@ -6,6 +6,16 @@ tests:
         - url: "https://t.co/slug"
           indices: [0, 17]
   ParseTweet:
+    - description: "CRLF character"
+      text: "a\r\nb"
+      expected:
+        weightedLength: 3
+        valid: true
+        permillage: 10
+        displayRangeStart: 0
+        displayRangeEnd: 3
+        validRangeStart: 0
+        validRangeEnd: 3
     - description: "A URL containing emojis"
       text: "https://😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷😷.jp"
       expected:
Repository: tableau/server-client-python

Issue:
Pager with users throws TypeError
I am trying to extract the list of users using the Pager:
`print(*TSC.Pager(tableau.users))`

I get the following error:

`  File "metalab_users.py", line 74, in <module>
    print(*tableau_users)
  File "C:\Program Files\Python35\lib\site-packages\tableauserverclient\server\pager.py", line 30, in __iter__
    yield current_item_list.pop(0)
TypeError: pop() takes no arguments (1 given)`

When calling projects with the same code, I get no such error:
`print(*TSC.Pager(tableau.projects))`

Comments:

Patch:
diff --git a/tableauserverclient/models/user_item.py b/tableauserverclient/models/user_item.py
index 1e4f54a..2df6764 100644
--- a/tableauserverclient/models/user_item.py
+++ b/tableauserverclient/models/user_item.py
@@ -119,7 +119,7 @@ class UserItem(object):
 
     @classmethod
     def from_response(cls, resp):
-        all_user_items = set()
+        all_user_items = []
         parsed_response = ET.fromstring(resp)
         all_user_xml = parsed_response.findall('.//t:user', namespaces=NAMESPACE)
         for user_xml in all_user_xml:
@@ -128,7 +128,7 @@ class UserItem(object):
             user_item = cls(name, site_role)
             user_item._set_values(id, name, site_role, last_login, external_auth_user_id,
                                   fullname, email, auth_setting, domain_name)
-            all_user_items.add(user_item)
+            all_user_items.append(user_item)
         return all_user_items
 
     @staticmethod


Test patch:
diff --git a/test/test_user.py b/test/test_user.py
index 556cd62..fa83443 100644
--- a/test/test_user.py
+++ b/test/test_user.py
@@ -54,7 +54,7 @@ class UserTests(unittest.TestCase):
             all_users, pagination_item = self.server.users.get()
 
         self.assertEqual(0, pagination_item.total_available)
-        self.assertEqual(set(), all_users)
+        self.assertEqual([], all_users)
 
     def test_get_before_signin(self):
         self.server._auth_token = None
Repository: tarohi24/typedflow

Issue:
Batch doesn't flow if any items in it has an error
even if the majority isn't troublesome

Comments:

Patch:
diff --git a/typedflow/typedflow.py b/typedflow/typedflow.py
index 8185bd6..b6dc426 100644
--- a/typedflow/typedflow.py
+++ b/typedflow/typedflow.py
@@ -19,6 +19,10 @@ T = TypeVar('T')  # serializable
 K = TypeVar('K')  # serializable
 
 
+class BatchIsEmpty(Exception):
+    pass
+
+
 @dataclass
 class Batch(Generic[T]):
     batch_id: int
@@ -31,8 +35,18 @@ class Task(Generic[T, K]):
 
     def process(self,
                 batch: Batch[T]) -> Batch[K]:
-        lst: List[K] = [self.func(item) for item in batch.data]
-        return Batch(batch_id=batch.batch_id, data=lst)
+        products: List[K] = []
+        for item in batch.data:
+            try:
+                products.append(self.func(item))
+            except Exception as e:
+                logger.warn(repr(e))
+                continue
+        if len(products) > 0:
+            return Batch[K](batch_id=batch.batch_id,
+                            data=products)
+        else:
+            raise BatchIsEmpty()
 
 
 @dataclass
@@ -97,7 +111,6 @@ class Pipeline:
         for batch in self.loader.load():
             try:
                 product: Batch = _run(batch, self.pipeline)
-            except Exception as e:
-                logger.warn(repr(e))
+            except BatchIsEmpty:
                 continue
             self.dumper.dump(product)


Test patch:
diff --git a/typedflow/tests/typedflow/test_task.py b/typedflow/tests/typedflow/test_task.py
index 3294062..93e6463 100644
--- a/typedflow/tests/typedflow/test_task.py
+++ b/typedflow/tests/typedflow/test_task.py
@@ -77,7 +77,7 @@ def test_process(pl, capsys):
 def test_except_batch(invalid_pl, capsys):
     invalid_pl.run()
     out, _ = capsys.readouterr()
-    assert out == ''
+    assert out == '15\n12\n'
 
 
 def test_multibatch_process(mutlibatch_pl, capsys):
Repository: tarohi24/typedflow

Issue:
The new syntax doesn't work
It doesn't accept args in the correct way. For instance, life of cache tables are never incremented.

Comments:

Patch:
diff --git a/typedflow/nodes/base.py b/typedflow/nodes/base.py
index ece0895..b9853f9 100644
--- a/typedflow/nodes/base.py
+++ b/typedflow/nodes/base.py
@@ -113,7 +113,8 @@ class ConsumerNode:
         None
         """
         assert len(self.precs) == 0, 'Some arguments have been already set'
-        self.precs: Dict[str, ProviderNode] = args
+        for name, prec in args.items():
+            self.set_upstream_node(name, prec)
         return self
 
 


Test patch:
diff --git a/typedflow/tests/flow/test_flow.py b/typedflow/tests/flow/test_flow.py
index aa31917..7682475 100644
--- a/typedflow/tests/flow/test_flow.py
+++ b/typedflow/tests/flow/test_flow.py
@@ -209,3 +209,4 @@ def test_declare_inputs_when_definition_with_multiple_args():
     node_dump = DumpNode(dump)({'a': node_task})
     flow = Flow([node_dump, ])
     flow.typecheck()
+    assert node_task.cache_table.life == 1
Repository: tefra/xsdata

Issue:
XmlSerializer render empty nillable tokens lists

Comments:

Patch:
diff --git a/xsdata/formats/dataclass/serializers/xml.py b/xsdata/formats/dataclass/serializers/xml.py
index 487ce89d..7a0e88f7 100644
--- a/xsdata/formats/dataclass/serializers/xml.py
+++ b/xsdata/formats/dataclass/serializers/xml.py
@@ -161,8 +161,8 @@ class XmlSerializer(AbstractSerializer):
     def write_tokens(self, value: Any, var: XmlVar, namespace: NoneStr) -> Generator:
         """Produce an events stream for the given tokens list or list of tokens
         lists."""
-        if value:
-            if isinstance(value[0], list):
+        if value or var.nillable:
+            if value and isinstance(value[0], list):
                 for val in value:
                     yield from self.write_element(val, var, namespace)
             else:


Test patch:
diff --git a/tests/formats/dataclass/serializers/test_xml.py b/tests/formats/dataclass/serializers/test_xml.py
index 10f1a9fe..7f065a9e 100644
--- a/tests/formats/dataclass/serializers/test_xml.py
+++ b/tests/formats/dataclass/serializers/test_xml.py
@@ -167,6 +167,17 @@ class XmlSerializerTests(TestCase):
         result = self.serializer.write_value([[1, 2, 3], [4, 5, 6]], var, "xsdata")
         self.assertEqual(expected, list(result))
 
+        var = XmlElement(qname="a", name="a", tokens=True, nillable=True)
+        expected = [
+            (XmlWriterEvent.START, "a"),
+            (XmlWriterEvent.ATTR, QNames.XSI_NIL, "true"),
+            (XmlWriterEvent.DATA, []),
+            (XmlWriterEvent.END, "a"),
+        ]
+
+        result = self.serializer.write_value([], var, "xsdata")
+        self.assertEqual(expected, list(result))
+
     def test_write_any_type_with_primitive(self):
         var = XmlWildcard(qname="a", name="a")
         expected = [(XmlWriterEvent.DATA, "str")]
Repository: tehmaze/ansi

Issue:
RGB background color support

hi!

Adding a switch to  `rgb256(r,g,b, bg=True)` you could return

```
if bg:
    return sequence('m', fields=3)(48, 5, colour)
else:
    return sequence('m', fields=3)(38, 5, colour)
```

Comments:

Patch:
diff --git a/ansi/colour/rgb.py b/ansi/colour/rgb.py
index 13fbc02..6eb1e29 100644
--- a/ansi/colour/rgb.py
+++ b/ansi/colour/rgb.py
@@ -56,7 +56,7 @@ def rgb16(r: int, g: int, b: int) -> str:
     return rgb_reduce(r, g, b, 16)
 
 
-def rgb256(r: int, g: int, b: int) -> str:
+def rgb256(r: int, g: int, b: int, bg: bool=False) -> str:
     """
     Convert an RGB colour to 256 colour ANSI graphics.
 
@@ -79,4 +79,4 @@ def rgb256(r: int, g: int, b: int) -> str:
         colour = sum([16] + [int(6 * float(val) / 256) * mod
                              for val, mod in ((r, 36), (g, 6), (b, 1))])
 
-    return sequence('m', fields=3)(38, 5, colour)
+    return sequence('m', fields=3)(38 if not bg else 48, 5, colour)


Test patch:
diff --git a/test_ansi.py b/test_ansi.py
index a12d704..a15a75e 100644
--- a/test_ansi.py
+++ b/test_ansi.py
@@ -40,6 +40,11 @@ def test_rgb() -> None:
     msg = (rgb256(0xff, 0x80, 0x00), 'hello world', reset)
     assert ''.join(map(str, msg)) == '\x1b[38;5;214mhello world\x1b[0m'
 
+def test_rgb_bg() -> None:
+    from ansi.colour.rgb import rgb256
+    from ansi.colour.fx import reset
+    msg = (rgb256(0xff, 0x80, 0x00, bg=True), 'hello world', reset)
+    assert ''.join(map(str, msg)) == '\x1b[48;5;214mhello world\x1b[0m'
 
 def test_osc() -> None:
     from ansi import osc
Repository: terrencepreilly/darglint

Issue:
I203 raised for return type annotations.
`darglint` raises an error (`I203 Return type mismatch:  ~Return: expected str but was `) when return type annotations are provided without a declared docstring return type. This is likely an oversight, this check should only fire if _both_ a type annotation and docstring type declaration are present.

Failure example:

```
def foo() -> str:
    """Just a standard foobar.

    Returns: Bar.
    
    """
    return "bar"
````

Comments:

Patch:
diff --git a/darglint/integrity_checker.py b/darglint/integrity_checker.py
index 729993d..1d24c0f 100644
--- a/darglint/integrity_checker.py
+++ b/darglint/integrity_checker.py
@@ -184,7 +184,7 @@ class IntegrityChecker(object):
         fun_type = self.function.return_type
         doc_type = self.docstring.get_types(Sections.RETURNS_SECTION)
         if not doc_type or isinstance(doc_type, list):
-            doc_type = ''
+            doc_type = None
         if fun_type is not None and doc_type is not None:
             if fun_type != doc_type:
                 line_numbers = self.docstring.get_line_numbers(


Test patch:
diff --git a/tests/test_integrity_checker.py b/tests/test_integrity_checker.py
index 53f6c8f..3d2b895 100644
--- a/tests/test_integrity_checker.py
+++ b/tests/test_integrity_checker.py
@@ -288,6 +288,40 @@ class IntegrityCheckerTestCase(TestCase):
         self.assertEqual(error.expected, 'int')
         self.assertEqual(error.actual, 'float')
 
+    def test_return_type_unchecked_if_not_defined_in_docstring(self):
+        program = '\n'.join([
+            'def foo() -> str:',
+            '    """Just a foobar.',
+            '',
+            '    Returns:',
+            '        bar',
+            '',
+            '    """',
+            '    return "bar"',
+        ])
+        tree = ast.parse(program)
+        functions = get_function_descriptions(tree)
+        checker = IntegrityChecker()
+        checker.run_checks(functions[0])
+        self.assertEqual(len(checker.errors), 0)
+
+    def test_return_type_unchecked_if_not_defined_in_function(self):
+        program = '\n'.join([
+            'def foo():',
+            '    """Just a foobar.',
+            '',
+            '    Returns:',
+            '        str: bar',
+            '',
+            '    """',
+            '    return "bar"',
+        ])
+        tree = ast.parse(program)
+        functions = get_function_descriptions(tree)
+        checker = IntegrityChecker()
+        checker.run_checks(functions[0])
+        self.assertEqual(len(checker.errors), 0)
+
     def test_return_type_checked_if_defined_in_docstring_and_function(self):
         program = '\n'.join([
             'def update_model(x: dict) -> dict:',
Repository: terryyin/lizard

Issue:
Lizard not handling functions within unions correctly
For the following code:

```c++
namespace foo{
	
	void myFunction() { }
	
	union bar{
		void mySecondFunction() { }
	};
	
	class dog{
		void bark() { }
	};
};
```

Lizard generates the following output:
![doxunionbug](https://user-images.githubusercontent.com/29785071/27710254-b019601a-5ce4-11e7-9706-da253a28276e.png)

This shows that the long_name generated by lizard includes the namespace or the class that a function is contained in but does not contain the union the function is contained in. This inconsistency can cause issues for code analysis tools.

Comments:

Patch:
diff --git a/lizard_languages/clike.py b/lizard_languages/clike.py
index 33e1c3d..2c1af01 100644
--- a/lizard_languages/clike.py
+++ b/lizard_languages/clike.py
@@ -155,7 +155,7 @@ class CLikeNestingStackStates(CodeStateMachine):
         if token == "template":
             self._state = self._template_declaration
 
-        elif token in ("struct", "class", "namespace"):
+        elif token in ("struct", "class", "namespace", "union"):
             self._state = self._read_namespace
 
         elif token == "{":


Test patch:
diff --git a/test/test_languages/testCAndCPP.py b/test/test_languages/testCAndCPP.py
index cd5569b..41a1b13 100644
--- a/test/test_languages/testCAndCPP.py
+++ b/test/test_languages/testCAndCPP.py
@@ -461,6 +461,11 @@ class Test_c_cpp_lizard(unittest.TestCase):
         self.assertEqual(1, len(result))
         self.assertEqual("A::foo", result[0].name)
 
+    def test_union_as_qualifier(self):
+        """Union as namespace for functions."""
+        result = get_cpp_function_list("union A { void foo() {} };")
+        self.assertEqual(1, len(result))
+        self.assertEqual("A::foo", result[0].name)
 
 class Test_cpp11_Attributes(unittest.TestCase):
     """C++11 extendable attributes can appear pretty much anywhere."""
Repository: testing-cabal/systemfixtures

Issue:
shutil.copytree to an overlayed dir fails under Python 3.8
When copying a tree to an overlayed dir, I get the following exception casued by `_is_fake_path` not handling DirEntry params:

```python
    shutil.copytree(CHARM_DIR, self.charm_dir)
  File "/usr/lib/python3.8/shutil.py", line 554, in copytree
    return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
  File "/usr/lib/python3.8/shutil.py", line 496, in _copytree
    copy_function(srcobj, dstname)
  File "/usr/lib/python3.8/shutil.py", line 432, in copy2
    copyfile(src, dst, follow_symlinks=follow_symlinks)
  File "/usr/lib/python3.8/shutil.py", line 261, in copyfile
    with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
  File "/home/nessita/canonical/franky/env/lib/python3.8/site-packages/systemfixtures/_overlay.py", line 23, in _new_value
    if self.condition(*args, **kwargs):
  File "/home/nessita/canonical/franky/env/lib/python3.8/site-packages/systemfixtures/filesystem.py", line 146, in _is_fake_path_or_fd
    return self._is_fake_path(path)
  File "/home/nessita/canonical/franky/env/lib/python3.8/site-packages/systemfixtures/filesystem.py", line 133, in _is_fake_path
    if path.startswith(prefix):
AttributeError: 'posix.DirEntry' object has no attribute 'startswith'
```

A possible fix would be something like this:

```python
    129             if isinstance(path, os.DirEntry):
    130                 path = path.name
```

Comments:

Patch:
diff --git a/systemfixtures/filesystem.py b/systemfixtures/filesystem.py
index 40d9da0..f26a3ee 100644
--- a/systemfixtures/filesystem.py
+++ b/systemfixtures/filesystem.py
@@ -12,6 +12,7 @@ if six.PY2:
     BUILTIN_OPEN = "__builtin__.open"
 if six.PY3:
     BUILTIN_OPEN = "builtins.open"
+    from os import DirEntry
 
 
 GENERIC_APIS = (
@@ -139,6 +140,8 @@ class FakeFilesystem(Fixture):
         def _is_fake_path_or_fd(self, path, *args, **kwargs):
             if isinstance(path, int):
                 path = self._path_from_fd(path)
+            elif isinstance(path, DirEntry):
+                path = path.name
             return self._is_fake_path(path)
 
     def _is_fake_symlink(self, src, dst, *args, **kwargs):


Test patch:
diff --git a/systemfixtures/tests/test_filesystem.py b/systemfixtures/tests/test_filesystem.py
index 5041bb0..ec3d26a 100644
--- a/systemfixtures/tests/test_filesystem.py
+++ b/systemfixtures/tests/test_filesystem.py
@@ -97,6 +97,12 @@ class FakeFilesystemTest(TestCase):
         shutil.rmtree("/foo/bar")
         self.assertEqual([], os.listdir("/foo"))
 
+    def test_copytree(self):
+        self.fs.add("/foo")
+        shutil.copytree("./doc", "/foo")
+        self.assertEqual(
+            sorted(os.listdir("./doc")), sorted(os.listdir("/foo")))
+
     if six.PY3:
 
         def test_listdir_with_fd(self):
Repository: textile/python-textile

Issue:
IndexError string index out of range on whitespace only string
When I try to process a string that is whitespace only, I get an `IndexError`:

```
In [1]: from textile import textile

In [2]: textile(' ')
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
```

Ref: https://github.com/textile/python-textile/issues/26

Comments:

Patch:
diff --git a/textile/core.py b/textile/core.py
index 692cca4..9c6623f 100644
--- a/textile/core.py
+++ b/textile/core.py
@@ -230,7 +230,7 @@ class Textile(object):
         self.unreferencedNotes = OrderedDict()
         self.notelist_cache = OrderedDict()
 
-        if text == '':
+        if text.strip() == '':
             return text
 
         if self.restricted:
@@ -811,7 +811,7 @@ class Textile(object):
             """If we find a closing square bracket we are going to see if it is
             balanced.  If it is balanced with matching opening bracket then it
             is part of the URL else we spit it back out of the URL."""
-            # If counts['['] is None, count the occurrences of '[' 
+            # If counts['['] is None, count the occurrences of '['
             counts['['] = counts['['] or url.count('[')
 
             if counts['['] == counts[']']:


Test patch:
diff --git a/tests/test_github_issues.py b/tests/test_github_issues.py
index bf9c339..b8a8330 100644
--- a/tests/test_github_issues.py
+++ b/tests/test_github_issues.py
@@ -91,3 +91,9 @@ def test_github_issue_36():
     result = textile.textile(text)
     expect = '\t<p><a href="https://www.google.com/search?q=Chögyam+Trungpa">Chögyam Trungpa</a></p>'
     assert result == expect
+
+def test_github_issue_40():
+    text = '\r\n'
+    result = textile.textile(text)
+    expect = '\r\n'
+    assert result == expect
Repository: theelous3/asks

Issue:
`request_object.RequestProcessor._dict_to_query` skips dict values evaluating to `False`
Test case:
```python
response = await asks.get('https://httpbin.org/get', params={
    'foo': 'bar',
    'zero': 0,
    'empty': '',
    'false': False
})

payload = response.json()

assert 'foo' in payload['args']  # OK
assert 'zero' in payload['args']  # Fail
assert 'empty' in payload['args']  # Fail
assert 'false' in payload['args']  # Fail
```

Erroneous code:
https://github.com/theelous3/asks/blob/733f277b7fa84e17afb4d8c3b0895bec7efb8ab4/asks/request_object.py#L442-L443


Comments:

Patch:
diff --git a/asks/request_object.py b/asks/request_object.py
index b9bfd32..6c05b00 100644
--- a/asks/request_object.py
+++ b/asks/request_object.py
@@ -424,7 +424,8 @@ class RequestProcessor:
 
         return c_type, str(len(body)), body
 
-    def _dict_to_query(self, data, params=True, base_query=False):
+    @staticmethod
+    def _dict_to_query(data, params=True, base_query=False):
         '''
         Turns python dicts in to valid body-queries or queries for use directly
         in the request url. Unlike the stdlib quote() and it's variations,
@@ -439,7 +440,7 @@ class RequestProcessor:
         query = []
 
         for k, v in data.items():
-            if not v:
+            if v is None:
                 continue
             if isinstance(v, (str, Number)):
                 query.append('='.join(quote_plus(x) for x in (k, str(v))))


Test patch:
diff --git a/tests/test_request_object.py b/tests/test_request_object.py
index 0f1c989..9627a99 100644
--- a/tests/test_request_object.py
+++ b/tests/test_request_object.py
@@ -1,6 +1,7 @@
 # pylint: disable=no-member
 
 import h11
+import pytest
 
 from asks.request_object import RequestProcessor
 
@@ -32,3 +33,13 @@ def test_http1_1(monkeypatch):
 def test_http1_0(monkeypatch):
     response = _catch_response(monkeypatch, [('Connection', 'close')], b'hello')
     assert response.body == b'hello'
+
+
+@pytest.mark.parametrize(['data', 'query_str'], [
+    [{'foo': 'bar', 'spam': None}, '?foo=bar'],
+    [{'zero': 0}, '?zero=0'],
+    [{'empty': ''}, '?empty='],
+    [{'false': False}, '?false=False'],
+])
+def test_dict_to_query(data, query_str):
+    assert RequestProcessor._dict_to_query(data) == query_str