Repository: leshchenko1979/fast_bitrix24
Pull request #73 (2020-10-14 22:41:44)

собственная реализация php.http_build_query

sourcery-ai[bot]: # Sourcery Code Quality Report


❌ &nbsp;Merging this PR will **decrease** code quality in the affected files by **2.02%**.

| Quality metrics | Before | After | Change |
| --- | :---: | :---: | :---: |
| [Complexity](https://github.com/sourcery-ai/sourcery/wiki/Quality-Report#complexity) | 0.38 ⭐ | 0.61 ⭐ | 0.23 👎 |
| [Method Length](https://github.com/sourcery-ai/sourcery/wiki/Quality-Report#method-length) | 28.33 ⭐ | 34.18 ⭐ | 5.85 👎 |
| [Working memory](https://github.com/sourcery-ai/sourcery/wiki/Quality-Report#method-length) | 5.79 ⭐ | 6.21 🙂 | 0.42 👎 |
| **[Quality](https://github.com/sourcery-ai/sourcery/wiki/Quality-Report#quality-score)** | **89.38%** ⭐| **87.36%** ⭐| **-2.02%** 👎 |



| Other metrics | Before | After | Change |
| --- | :---: | :---: | :---: |
| Lines | 174 | 268 | 94 |



| Changed files | Quality Before | Quality After | Quality Change |
| --- | :---: | :---: | :---: |
| fast_bitrix24/mult_request.py | 91.04% ⭐ | 91.18% ⭐ | 0.14% 👍|
| fast_bitrix24/test_.py | 84.44% ⭐ | 83.46% ⭐ | -0.98% 👎|
| fast_bitrix24/utils.py | 95.35% ⭐ | 85.64% ⭐ | -9.71% 👎|



Here are some functions in these files that still need a tune-up:

| File | Function | Complexity | Length | Working Memory | Quality | Recommendation |
| --- | --- | :---: | :---: | :---: | :---: | --- |
| fast_bitrix24/utils.py | http\_build\_query | 8 ⭐ | 110 🙂 | 12 😞 | 56.18% 🙂 | Extract out complex expressions |
| fast_bitrix24/mult_request.py | MultipleServerRequestHandler.prepare\_batches | 0  | 52 ⭐ | 17 ⛔ | 66.18% 🙂 | Extract out complex expressions |
| fast_bitrix24/test_.py | create\_100\_leads | 1 ⭐ | 82 🙂 | 10 😞 | 70.56% 🙂 | Extract out complex expressions |
| fast_bitrix24/test_.py | TestHttpBuildQuery.test\_original | 0  | 75 🙂 | 11 😞 | 70.70% 🙂 | Extract out complex expressions |
| fast_bitrix24/test_.py | TestParamsEncoding.test\_mobile\_phone | 0  | 60 ⭐ | 12 😞 | 71.27% 🙂 | Extract out complex expressions |


## Legend and Explanation

The emojis denote the absolute quality of the code:

 - ⭐ excellent
 - 🙂 good
 - 😞 poor
 - ⛔ very poor


The 👍 and 👎 indicate whether the quality has improved or gotten worse with this pull request.

***

Please see our documentation [here](https://github.com/sourcery-ai/sourcery/wiki/Quality-Report) for details on how these metrics are calculated.

We are actively working on this report - lots more documentation and extra metrics to come!

Let us know what you think of it by mentioning @sourcery-ai in a comment.

Patch:
diff --git a/fast_bitrix24/mult_request.py b/fast_bitrix24/mult_request.py
index 437460d..28b3513 100644
--- a/fast_bitrix24/mult_request.py
+++ b/fast_bitrix24/mult_request.py
@@ -1,5 +1,5 @@
 import more_itertools
-import php
+from .utils import http_build_query
 import itertools
 
 from .srh import BITRIX_MAX_BATCH_SIZE
@@ -25,13 +25,12 @@ class MultipleServerRequestHandler:
 
     def prepare_batches(self):
         batch_size = BITRIX_MAX_BATCH_SIZE
-        builder = php.Php()
 
         batches = [{
             'halt': 0,
             'cmd': {
                 self.batch_command_label(i, item): 
-                f'{self.method}?{builder.http_build_query(item)}'
+                f'{self.method}?{http_build_query(item)}'
                 for i, item in enumerate(next_batch)
             }}
             for next_batch in more_itertools.chunked(self.item_list, batch_size)
diff --git a/fast_bitrix24/utils.py b/fast_bitrix24/utils.py
index 4e6e0b5..783aef8 100644
--- a/fast_bitrix24/utils.py
+++ b/fast_bitrix24/utils.py
@@ -4,11 +4,11 @@
 #
 ##########################################
 
-import urllib
+from urllib.parse import quote, urlparse
 
 def _url_valid(url):
     try:
-        result = urllib.parse.urlparse(url)
+        result = urlparse(url)
         return all([result.scheme, result.netloc, result.path])
     except:
         return False
@@ -19,3 +19,30 @@ def _merge_dict(d1, d2):
     if d2:
         d3.update(d2)
     return d3
+
+
+def http_build_query(params, convention="%s"):
+    if len(params) == 0:
+        return ""
+
+    output = ""
+    for key in params.keys():
+
+        if type(params[key]) is dict:
+
+            output += http_build_query(params[key], convention % key + "[%s]")
+
+        elif type(params[key]) is list:
+
+            new_params = {str(i): element for i, element in enumerate(params[key])}
+
+            output += http_build_query(
+                new_params, convention % key + "[%s]")
+
+        else:
+
+            val = quote(str(params[key]))
+            key = quote(key)
+            output = output + convention % key + "=" + val + "&"
+
+    return output
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 09f39de..3ab3b06 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,4 @@
 aiohttp
 asyncio
 tqdm
-more_itertools
-php
\ No newline at end of file
+more_itertools
\ No newline at end of file


Test patch:
diff --git a/fast_bitrix24/test_.py b/fast_bitrix24/test_.py
index d260b58..f469ce1 100644
--- a/fast_bitrix24/test_.py
+++ b/fast_bitrix24/test_.py
@@ -1,3 +1,4 @@
+from .utils import http_build_query
 import os
 
 import pytest
@@ -86,7 +87,7 @@ class TestLongRequests:
         b.get_by_ID('crm.lead.delete', [lead_no])
         
         
-class TestEmbeddedListsInParams:
+class TestParamsEncoding:
     
     def test_mobile_phone(self, get_test):
         b = get_test
@@ -104,4 +105,81 @@ class TestEmbeddedListsInParams:
         try:
             assert lead['PHONE'][0]['VALUE_TYPE'] == 'MOBILE'
         finally:
-            b.get_by_ID('crm.lead.delete', [lead_no])
\ No newline at end of file
+            b.get_by_ID('crm.lead.delete', [lead_no])
+            
+
+    def test_filter_not_equal(self, create_100_leads):
+        b = create_100_leads
+
+        result = b.get_all('crm.lead.list', {
+            'FILTER': {
+                '!STATUS_ID': 'NEW'
+            }
+        })
+        assert not result
+            
+        result = b.get_all('crm.lead.list', {
+            'FILTER': {
+                '!STATUS_ID': 'CLOSED'
+            }
+        })
+        assert result
+            
+        result = b.get_all('crm.lead.list', {
+            'FILTER': {
+                '<>STATUS_ID': 'NEW'
+            }
+        })
+        assert result
+        
+        result = b.get_all('crm.lead.list', {
+            'FILTER': {
+                '<>STATUS_ID': 'CLOSED'
+            }
+        })
+        assert result
+
+
+class TestHttpBuildQuery:
+    
+    def test_original(self):
+        assert http_build_query ({"alpha": "bravo"}) == "alpha=bravo&"
+
+        test = http_build_query({"charlie": ["delta", "echo", "foxtrot"]})
+        assert "charlie[0]=delta" in test
+        assert "charlie[1]=echo" in test
+        assert "charlie[2]=foxtrot" in test
+
+        test = http_build_query({
+            "golf": [
+                "hotel",
+                {"india": "juliet", "kilo": ["lima", "mike"]},
+                "november", "oscar"
+            ]
+        })
+        assert "golf[0]=hotel" in test
+        assert "golf[1][india]=juliet" in test
+        assert "golf[1][kilo][0]=lima" in test
+        assert "golf[1][kilo][1]=mike" in test
+        assert "golf[2]=november" in test
+        assert "golf[3]=oscar" in test
+
+
+    def test_new(self):
+        d = {
+            'FILTER': {
+                'STATUS_ID': 'CLOSED'
+            }
+        }
+        
+        test = http_build_query(d)
+        assert test == 'FILTER[STATUS_ID]=CLOSED&' 
+        
+        d = {
+            'FILTER': {
+                '!STATUS_ID': 'CLOSED'
+            }
+        }
+        
+        test = http_build_query(d)
+        assert test == 'FILTER[%21STATUS_ID]=CLOSED&' 
\ No newline at end of file