Skip to content

Commit 20fd89d

Browse files
committed
Merge branch 'main' of github.com:codellm-devkit/python-sdk
2 parents 9b3cd4a + 1ccf71a commit 20fd89d

File tree

17 files changed

+39627
-38307
lines changed

17 files changed

+39627
-38307
lines changed

cldk/analysis/java/codeanalyzer/codeanalyzer.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ def __init__(
6767
self.eager_analysis = eager_analysis
6868
self.analysis_level = analysis_level
6969
self.target_files = target_files
70-
self.application = self._init_codeanalyzer(analysis_level=1 if analysis_level == AnalysisLevel.symbol_table else 2)
70+
if self.source_code is None:
71+
self.application = self._init_codeanalyzer(analysis_level=1 if analysis_level == AnalysisLevel.symbol_table else 2)
72+
else:
73+
self.application = self._codeanalyzer_single_file()
7174
# Attributes related the Java code analysis...
7275
if analysis_level == AnalysisLevel.call_graph:
7376
self.call_graph: nx.DiGraph = self._generate_call_graph(using_symbol_table=False)
Binary file not shown.

cldk/core.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from cldk.analysis.java import JavaAnalysis
2929
from cldk.analysis.commons.treesitter import TreesitterJava
3030
from cldk.analysis.python.python_analysis import PythonAnalysis
31+
from cldk.analysis.python.python_analysis import PythonAnalysis
3132
from cldk.utils.exceptions import CldkInitializationException
3233
from cldk.utils.sanitization.java import TreesitterSanitizer
3334

@@ -123,9 +124,6 @@ def analysis(
123124
return PythonAnalysis(
124125
project_dir=project_path,
125126
source_code=source_code,
126-
analysis_backend_path=analysis_backend_path,
127-
analysis_json_path=analysis_json_path,
128-
eager_analysis=eager,
129127
)
130128
elif self.language == "c":
131129
return CAnalysis(project_dir=project_path)

cldk/models/java/models.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ class JCallable(BaseModel):
270270
code (str): The code block of the callable.
271271
start_line (int): The starting line number of the callable in the source file.
272272
end_line (int): The ending line number of the callable in the source file.
273+
code_start_line (int): The starting line number of the code block of a callable in the source file.
273274
referenced_types (List[str]): The types referenced within the callable.
274275
accessed_fields (List[str]): Fields accessed in the callable.
275276
call_sites (List[JCallSite]): Call sites in the callable.
@@ -293,6 +294,7 @@ class JCallable(BaseModel):
293294
code: str
294295
start_line: int
295296
end_line: int
297+
code_start_line: int
296298
referenced_types: List[str]
297299
accessed_fields: List[str]
298300
call_sites: List[JCallSite]
@@ -363,11 +365,15 @@ class JCompilationUnit(BaseModel):
363365
"""Represents a compilation unit in Java.
364366
365367
Attributes:
368+
file_path (str): The path to the source file.
369+
package_name (str): The name of the package for the comppilation unit.
366370
comments (List[JComment]): A list of comments in the compilation unit.
367371
imports (List[str]): A list of import statements in the compilation unit.
368372
type_declarations (Dict[str, JType]): A dictionary mapping type names to their corresponding JType representations.
369373
"""
370374

375+
file_path: str
376+
package_name: str
371377
comments: List[JComment]
372378
imports: List[str]
373379
type_declarations: Dict[str, JType]
@@ -430,11 +436,10 @@ def validate_source(cls, value) -> JMethodDetail:
430436
j_callable: JCallable = _CALLABLES_LOOKUP_TABLE.get(
431437
(type_declaration, signature),
432438
JCallable(
433-
comments=[],
434439
signature=signature,
435440
is_implicit=True,
436441
is_constructor="<init>" in value["callable_declaration"],
437-
comment="",
442+
comments=[],
438443
annotations=[],
439444
modifiers=[],
440445
thrown_exceptions=[],
@@ -443,12 +448,15 @@ def validate_source(cls, value) -> JMethodDetail:
443448
JCallableParameter(name=None, type=t, annotations=[], modifiers=[], start_column=-1, end_column=-1, start_line=-1, end_line=-1)
444449
for t in value["callable_declaration"].split("(")[1].split(")")[0].split(",")
445450
],
451+
return_type=None,
446452
code="",
447453
start_line=-1,
448454
end_line=-1,
455+
code_start_line=-1,
449456
referenced_types=[],
450457
accessed_fields=[],
451458
call_sites=[],
459+
is_entrypoint=False,
452460
variable_declarations=[],
453461
crud_operations=[],
454462
crud_queries=[],

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "cldk"
3-
version = "1.0.1"
3+
version = "1.0.4"
44
description = "The official Python SDK for Codellm-Devkit."
55
authors = ["Rahul Krishna <[email protected]>", "Rangeet Pan <[email protected]>", "Saurabh Sinhas <[email protected]>",
66
"Raju Pavuluri <[email protected]>"]
@@ -120,4 +120,4 @@ directory = "coverage_html_report"
120120
sample-c-application = "tests/resources/c/application/"
121121
sample-application = "tests/resources/java/application/"
122122
sample-application-analysis-json = "tests/resources/java/analysis_json/"
123-
codeanalyzer-jar-path = "tests/resources/java/codeanalyzer_jars/"
123+
codeanalyzer-jar-path = "cldk/analysis/java/codeanalyzer/jar/"

tests/analysis/java/test_java_analysis.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,24 @@ def test_get_symbol_table_is_not_null(test_fixture, analysis_json):
5050
)
5151
assert analysis.get_symbol_table() is not None
5252

53+
def test_get_symbol_table_source_code(java_code):
54+
"""Should return a symbol table for source analysis with expected class/method count"""
55+
56+
# Initialize the CLDK object with the project directory, language, and analysis_backend
57+
cldk = CLDK(language="java")
58+
analysis = cldk.analysis(
59+
source_code=java_code,
60+
analysis_backend_path=None,
61+
eager=True,
62+
analysis_level=AnalysisLevel.symbol_table,
63+
)
64+
65+
# assert on expected class name and method count in the symbol table
66+
expected_class_name = "com.acme.modres.WeatherServlet"
67+
assert analysis.get_symbol_table() is not None
68+
assert len(analysis.get_symbol_table().keys()) == 1
69+
assert expected_class_name in analysis.get_methods().keys()
70+
assert len(analysis.get_methods().get(expected_class_name).keys()) == 9
5371

5472
def test_get_imports(test_fixture, analysis_json):
5573
"""Should return NotImplemented for get_imports()"""
@@ -632,11 +650,11 @@ def test_get_methods_in_class(test_fixture, analysis_json):
632650
eager_analysis=False,
633651
)
634652

635-
# Test that there are 30 methods in the Log class
653+
# Test that there are 29 methods in the Log class
636654
methods = java_analysis.get_methods_in_class("com.ibm.websphere.samples.daytrader.util.Log")
637655
assert methods is not None
638656
assert isinstance(methods, Dict)
639-
assert len(methods) == 30
657+
assert len(methods) == 29
640658
for method in methods:
641659
assert isinstance(methods[method], JCallable)
642660

tests/analysis/python/test_python_analysis.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def divide(self, a, b):
6767

6868
def test_get_methods():
6969
"""Should return all of the methods"""
70-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
70+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
7171

7272
all_methods = python_analysis.get_methods()
7373
assert all_methods is not None
@@ -79,7 +79,7 @@ def test_get_methods():
7979

8080
def test_get_functions():
8181
"""Should return all of the functions"""
82-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
82+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
8383

8484
all_functions = python_analysis.get_functions()
8585
assert all_functions is not None
@@ -91,7 +91,7 @@ def test_get_functions():
9191

9292
def test_get_all_modules(tmp_path):
9393
"""Should return all of the modules"""
94-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=tmp_path, source_code=None, analysis_backend_path=None, analysis_json_path=None)
94+
python_analysis = PythonAnalysis(project_dir=tmp_path, source_code=None)
9595

9696
# set up some temporary modules
9797
temp_file_path = os.path.join(tmp_path, "hello.py")
@@ -111,7 +111,7 @@ def test_get_all_modules(tmp_path):
111111

112112
def test_get_method_details():
113113
"""Should return the method details"""
114-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
114+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
115115

116116
method_details = python_analysis.get_method_details("add(self, a, b)")
117117
assert method_details is not None
@@ -121,7 +121,7 @@ def test_get_method_details():
121121

122122
def test_is_parsable():
123123
"""Should be able to parse the code"""
124-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
124+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
125125

126126
code = "def is_parsable(self, code: str) -> bool: return True"
127127
is_parsable = python_analysis.is_parsable(code)
@@ -134,7 +134,7 @@ def test_is_parsable():
134134

135135
def test_get_raw_ast():
136136
"""Should return the raw AST"""
137-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
137+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
138138

139139
raw_ast = python_analysis.get_raw_ast(PYTHON_CODE)
140140
assert raw_ast is not None
@@ -144,7 +144,7 @@ def test_get_raw_ast():
144144

145145
def test_get_imports():
146146
"""Should return all of the imports"""
147-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
147+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
148148

149149
all_imports = python_analysis.get_imports()
150150
assert all_imports is not None
@@ -156,7 +156,7 @@ def test_get_imports():
156156

157157
def test_get_variables():
158158
"""Should return all of the variables"""
159-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
159+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
160160

161161
with pytest.raises(NotImplementedError) as except_info:
162162
python_analysis.get_variables()
@@ -165,7 +165,7 @@ def test_get_variables():
165165

166166
def test_get_classes():
167167
"""Should return all of the classes"""
168-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
168+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
169169

170170
all_classes = python_analysis.get_classes()
171171
assert all_classes is not None
@@ -178,7 +178,7 @@ def test_get_classes():
178178

179179
def test_get_classes_by_criteria():
180180
"""Should return all of the classes that match the criteria"""
181-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
181+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
182182

183183
with pytest.raises(NotImplementedError) as except_info:
184184
python_analysis.get_classes_by_criteria()
@@ -187,7 +187,7 @@ def test_get_classes_by_criteria():
187187

188188
def test_get_sub_classes():
189189
"""Should return all of the subclasses"""
190-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
190+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
191191

192192
with pytest.raises(NotImplementedError) as except_info:
193193
python_analysis.get_sub_classes()
@@ -196,7 +196,7 @@ def test_get_sub_classes():
196196

197197
def test_get_nested_classes():
198198
"""Should return all of the nested classes"""
199-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
199+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
200200

201201
with pytest.raises(NotImplementedError) as except_info:
202202
python_analysis.get_nested_classes()
@@ -205,7 +205,7 @@ def test_get_nested_classes():
205205

206206
def test_get_constructors():
207207
"""Should return all of the constructors"""
208-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
208+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
209209

210210
with pytest.raises(NotImplementedError) as except_info:
211211
python_analysis.get_constructors()
@@ -214,7 +214,7 @@ def test_get_constructors():
214214

215215
def test_get_methods_in_class():
216216
"""Should return all of the methods in the class"""
217-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
217+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
218218

219219
with pytest.raises(NotImplementedError) as except_info:
220220
python_analysis.get_methods_in_class()
@@ -223,7 +223,7 @@ def test_get_methods_in_class():
223223

224224
def test_get_fields():
225225
"""Should return all of the fields in the class"""
226-
python_analysis = PythonAnalysis(eager_analysis=True, project_dir=None, source_code=PYTHON_CODE, analysis_backend_path=None, analysis_json_path=None)
226+
python_analysis = PythonAnalysis(project_dir=None, source_code=PYTHON_CODE)
227227

228228
with pytest.raises(NotImplementedError) as except_info:
229229
python_analysis.get_fields()

tests/conftest.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def codeanalyzer_jar_path():
7575
# Load the configuration
7676
config = toml.load(pyproject_path)
7777

78-
return Path(config["tool"]["cldk"]["testing"]["codeanalyzer-jar-path"]) / "2.3.0"
78+
return Path(config["tool"]["cldk"]["testing"]["codeanalyzer-jar-path"])
7979

8080

8181
@pytest.fixture(scope="session", autouse=True)
@@ -190,3 +190,24 @@ def test_fixture_binutils():
190190
for directory in Path(test_data_path).iterdir():
191191
if directory.exists() and directory.is_dir():
192192
shutil.rmtree(directory)
193+
194+
@pytest.fixture(scope="session", autouse=True)
195+
def java_code() -> str:
196+
"""
197+
Returns sample Java source code for analysis.
198+
199+
Yields:
200+
str : Java code to be analyzed.
201+
"""
202+
# ----------------------------------[ SETUP ]----------------------------------
203+
# Path to your pyproject.toml
204+
pyproject_path = Path(__file__).parent.parent / "pyproject.toml"
205+
206+
# Load the configuration
207+
config = toml.load(pyproject_path)
208+
209+
# Access the test data path
210+
test_data_path = config["tool"]["cldk"]["testing"]["sample-application"]
211+
javafile = Path(test_data_path).absolute() / ("WeatherServlet.java")
212+
with open(javafile) as f:
213+
return f.read()

0 commit comments

Comments
 (0)