Skip to content

Commit 836c819

Browse files
authored
Merge branch 'main' into save-event-creator
2 parents 5aba6d9 + 8b1f4b6 commit 836c819

File tree

7 files changed

+197
-27
lines changed

7 files changed

+197
-27
lines changed

codeflash/cli_cmds/cmd_init.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from codeflash.cli_cmds.console import console, logger
2323
from codeflash.code_utils.compat import LF
2424
from codeflash.code_utils.config_parser import parse_config_file
25-
from codeflash.code_utils.env_utils import get_codeflash_api_key
25+
from codeflash.code_utils.env_utils import check_formatter_installed, get_codeflash_api_key
2626
from codeflash.code_utils.git_utils import get_git_remotes, get_repo_owner_and_name
2727
from codeflash.code_utils.github_utils import get_github_secrets_page_url
2828
from codeflash.code_utils.shell_utils import get_shell_rc_path, save_api_key_to_rc
@@ -201,7 +201,7 @@ def collect_setup_info() -> SetupInfo:
201201
path_type=inquirer.Path.DIRECTORY,
202202
)
203203
if custom_module_root_answer:
204-
module_root = Path(curdir) / Path(custom_module_root_answer["path"])
204+
module_root = Path(custom_module_root_answer["path"])
205205
else:
206206
apologize_and_exit()
207207
else:
@@ -537,7 +537,7 @@ def install_github_actions(override_formatter_check: bool = False) -> None: # n
537537
existing_api_key = None
538538
click.prompt(
539539
f"Next, you'll need to add your CODEFLASH_API_KEY as a secret to your GitHub repo.{LF}"
540-
f"Press Enter to open your repo's secrets page at {get_github_secrets_page_url(repo)}{LF}"
540+
f"Press Enter to open your repo's secrets page at {get_github_secrets_page_url(repo)} {LF}"
541541
f"Then, click 'New repository secret' to add your api key with the variable name CODEFLASH_API_KEY.{LF}"
542542
f"{'Here is your CODEFLASH_API_KEY: ' + existing_api_key + ' ' + LF}"
543543
if existing_api_key
@@ -720,11 +720,7 @@ def configure_pyproject_toml(setup_info: SetupInfo) -> None:
720720
)
721721
elif formatter == "don't use a formatter":
722722
formatter_cmds.append("disabled")
723-
if formatter in ["black", "ruff"]:
724-
try:
725-
subprocess.run([formatter], capture_output=True, check=False)
726-
except (FileNotFoundError, NotADirectoryError):
727-
click.echo(f"⚠️ Formatter not found: {formatter}, please ensure it is installed")
723+
check_formatter_installed(formatter_cmds)
728724
codeflash_section["formatter-cmds"] = formatter_cmds
729725
# Add the 'codeflash' section, ensuring 'tool' section exists
730726
tool_section = pyproject_data.get("tool", tomlkit.table())
@@ -750,7 +746,7 @@ def install_github_app() -> None:
750746

751747
else:
752748
click.prompt(
753-
f"Finally, you'll need install the Codeflash GitHub app by choosing the repository you want to install Codeflash on.{LF}"
749+
f"Finally, you'll need to install the Codeflash GitHub app by choosing the repository you want to install Codeflash on.{LF}"
754750
f"I will attempt to open the github app page - https://github.com/apps/codeflash-ai/installations/select_target {LF}"
755751
f"Press Enter to open the page to let you install the app…{LF}",
756752
default="",
@@ -924,6 +920,14 @@ def test_sort():
924920

925921

926922
def run_end_to_end_test(args: Namespace, bubble_sort_path: str, bubble_sort_test_path: str) -> None:
923+
try:
924+
check_formatter_installed(args.formatter_cmds)
925+
except Exception:
926+
logger.error(
927+
"Formatter not found. Review the formatter_cmds in your pyproject.toml file and make sure the formatter is installed."
928+
)
929+
return
930+
927931
command = ["codeflash", "--file", "bubble_sort.py", "--function", "sorter"]
928932
if args.no_pr:
929933
command.append("--no-pr")

codeflash/code_utils/env_utils.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,52 @@
11
from __future__ import annotations
22

33
import os
4+
import shlex
5+
import subprocess
6+
import tempfile
47
from functools import lru_cache
8+
from pathlib import Path
59
from typing import Optional
610

711
from codeflash.cli_cmds.console import logger
812
from codeflash.code_utils.shell_utils import read_api_key_from_shell_config
913

1014

15+
class FormatterNotFoundError(Exception):
16+
"""Exception raised when a formatter is not found."""
17+
18+
def __init__(self, formatter_cmd: str) -> None:
19+
super().__init__(f"Formatter command not found: {formatter_cmd}")
20+
21+
22+
def check_formatter_installed(formatter_cmds: list[str]) -> bool:
23+
return_code = True
24+
if formatter_cmds[0] == "disabled":
25+
return return_code
26+
tmp_code = """print("hello world")"""
27+
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", suffix=".py") as f:
28+
f.write(tmp_code)
29+
f.flush()
30+
tmp_file = Path(f.name)
31+
file_token = "$file" # noqa: S105
32+
for command in set(formatter_cmds):
33+
formatter_cmd_list = shlex.split(command, posix=os.name != "nt")
34+
formatter_cmd_list = [tmp_file.as_posix() if chunk == file_token else chunk for chunk in formatter_cmd_list]
35+
try:
36+
result = subprocess.run(formatter_cmd_list, capture_output=True, check=False)
37+
except (FileNotFoundError, NotADirectoryError):
38+
return_code = False
39+
break
40+
if result.returncode:
41+
return_code = False
42+
break
43+
tmp_file.unlink(missing_ok=True)
44+
if not return_code:
45+
msg = f"Error running formatter command: {command}"
46+
raise FormatterNotFoundError(msg)
47+
return return_code
48+
49+
1150
@lru_cache(maxsize=1)
1251
def get_codeflash_api_key() -> str:
1352
api_key = os.environ.get("CODEFLASH_API_KEY") or read_api_key_from_shell_config()

codeflash/optimization/function_optimizer.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ def determine_best_candidate(
392392
try:
393393
candidate_index = 0
394394
original_len = len(candidates)
395-
while True:
395+
while candidates:
396396
done = True if future_line_profile_results is None else future_line_profile_results.done()
397397
if done and (future_line_profile_results is not None):
398398
line_profile_results = future_line_profile_results.result()
@@ -402,13 +402,7 @@ def determine_best_candidate(
402402
f"Added results from line profiler to candidates, total candidates now: {original_len}"
403403
)
404404
future_line_profile_results = None
405-
try:
406-
candidate = candidates.popleft()
407-
except IndexError:
408-
if done:
409-
break
410-
time.sleep(0.1)
411-
continue
405+
candidate = candidates.popleft()
412406
candidate_index += 1
413407
get_run_tmp_file(Path(f"test_return_values_{candidate_index}.bin")).unlink(missing_ok=True)
414408
get_run_tmp_file(Path(f"test_return_values_{candidate_index}.sqlite")).unlink(missing_ok=True)
@@ -517,8 +511,17 @@ def determine_best_candidate(
517511
self.write_code_and_helpers(
518512
self.function_to_optimize_source_code, original_helper_code, self.function_to_optimize.file_path
519513
)
520-
if done and not candidates:
521-
break
514+
if (not len(candidates)) and (
515+
not done
516+
): # all original candidates processed but lp results haven't been processed
517+
concurrent.futures.wait([future_line_profile_results])
518+
line_profile_results = future_line_profile_results.result()
519+
candidates.extend(line_profile_results)
520+
original_len += len(line_profile_results)
521+
logger.info(
522+
f"Added results from line profiler to candidates, total candidates now: {original_len}"
523+
)
524+
future_line_profile_results = None
522525
except KeyboardInterrupt as e:
523526
self.write_code_and_helpers(
524527
self.function_to_optimize_source_code, original_helper_code, self.function_to_optimize.file_path

codeflash/optimization/optimizer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ def run(self) -> None:
8282
console.rule()
8383
if not env_utils.ensure_codeflash_api_key():
8484
return
85+
if not env_utils.check_formatter_installed(self.args.formatter_cmds):
86+
return
8587
function_optimizer = None
8688
file_to_funcs_to_optimize: dict[Path, list[FunctionToOptimize]]
8789
num_optimizable_functions: int

docs/docs/getting-started/local-installation.md

Lines changed: 124 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,26 @@ Codeflash is installed and configured on a per-project basis.
88

99
You can install Codeflash locally for a project by running the following command in the project's virtual environment:
1010

11+
### Prerequisites
12+
13+
Before installing Codeflash, ensure you have:
14+
15+
1. **Python 3.9 or above** installed
16+
2. **A Python project** with a virtual environment
17+
3. **Project dependencies installed** in your virtual environment
18+
4. **Tests** (optional) for your code (Codeflash uses tests to verify optimizations)
19+
20+
:::important[Virtual Environment Required]
21+
Always install Codeflash in your project's virtual environment, not globally. Make sure your virtual environment is activated before proceeding.
22+
23+
```bash
24+
# Example: Activate your virtual environment
25+
source venv/bin/activate # On Linux/Mac
26+
# or
27+
#venv\Scripts\activate # On Windows
28+
```
29+
:::
30+
### Step 1: Install Codeflash
1131
```bash
1232
pip install codeflash
1333
```
@@ -16,22 +36,39 @@ pip install codeflash
1636
We recommend installing Codeflash as a development dependency.
1737
It doesn't need to be installed as part of your package requirements.
1838
Codeflash is intended to be used locally and as part of development workflows such as CI.
39+
If using pyproject.toml:
40+
```toml
41+
[tool.poetry.dependencies.dev]
42+
codeflash = "^latest"
43+
```
44+
Or with pip:
45+
```bash
46+
pip install --dev codeflash
47+
````
1948
:::
2049

21-
## Generate a Codeflash API Key
50+
### Step 2: Generate a Codeflash API Key
2251

23-
Since Codeflash uses advanced Large Language Models (LLMs) that are hosted in the cloud, you will need to generate an API key to use Codeflash.
52+
Codeflash uses cloud-hosted AI models to optimize your code. You'll need an API key to use it.
2453
25-
To generate an API key, visit the [Codeflash Web App](https://app.codeflash.ai/) and sign up for an account with GitHub login.
54+
1. Visit the [Codeflash Web App](https://app.codeflash.ai/)
55+
2. Sign up with your GitHub account (free)
56+
3. Navigate to the [API Key](https://app.codeflash.ai/app/apikeys) page to generate your API key
2657
<!--- TODO: Do we ask for access to specific repositories here? --->
27-
Once you have signed up, you will be able to generate an API key from the [API Key](https://app.codeflash.ai/app/apikeys) page.
28-
You will need the API key in the next step.
2958
30-
## Automatic Configuration
59+
:::note[Free Tier Available]
60+
Codeflash offers a **free tier** with a limited number of optimizations per month. Perfect for trying it out or small projects!
61+
:::
62+
63+
### Step 3: Automatic Configuration
3164
32-
To configure Codeflash for a project, in the root directory of your project where your `pyproject.toml` file is located, run the following command :
65+
Navigate to your project's root directory (where your `pyproject.toml` file is or should be) and run:
3366

3467
```bash
68+
# Make sure you're in your project root
69+
cd /path/to/your/project
70+
71+
# Run the initialization
3572
codeflash init
3673
```
3774

@@ -56,11 +93,90 @@ After you have answered these questions, Codeflash will be configured for your p
5693
The configuration will be saved in the `pyproject.toml` file in the root directory of your project.
5794
To understand the configuration options, and set more advanced options, see the [Configuration](/configuration) page.
5895
59-
## Install the Codeflash GitHub App
96+
### Step 4: Install the Codeflash GitHub App
6097
98+
<!--- TODO: Justify to users Why we need the user to install Github App even in local Installation or local optimization? --->
6199
Finally, if you have not done so already, Codeflash will ask you to install the Github App in your repository. The Codeflash GitHub App allows access to your repository to the codeflash-ai bot to open PRs, review code, and provide optimization suggestions.
62100
63101
Please [install the Codeflash GitHub
64102
app](https://github.com/apps/codeflash-ai/installations/select_target) by choosing the repository you want to install
65103
Codeflash on.
66104
##
105+
106+
## Try It Out!
107+
108+
Once configured, you can start optimizing your code:
109+
110+
```bash
111+
# Optimize a specific function
112+
codeflash --file path/to/your/file.py --function function_name
113+
114+
# Or if want to optimize only locally without creating a PR
115+
codeflash --file path/to/your/file.py --function function_name --no-pr
116+
```
117+
118+
### Example Project
119+
120+
Want to see Codeflash in action? Check out our example repository:
121+
122+
🔗 [github.com/codeflash-ai/optimize-me](https://github.com/codeflash-ai/optimize-me)
123+
124+
This repo includes:
125+
- Sample Python code with performance issues
126+
- Tests for verification
127+
- Pre-configured `pyproject.toml`
128+
- Before/after optimization examples in PRs
129+
130+
Clone it and try running:
131+
```bash
132+
git clone https://github.com/codeflash-ai/optimize-me.git
133+
cd optimize-me
134+
python -m venv .venv
135+
source .venv/bin/activate # or venv\Scripts\activate on Windows
136+
pip install -r requirements.txt
137+
pip install codeflash
138+
codeflash init # Use your own API key
139+
codeflash --all # optimize the entire repo
140+
```
141+
142+
### 🔧 Troubleshooting
143+
144+
#### 📦 "Module not found" errors
145+
Make sure:
146+
- ✅ Your virtual environment is activated
147+
- ✅ All project dependencies are installed
148+
- ✅ You're running `codeflash` from your project root
149+
150+
#### 🧪 "No optimizations found" or debugging issues
151+
Use the `--verbose` flag for detailed output:
152+
```bash
153+
codeflash optimize --verbose
154+
```
155+
156+
This will show:
157+
- 🔍 Which functions are being analyzed
158+
- 🚫 Why certain functions were skipped
159+
- ⚠️ Detailed error messages
160+
- 📊 Performance analysis results
161+
162+
#### 🔍 "No tests found" errors
163+
Verify:
164+
- 📁 Your test directory path is correct in `pyproject.toml`
165+
- 🔍 Tests are discoverable by your test framework
166+
- 📝 Test files follow naming conventions (`test_*.py` for pytest)
167+
168+
#### ⚙️ Configuration issues
169+
Check your `pyproject.toml`:
170+
```toml
171+
[tool.codeflash]
172+
module = "my_package"
173+
test-framework = "pytest"
174+
tests = "tests/"
175+
```
176+
177+
### Next Steps
178+
179+
- Learn about [Codeflash Concepts](/codeflash-concepts/how-codeflash-works)
180+
- Explore [optimization workflows](/optimizing-with-codeflash/one-function)
181+
- Set up [GitHub Actions integration](/getting-started/codeflash-github-actions)
182+
- Read [configuration options](/configuration) for advanced setups

docs/src/css/custom.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@
2828
--ifm-color-primary-lightest: #FFECB3;
2929
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
3030
}
31+
32+
[data-theme='dark'] {
33+
/* Attempt to override Algolia's own CSS variables for the selected item's background */
34+
--docsearch-highlight-color: #d08e0d !important;
35+
}

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ init_typed = true
151151
warn_required_dynamic_aliases = true
152152

153153
[tool.ruff]
154+
target-version = "py39"
154155
line-length = 120
155156
fix = true
156157
show-fixes = true

0 commit comments

Comments
 (0)