codeflash 0.3.3__tar.gz → 0.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codeflash-0.3.3 → codeflash-0.3.4}/PKG-INFO +2 -2
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/api/aiservice.py +21 -18
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/api/cfapi.py +8 -4
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/env_utils.py +4 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/discovery/functions_to_optimize.py +13 -5
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/main.py +3 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/optimization/function_context.py +25 -20
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/result/create_pr.py +2 -6
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/verification/comparator.py +39 -2
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/verification/parse_test_output.py +4 -3
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/version.py +2 -2
- {codeflash-0.3.3 → codeflash-0.3.4}/pyproject.toml +3 -3
- {codeflash-0.3.3 → codeflash-0.3.4}/README.md +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/LICENSE +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/analytics/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/analytics/posthog.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/api/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/cli_cmds/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/cli_cmds/cli.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/cli_cmds/cmd_init.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/cli_cmds/logging_config.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/cli_cmds/workflows/codeflash-optimize.yaml +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/code_extractor.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/code_replacer.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/code_utils.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/config_consts.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/config_parser.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/git_utils.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/instrument_existing_tests.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/linter.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/sqlalchemy_utils.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/code_utils/time_utils.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/discovery/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/discovery/discover_unit_tests.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/github/PrComment.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/github/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/optimization/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/result/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/result/explanation.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/tracing/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/tracing/replay_test.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/tracing/tracer.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/update_license_version.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/verification/__init__.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/verification/equivalence.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/verification/test_results.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/verification/test_runner.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/verification/verification_utils.py +0 -0
- {codeflash-0.3.3 → codeflash-0.3.4}/codeflash/verification/verifier.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codeflash
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: A Code Performance Optimization Library
|
|
5
5
|
Home-page: https://codeflash.ai
|
|
6
6
|
Author: CodeFlash Inc.
|
|
@@ -20,7 +20,7 @@ Requires-Dist: jedi (>=0.19.0)
|
|
|
20
20
|
Requires-Dist: junitparser (>=3.1.0)
|
|
21
21
|
Requires-Dist: libcst (>=1.0.1)
|
|
22
22
|
Requires-Dist: posthog (>=3.0.0)
|
|
23
|
-
Requires-Dist: pydantic (>=
|
|
23
|
+
Requires-Dist: pydantic (>=1.10.1)
|
|
24
24
|
Requires-Dist: pytest (>=7.0.0)
|
|
25
25
|
Requires-Dist: pytest-timeout (>=2.1.0)
|
|
26
26
|
Requires-Dist: tiktoken (>=0.3.2)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
2
3
|
import os
|
|
3
|
-
import requests
|
|
4
|
-
from pydantic import RootModel
|
|
5
4
|
from typing import Any, Dict, List, Tuple, Optional
|
|
6
5
|
|
|
6
|
+
import requests
|
|
7
|
+
from pydantic.json import pydantic_encoder
|
|
8
|
+
|
|
7
9
|
from codeflash.analytics.posthog import ph
|
|
8
10
|
from codeflash.code_utils.env_utils import get_codeflash_api_key
|
|
9
11
|
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
|
|
@@ -23,19 +25,20 @@ def make_ai_service_request(
|
|
|
23
25
|
) -> requests.Response:
|
|
24
26
|
"""
|
|
25
27
|
Make an API request to the given endpoint on the AI service.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Returns:
|
|
33
|
-
- requests.Response: The response from the API.
|
|
28
|
+
:param endpoint: The endpoint to call, e.g., "/optimize".
|
|
29
|
+
:param method: The HTTP method to use ('GET' or 'POST').
|
|
30
|
+
:param payload: Optional JSON payload to include in the POST request body.
|
|
31
|
+
:param timeout: The timeout for the request.
|
|
32
|
+
:return: The response object from the API.
|
|
34
33
|
"""
|
|
35
34
|
url = f"{AI_SERVICE_BASE_URL}/ai{endpoint}"
|
|
36
35
|
ai_service_headers = {"Authorization": f"Bearer {get_codeflash_api_key()}"}
|
|
37
36
|
if method.upper() == "POST":
|
|
38
|
-
|
|
37
|
+
json_payload = json.dumps(payload, indent=None, default=pydantic_encoder)
|
|
38
|
+
ai_service_headers["Content-Type"] = "application/json"
|
|
39
|
+
response = requests.post(
|
|
40
|
+
url, data=json_payload, headers=ai_service_headers, timeout=timeout
|
|
41
|
+
)
|
|
39
42
|
else:
|
|
40
43
|
response = requests.get(url, headers=ai_service_headers, timeout=timeout)
|
|
41
44
|
# response.raise_for_status() # Will raise an HTTPError if the HTTP request returned an unsuccessful status code
|
|
@@ -55,10 +58,10 @@ def optimize_python_code(
|
|
|
55
58
|
Returns:
|
|
56
59
|
- List[Tuple[str, str]]: A list of tuples where the first element is the optimized code and the second is the explanation.
|
|
57
60
|
"""
|
|
58
|
-
|
|
61
|
+
payload = {"source_code": source_code, "num_variants": num_variants}
|
|
59
62
|
logging.info(f"Generating optimized candidates ...")
|
|
60
63
|
try:
|
|
61
|
-
response = make_ai_service_request("/optimize", payload=
|
|
64
|
+
response = make_ai_service_request("/optimize", payload=payload, timeout=600)
|
|
62
65
|
except requests.exceptions.RequestException as e:
|
|
63
66
|
logging.error(f"Error generating optimized candidates: {e}")
|
|
64
67
|
ph("cli-optimize-error-caught", {"error": str(e)})
|
|
@@ -66,6 +69,7 @@ def optimize_python_code(
|
|
|
66
69
|
|
|
67
70
|
if response.status_code == 200:
|
|
68
71
|
optimizations = response.json()["optimizations"]
|
|
72
|
+
logging.info(f"Generated {len(optimizations)} candidates.")
|
|
69
73
|
return [(opt["source_code"], opt["explanation"]) for opt in optimizations]
|
|
70
74
|
else:
|
|
71
75
|
try:
|
|
@@ -108,11 +112,9 @@ def generate_regression_tests(
|
|
|
108
112
|
"pytest",
|
|
109
113
|
"unittest",
|
|
110
114
|
], f"Invalid test framework, got {test_framework} but expected 'pytest' or 'unittest'"
|
|
111
|
-
|
|
115
|
+
payload = {
|
|
112
116
|
"source_code_being_tested": source_code_being_tested,
|
|
113
|
-
"function_to_optimize":
|
|
114
|
-
mode="json"
|
|
115
|
-
),
|
|
117
|
+
"function_to_optimize": function_to_optimize,
|
|
116
118
|
"dependent_function_names": dependent_function_names,
|
|
117
119
|
"module_path": module_path,
|
|
118
120
|
"test_module_path": test_module_path,
|
|
@@ -120,7 +122,7 @@ def generate_regression_tests(
|
|
|
120
122
|
"test_timeout": test_timeout,
|
|
121
123
|
}
|
|
122
124
|
try:
|
|
123
|
-
response = make_ai_service_request("/testgen", payload=
|
|
125
|
+
response = make_ai_service_request("/testgen", payload=payload, timeout=600)
|
|
124
126
|
except requests.exceptions.RequestException as e:
|
|
125
127
|
logging.error(f"Error generating tests: {e}")
|
|
126
128
|
ph("cli-testgen-error-caught", {"error": str(e)})
|
|
@@ -130,6 +132,7 @@ def generate_regression_tests(
|
|
|
130
132
|
|
|
131
133
|
if response.status_code == 200:
|
|
132
134
|
response_json = response.json()
|
|
135
|
+
logging.info(f"Generated tests for function {function_to_optimize.function_name}")
|
|
133
136
|
return response_json["generated_tests"], response_json["instrumented_tests"]
|
|
134
137
|
else:
|
|
135
138
|
try:
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
2
3
|
import os
|
|
3
4
|
from functools import lru_cache
|
|
4
5
|
from typing import Optional, Dict, Any
|
|
5
6
|
|
|
6
7
|
import requests
|
|
8
|
+
from pydantic.json import pydantic_encoder
|
|
7
9
|
from requests import Response
|
|
8
10
|
|
|
9
11
|
from codeflash.code_utils.env_utils import get_codeflash_api_key
|
|
@@ -21,15 +23,17 @@ def make_cfapi_request(
|
|
|
21
23
|
) -> requests.Response:
|
|
22
24
|
"""
|
|
23
25
|
Make an HTTP request using the specified method, URL, headers, and JSON payload.
|
|
24
|
-
:param endpoint: The URL to send the request to.
|
|
26
|
+
:param endpoint: The endpoint URL to send the request to.
|
|
25
27
|
:param method: The HTTP method to use ('GET', 'POST', etc.).
|
|
26
|
-
:param payload: Optional JSON payload to include in the request body.
|
|
27
|
-
:return: The response object.
|
|
28
|
+
:param payload: Optional JSON payload to include in the POST request body.
|
|
29
|
+
:return: The response object from the API.
|
|
28
30
|
"""
|
|
29
31
|
url = f"{CFAPI_BASE_URL}/cfapi{endpoint}"
|
|
30
32
|
cfapi_headers = {"Authorization": f"Bearer {get_codeflash_api_key()}"}
|
|
31
33
|
if method.upper() == "POST":
|
|
32
|
-
|
|
34
|
+
json_payload = json.dumps(payload, indent=None, default=pydantic_encoder)
|
|
35
|
+
cfapi_headers["Content-Type"] = "application/json"
|
|
36
|
+
response = requests.post(url, data=json_payload, headers=cfapi_headers)
|
|
33
37
|
else:
|
|
34
38
|
response = requests.get(url, headers=cfapi_headers)
|
|
35
39
|
return response
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
|
+
from functools import lru_cache
|
|
3
4
|
from typing import Optional
|
|
4
5
|
|
|
5
6
|
|
|
7
|
+
@lru_cache(maxsize=1)
|
|
6
8
|
def get_codeflash_api_key() -> Optional[str]:
|
|
7
9
|
api_key = os.environ.get("CODEFLASH_API_KEY")
|
|
8
10
|
if not api_key:
|
|
@@ -33,11 +35,13 @@ def ensure_codeflash_api_key() -> bool:
|
|
|
33
35
|
return True
|
|
34
36
|
|
|
35
37
|
|
|
38
|
+
@lru_cache(maxsize=1)
|
|
36
39
|
def get_codeflash_org_key() -> Optional[str]:
|
|
37
40
|
api_key = os.environ.get("CODEFLASH_ORG_KEY")
|
|
38
41
|
return api_key
|
|
39
42
|
|
|
40
43
|
|
|
44
|
+
@lru_cache(maxsize=1)
|
|
41
45
|
def get_pr_number() -> Optional[int]:
|
|
42
46
|
pr_number = os.environ.get("CODEFLASH_PR_NUMBER")
|
|
43
47
|
if not pr_number:
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import ast
|
|
2
|
+
import libcst as cst
|
|
2
3
|
import logging
|
|
3
4
|
import os
|
|
5
|
+
import random
|
|
4
6
|
from _ast import ClassDef, FunctionDef, AsyncFunctionDef
|
|
5
|
-
from typing import Dict, Optional, List, Tuple, Union
|
|
6
|
-
|
|
7
|
-
import libcst as cst
|
|
8
7
|
from libcst import CSTNode
|
|
9
8
|
from pydantic.dataclasses import dataclass
|
|
9
|
+
from typing import Dict, Optional, List, Tuple, Union
|
|
10
10
|
|
|
11
11
|
from codeflash.code_utils.code_utils import path_belongs_to_site_packages
|
|
12
12
|
from codeflash.code_utils.git_utils import get_git_diff
|
|
@@ -128,7 +128,10 @@ def get_functions_to_optimize_by_file(
|
|
|
128
128
|
if only_function_name == fn.function_name:
|
|
129
129
|
found_function = fn
|
|
130
130
|
if found_function is None:
|
|
131
|
-
raise ValueError(
|
|
131
|
+
raise ValueError(
|
|
132
|
+
f"Function {only_function_name} not found in file {file} or"
|
|
133
|
+
f" the function does not have a 'return' statement."
|
|
134
|
+
)
|
|
132
135
|
functions[file] = [found_function]
|
|
133
136
|
else:
|
|
134
137
|
logging.info("Finding all functions modified in the current git diff ...")
|
|
@@ -170,7 +173,12 @@ def get_all_files_and_functions(module_root_path: str) -> Dict[str, List[Functio
|
|
|
170
173
|
file_path = os.path.join(root, file)
|
|
171
174
|
# Find all the functions in the file
|
|
172
175
|
functions.update(find_all_functions_in_file(file_path))
|
|
173
|
-
|
|
176
|
+
# Randomize the order of the files to optimize to avoid optimizing the same file in the same order every time.
|
|
177
|
+
# Helpful if an optimize-all run is stuck and we restart it.
|
|
178
|
+
files_list = list(functions.items())
|
|
179
|
+
random.shuffle(files_list)
|
|
180
|
+
functions_shuffled = dict(files_list)
|
|
181
|
+
return functions_shuffled
|
|
174
182
|
|
|
175
183
|
|
|
176
184
|
def find_all_functions_in_file(file_path: str) -> Dict[str, List[FunctionToOptimize]]:
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"""Thanks for being curious about how codeflash works! If you might want to work with us on finally making performance a
|
|
2
|
+
solved problem, please reach out to us at careers@codeflash.ai. We're hiring!
|
|
3
|
+
"""
|
|
1
4
|
import concurrent.futures
|
|
2
5
|
import libcst as cst
|
|
3
6
|
import logging
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import ast
|
|
2
|
-
import jedi
|
|
3
2
|
import logging
|
|
4
3
|
import os
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
import jedi
|
|
5
7
|
import tiktoken
|
|
6
8
|
from jedi.api.classes import Name
|
|
7
|
-
from pydantic import RootModel
|
|
8
9
|
from pydantic.dataclasses import dataclass
|
|
9
|
-
from typing import List
|
|
10
10
|
|
|
11
11
|
from codeflash.code_utils.code_extractor import get_code_no_skeleton, get_code
|
|
12
12
|
from codeflash.code_utils.code_utils import path_belongs_to_site_packages
|
|
@@ -43,11 +43,6 @@ class Source:
|
|
|
43
43
|
source_code: str
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
@dataclass(frozen=True)
|
|
47
|
-
class SourceList(RootModel):
|
|
48
|
-
root: list[Source]
|
|
49
|
-
|
|
50
|
-
|
|
51
46
|
def get_type_annotation_context(
|
|
52
47
|
function: FunctionToOptimize, jedi_script: jedi.Script, project_root_path: str
|
|
53
48
|
) -> List[Source]:
|
|
@@ -72,12 +67,18 @@ def get_type_annotation_context(
|
|
|
72
67
|
name = arg.annotation.id
|
|
73
68
|
line_no = arg.annotation.lineno
|
|
74
69
|
col_no = arg.annotation.col_offset
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
try:
|
|
71
|
+
definition: List[Name] = jedi_script.goto(
|
|
72
|
+
line=line_no,
|
|
73
|
+
column=col_no,
|
|
74
|
+
follow_imports=True,
|
|
75
|
+
follow_builtin_imports=False,
|
|
76
|
+
)
|
|
77
|
+
except Exception as e:
|
|
78
|
+
logging.error(
|
|
79
|
+
f"Error while getting definition for {name.full_name}: {e}"
|
|
80
|
+
)
|
|
81
|
+
definition = []
|
|
81
82
|
if definition: # TODO can be multiple definitions
|
|
82
83
|
definition_path = str(definition[0].module_path)
|
|
83
84
|
# The definition is part of this project and not defined within the original function
|
|
@@ -136,12 +137,16 @@ def get_function_variables_definitions(
|
|
|
136
137
|
names.append(ref)
|
|
137
138
|
|
|
138
139
|
for name in names:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
try:
|
|
141
|
+
definitions: List[Name] = script.goto(
|
|
142
|
+
line=name.line,
|
|
143
|
+
column=name.column,
|
|
144
|
+
follow_imports=True,
|
|
145
|
+
follow_builtin_imports=False,
|
|
146
|
+
)
|
|
147
|
+
except Exception as e:
|
|
148
|
+
logging.error(f"Error while getting definition for {name.full_name}: {e}")
|
|
149
|
+
definitions = []
|
|
145
150
|
if definitions:
|
|
146
151
|
# TODO: there can be multiple definitions, see how to handle such cases
|
|
147
152
|
definition_path = str(definitions[0].module_path)
|
|
@@ -29,9 +29,7 @@ def check_create_pr(
|
|
|
29
29
|
repo=repo,
|
|
30
30
|
pr_number=pr_number,
|
|
31
31
|
file_changes={
|
|
32
|
-
relative_path: FileDiffContent(
|
|
33
|
-
oldContent=original_code, newContent=new_code
|
|
34
|
-
).model_dump(mode="json")
|
|
32
|
+
relative_path: FileDiffContent(oldContent=original_code, newContent=new_code)
|
|
35
33
|
},
|
|
36
34
|
pr_comment=PrComment(
|
|
37
35
|
optimization_explanation=explanation.explanation_message(),
|
|
@@ -64,9 +62,7 @@ def check_create_pr(
|
|
|
64
62
|
repo=repo,
|
|
65
63
|
base_branch=base_branch,
|
|
66
64
|
file_changes={
|
|
67
|
-
relative_path: FileDiffContent(
|
|
68
|
-
oldContent=original_code, newContent=new_code
|
|
69
|
-
).model_dump(mode="json")
|
|
65
|
+
relative_path: FileDiffContent(oldContent=original_code, newContent=new_code)
|
|
70
66
|
},
|
|
71
67
|
pr_comment=PrComment(
|
|
72
68
|
optimization_explanation=explanation.explanation_message(),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import datetime
|
|
2
|
+
import decimal
|
|
2
3
|
import logging
|
|
3
4
|
import math
|
|
4
5
|
from typing import Any
|
|
@@ -15,6 +16,19 @@ try:
|
|
|
15
16
|
HAS_SQLALCHEMY = True
|
|
16
17
|
except ImportError:
|
|
17
18
|
HAS_SQLALCHEMY = False
|
|
19
|
+
try:
|
|
20
|
+
import scipy
|
|
21
|
+
|
|
22
|
+
HAS_SCIPY = True
|
|
23
|
+
except ImportError:
|
|
24
|
+
HAS_SCIPY = False
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
import pandas
|
|
28
|
+
|
|
29
|
+
HAS_PANDAS = True
|
|
30
|
+
except ImportError:
|
|
31
|
+
HAS_PANDAS = False
|
|
18
32
|
|
|
19
33
|
|
|
20
34
|
def comparator(orig: Any, new: Any) -> bool:
|
|
@@ -43,13 +57,14 @@ def comparator(orig: Any, new: Any) -> bool:
|
|
|
43
57
|
return False
|
|
44
58
|
return True
|
|
45
59
|
|
|
46
|
-
if isinstance(orig, (str, int, bool, complex, type(None))):
|
|
60
|
+
if isinstance(orig, (str, int, bool, complex, type(None), decimal.Decimal)):
|
|
47
61
|
return orig == new
|
|
48
62
|
if isinstance(orig, float):
|
|
49
63
|
if math.isnan(orig) and math.isnan(new):
|
|
50
64
|
return True
|
|
51
65
|
return math.isclose(orig, new)
|
|
52
|
-
|
|
66
|
+
# scipy condition because dok_matrix type is also a instance of dict, but dict comparison doesn't work for it
|
|
67
|
+
if isinstance(orig, dict) and not (HAS_SCIPY and isinstance(orig, scipy.sparse.spmatrix)):
|
|
53
68
|
if len(orig) != len(new):
|
|
54
69
|
return False
|
|
55
70
|
for key in orig:
|
|
@@ -76,6 +91,28 @@ def comparator(orig: Any, new: Any) -> bool:
|
|
|
76
91
|
if HAS_NUMPY and isinstance(orig, (np.integer, np.bool_, np.byte)):
|
|
77
92
|
return orig == new
|
|
78
93
|
|
|
94
|
+
if HAS_SCIPY and isinstance(orig, scipy.sparse.spmatrix):
|
|
95
|
+
if orig.dtype != new.dtype:
|
|
96
|
+
return False
|
|
97
|
+
if orig.get_shape() != new.get_shape():
|
|
98
|
+
return False
|
|
99
|
+
return (orig != new).nnz == 0
|
|
100
|
+
|
|
101
|
+
if HAS_PANDAS and isinstance(
|
|
102
|
+
orig,
|
|
103
|
+
(
|
|
104
|
+
pandas.DataFrame,
|
|
105
|
+
pandas.Series,
|
|
106
|
+
pandas.Index,
|
|
107
|
+
pandas.Categorical,
|
|
108
|
+
pandas.arrays.SparseArray,
|
|
109
|
+
),
|
|
110
|
+
):
|
|
111
|
+
return orig.equals(new)
|
|
112
|
+
|
|
113
|
+
if HAS_PANDAS and isinstance(orig, (pandas.CategoricalDtype, pandas.Interval, pandas.Period)):
|
|
114
|
+
return orig == new
|
|
115
|
+
|
|
79
116
|
# This should be at the end of all numpy checking
|
|
80
117
|
try:
|
|
81
118
|
if HAS_NUMPY and np.isnan(orig):
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
|
|
1
3
|
import logging
|
|
2
4
|
import os
|
|
3
5
|
import pathlib
|
|
@@ -5,10 +7,8 @@ import pickle
|
|
|
5
7
|
import re
|
|
6
8
|
import sqlite3
|
|
7
9
|
import subprocess
|
|
8
|
-
from collections import defaultdict
|
|
9
|
-
from typing import Optional
|
|
10
|
-
|
|
11
10
|
from junitparser.xunit2 import JUnitXml
|
|
11
|
+
from typing import Optional
|
|
12
12
|
|
|
13
13
|
from codeflash.code_utils.code_utils import (
|
|
14
14
|
module_name_from_file_path,
|
|
@@ -258,6 +258,7 @@ def merge_test_results(xml_test_results: TestResults, bin_test_results: TestResu
|
|
|
258
258
|
)
|
|
259
259
|
)
|
|
260
260
|
else:
|
|
261
|
+
# Looks like we would never reach this condition because we are not printing the log line in the xml file
|
|
261
262
|
for xml_result in xml_results:
|
|
262
263
|
bin_result = bin_results.get_by_id(xml_result.id)
|
|
263
264
|
if bin_result is None:
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# These version placeholders will be replaced by poetry-dynamic-versioning during `poetry build`.
|
|
2
|
-
__version__ = "0.3.
|
|
3
|
-
__version_tuple__ = (0, 3,
|
|
2
|
+
__version__ = "0.3.4"
|
|
3
|
+
__version_tuple__ = (0, 3, 4)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "codeflash"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.4" # Determined by poetry-dynamic-versioning during `poetry build`
|
|
4
4
|
description = "A Code Performance Optimization Library"
|
|
5
5
|
authors = ["CodeFlash Inc. <contact@codeflash.ai>"]
|
|
6
6
|
homepage = "https://codeflash.ai"
|
|
@@ -22,7 +22,7 @@ pytest-timeout = ">=2.1.0"
|
|
|
22
22
|
tomlkit = ">=0.11.7"
|
|
23
23
|
unittest-xml-reporting = ">=3.2.0"
|
|
24
24
|
junitparser = ">=3.1.0"
|
|
25
|
-
pydantic = "
|
|
25
|
+
pydantic = ">=1.10.1"
|
|
26
26
|
black = ">=22.3.0"
|
|
27
27
|
humanize = ">=4.0.0"
|
|
28
28
|
posthog = ">=3.0.0"
|
|
@@ -60,7 +60,7 @@ line-length = 100
|
|
|
60
60
|
target-version = ['py312']
|
|
61
61
|
|
|
62
62
|
[build-system]
|
|
63
|
-
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.
|
|
63
|
+
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.2.0,<2.0.0"]
|
|
64
64
|
build-backend = "poetry_dynamic_versioning.backend"
|
|
65
65
|
|
|
66
66
|
[tool.poetry.build]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|