lean-explore 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl

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.
@@ -6,7 +6,8 @@ This module provides functions to save and load user-specific settings,
6
6
  such as API keys for Lean Explore and OpenAI, from a configuration
7
7
  file stored in the user's home directory. It handles file creation,
8
8
  parsing, and sets secure permissions for files containing sensitive
9
- information.
9
+ information. It also supports loading API keys from environment
10
+ variables as a fallback if they are not found in the configuration file.
10
11
  """
11
12
 
12
13
  import logging
@@ -23,12 +24,14 @@ _APP_CONFIG_DIR_NAME: str = "leanexplore"
23
24
  _CONFIG_FILENAME: str = "config.toml"
24
25
 
25
26
  # Define keys for Lean Explore API section
26
- _LEAN_EXPLORE_API_SECTION_NAME: str = "lean_explore_api" # Renamed for clarity
27
+ _LEAN_EXPLORE_API_SECTION_NAME: str = "lean_explore_api"
27
28
  _LEAN_EXPLORE_API_KEY_NAME: str = "key"
29
+ _LEAN_EXPLORE_API_KEY_ENV_VAR: str = "LEANEXPLORE_API_KEY"
28
30
 
29
31
  # Define keys for OpenAI API section
30
32
  _OPENAI_API_SECTION_NAME: str = "openai"
31
- _OPENAI_API_KEY_NAME: str = "api_key" # Using a distinct key name for clarity
33
+ _OPENAI_API_KEY_NAME: str = "api_key"
34
+ _OPENAI_API_KEY_ENV_VAR: str = "OPENAI_API_KEY"
32
35
 
33
36
 
34
37
  def get_config_file_path() -> pathlib.Path:
@@ -83,7 +86,6 @@ def _load_config_data(config_file_path: pathlib.Path) -> Dict[str, Any]:
83
86
  "Configuration file %s is corrupted. Treating as empty.",
84
87
  config_file_path,
85
88
  )
86
- # Potentially back up corrupted file before returning empty
87
89
  except Exception as e:
88
90
  logger.error(
89
91
  "Error reading existing config file %s: %s",
@@ -91,7 +93,6 @@ def _load_config_data(config_file_path: pathlib.Path) -> Dict[str, Any]:
91
93
  e,
92
94
  exc_info=True,
93
95
  )
94
- # Decide if to proceed with empty or raise further
95
96
  return config_data
96
97
 
97
98
 
@@ -162,9 +163,7 @@ def save_api_key(api_key: str) -> bool:
162
163
  if _save_config_data(config_file_path, config_data):
163
164
  logger.info("Lean Explore API key saved to %s", config_file_path)
164
165
  return True
165
- except (
166
- Exception
167
- ) as e: # Catch any exception from _ensure_config_dir_exists or broad issues
166
+ except Exception as e:
168
167
  logger.error(
169
168
  "General error during Lean Explore API key saving process: %s",
170
169
  e,
@@ -174,50 +173,86 @@ def save_api_key(api_key: str) -> bool:
174
173
 
175
174
 
176
175
  def load_api_key() -> Optional[str]:
177
- """Loads the Lean Explore API key from the user's configuration file.
176
+ """Loads the Lean Explore API key.
177
+
178
+ It first checks the user's configuration file (typically
179
+ ~/.config/leanexplore/config.toml under the section
180
+ `lean_explore_api` with key `key`). If a valid, non-empty API key
181
+ is found there, it is returned.
182
+
183
+ If the API key is not found in the configuration file, is empty,
184
+ or is not a string, this function then checks the environment
185
+ variable `LEAN_EXPLORE_API_KEY`. If this environment variable is
186
+ set to a non-empty string, its value is returned.
187
+
188
+ If the API key is not found or is invalid in both locations,
189
+ None is returned.
178
190
 
179
191
  Returns:
180
192
  Optional[str]: The Lean Explore API key string if found and valid,
181
193
  otherwise None.
182
194
  """
183
195
  config_file_path = get_config_file_path()
184
- if not config_file_path.exists() or not config_file_path.is_file():
185
- logger.debug(
186
- "Configuration file not found at %s for Lean Explore API key.",
187
- config_file_path,
188
- )
189
- return None
190
196
 
191
- try:
192
- config_data = _load_config_data(config_file_path)
193
- api_key = config_data.get(_LEAN_EXPLORE_API_SECTION_NAME, {}).get(
194
- _LEAN_EXPLORE_API_KEY_NAME
195
- )
196
-
197
- if api_key and isinstance(api_key, str):
198
- logger.debug(
199
- "Lean Explore API key loaded successfully from %s", config_file_path
200
- )
201
- return api_key
202
- elif api_key: # Found but not a string
203
- logger.warning(
204
- "Lean Explore API key found in %s but is not a valid string.",
205
- config_file_path,
197
+ # 1. Try loading from config file
198
+ if config_file_path.exists() and config_file_path.is_file():
199
+ try:
200
+ config_data = _load_config_data(config_file_path)
201
+ key_value = config_data.get(_LEAN_EXPLORE_API_SECTION_NAME, {}).get(
202
+ _LEAN_EXPLORE_API_KEY_NAME
206
203
  )
207
- else: # Not found under the expected keys
208
- logger.debug(
209
- "Lean Explore API key not found under section '%s', key '%s' in %s",
210
- _LEAN_EXPLORE_API_SECTION_NAME,
211
- _LEAN_EXPLORE_API_KEY_NAME,
204
+
205
+ if isinstance(key_value, str) and key_value: # Non-empty string
206
+ logger.debug(
207
+ "Lean Explore API key loaded from configuration file %s",
208
+ config_file_path,
209
+ )
210
+ return key_value
211
+ elif key_value is not None: # Present but not a valid non-empty string
212
+ logger.warning(
213
+ "Lean Explore API key found in %s but is not a valid "
214
+ "non-empty string. "
215
+ "Will check environment variable %s.",
216
+ config_file_path,
217
+ _LEAN_EXPLORE_API_KEY_ENV_VAR,
218
+ )
219
+ except Exception as e: # Catch unexpected errors during config processing
220
+ logger.error(
221
+ "Error processing configuration file %s for Lean Explore API key: %s. "
222
+ "Will check environment variable %s.",
212
223
  config_file_path,
224
+ e,
225
+ _LEAN_EXPLORE_API_KEY_ENV_VAR,
226
+ exc_info=True,
213
227
  )
214
- except Exception as e: # Catch any other unexpected errors during loading
215
- logger.error(
216
- "Unexpected error loading Lean Explore API key from %s: %s",
228
+ else:
229
+ logger.debug(
230
+ "Configuration file %s not found. Will check environment "
231
+ "variable %s for Lean Explore API key.",
217
232
  config_file_path,
218
- e,
219
- exc_info=True,
233
+ _LEAN_EXPLORE_API_KEY_ENV_VAR,
220
234
  )
235
+
236
+ # 2. Try loading from environment variable
237
+ api_key_from_env = os.getenv(_LEAN_EXPLORE_API_KEY_ENV_VAR)
238
+
239
+ if isinstance(api_key_from_env, str) and api_key_from_env: # Non-empty string
240
+ logger.debug(
241
+ "Lean Explore API key loaded from environment variable %s",
242
+ _LEAN_EXPLORE_API_KEY_ENV_VAR,
243
+ )
244
+ return api_key_from_env
245
+ elif api_key_from_env is not None: # Env var exists but is empty string
246
+ logger.debug(
247
+ "Environment variable %s for Lean Explore API key is set but empty.",
248
+ _LEAN_EXPLORE_API_KEY_ENV_VAR,
249
+ )
250
+
251
+ logger.debug(
252
+ "Lean Explore API key not found in configuration file or "
253
+ "valid in environment variable %s.",
254
+ _LEAN_EXPLORE_API_KEY_ENV_VAR,
255
+ )
221
256
  return None
222
257
 
223
258
 
@@ -262,7 +297,7 @@ def delete_api_key() -> bool:
262
297
  "Lean Explore API key not found in %s, no deletion performed.",
263
298
  config_file_path,
264
299
  )
265
- return True # Key wasn't there, so considered successful
300
+ return True
266
301
 
267
302
  except Exception as e:
268
303
  logger.error(
@@ -316,46 +351,84 @@ def save_openai_api_key(api_key: str) -> bool:
316
351
 
317
352
 
318
353
  def load_openai_api_key() -> Optional[str]:
319
- """Loads the OpenAI API key from the user's configuration file.
354
+ """Loads the OpenAI API key.
355
+
356
+ It first checks the user's configuration file (typically
357
+ ~/.config/leanexplore/config.toml under the section
358
+ `openai` with key `api_key`). If a valid, non-empty API key
359
+ is found there, it is returned.
360
+
361
+ If the API key is not found in the configuration file, is empty,
362
+ or is not a string, this function then checks the environment
363
+ variable `OPENAI_API_KEY`. If this environment variable is
364
+ set to a non-empty string, its value is returned.
365
+
366
+ If the API key is not found or is invalid in both locations,
367
+ None is returned.
320
368
 
321
369
  Returns:
322
370
  Optional[str]: The OpenAI API key string if found and valid, otherwise None.
323
371
  """
324
372
  config_file_path = get_config_file_path()
325
- if not config_file_path.exists() or not config_file_path.is_file():
326
- logger.debug(
327
- "Configuration file not found at %s for OpenAI API key.", config_file_path
328
- )
329
- return None
330
373
 
331
- try:
332
- config_data = _load_config_data(config_file_path)
333
- api_key = config_data.get(_OPENAI_API_SECTION_NAME, {}).get(
334
- _OPENAI_API_KEY_NAME
335
- )
336
-
337
- if api_key and isinstance(api_key, str):
338
- logger.debug("OpenAI API key loaded successfully from %s", config_file_path)
339
- return api_key
340
- elif api_key: # Found but not a string
341
- logger.warning(
342
- "OpenAI API key found in %s but is not a valid string.",
343
- config_file_path,
374
+ # 1. Try loading from config file
375
+ if config_file_path.exists() and config_file_path.is_file():
376
+ try:
377
+ config_data = _load_config_data(config_file_path)
378
+ key_value = config_data.get(_OPENAI_API_SECTION_NAME, {}).get(
379
+ _OPENAI_API_KEY_NAME
344
380
  )
345
- else: # Not found under the expected keys
346
- logger.debug(
347
- "OpenAI API key not found under section '%s', key '%s' in %s",
348
- _OPENAI_API_SECTION_NAME,
349
- _OPENAI_API_KEY_NAME,
381
+
382
+ if isinstance(key_value, str) and key_value: # Non-empty string
383
+ logger.debug(
384
+ "OpenAI API key loaded from configuration file %s",
385
+ config_file_path,
386
+ )
387
+ return key_value
388
+ elif key_value is not None: # Present but not a valid non-empty string
389
+ logger.warning(
390
+ "OpenAI API key found in %s but is not a valid non-empty string. "
391
+ "Will check environment variable %s.",
392
+ config_file_path,
393
+ _OPENAI_API_KEY_ENV_VAR,
394
+ )
395
+ except Exception as e: # Catch unexpected errors during config processing
396
+ logger.error(
397
+ "Error processing configuration file %s for OpenAI API key: %s. "
398
+ "Will check environment variable %s.",
350
399
  config_file_path,
400
+ e,
401
+ _OPENAI_API_KEY_ENV_VAR,
402
+ exc_info=True,
351
403
  )
352
- except Exception as e:
353
- logger.error(
354
- "Unexpected error loading OpenAI API key from %s: %s",
404
+ else:
405
+ logger.debug(
406
+ "Configuration file %s not found. Will check environment "
407
+ "variable %s for OpenAI API key.",
355
408
  config_file_path,
356
- e,
357
- exc_info=True,
409
+ _OPENAI_API_KEY_ENV_VAR,
358
410
  )
411
+
412
+ # 2. Try loading from environment variable
413
+ api_key_from_env = os.getenv(_OPENAI_API_KEY_ENV_VAR)
414
+
415
+ if isinstance(api_key_from_env, str) and api_key_from_env: # Non-empty string
416
+ logger.debug(
417
+ "OpenAI API key loaded from environment variable %s",
418
+ _OPENAI_API_KEY_ENV_VAR,
419
+ )
420
+ return api_key_from_env
421
+ elif api_key_from_env is not None: # Env var exists but is empty string
422
+ logger.debug(
423
+ "Environment variable %s for OpenAI API key is set but empty.",
424
+ _OPENAI_API_KEY_ENV_VAR,
425
+ )
426
+
427
+ logger.debug(
428
+ "OpenAI API key not found in configuration file or valid in "
429
+ "environment variable %s.",
430
+ _OPENAI_API_KEY_ENV_VAR,
431
+ )
359
432
  return None
360
433
 
361
434
 
@@ -396,7 +469,7 @@ def delete_openai_api_key() -> bool:
396
469
  "OpenAI API key not found in %s, no deletion performed.",
397
470
  config_file_path,
398
471
  )
399
- return True # Key wasn't there, so considered successful
472
+ return True
400
473
 
401
474
  except Exception as e:
402
475
  logger.error(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-explore
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A project to explore and rank Lean mathematical declarations.
5
5
  Author-email: Justin Asher <justinchadwickasher@gmail.com>
6
6
  License: Apache License
@@ -213,15 +213,13 @@ Classifier: Intended Audience :: Developers
213
213
  Classifier: Intended Audience :: Science/Research
214
214
  Classifier: License :: OSI Approved :: Apache Software License
215
215
  Classifier: Programming Language :: Python :: 3
216
- Classifier: Programming Language :: Python :: 3.8
217
- Classifier: Programming Language :: Python :: 3.9
218
216
  Classifier: Programming Language :: Python :: 3.10
219
217
  Classifier: Programming Language :: Python :: 3.11
220
218
  Classifier: Programming Language :: Python :: 3.12
221
219
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
222
220
  Classifier: Topic :: Scientific/Engineering :: Mathematics
223
221
  Classifier: Topic :: Text Processing :: Indexing
224
- Requires-Python: >=3.8
222
+ Requires-Python: >=3.10
225
223
  Description-Content-Type: text/markdown
226
224
  License-File: LICENSE
227
225
  Requires-Dist: sqlalchemy>=2.0
@@ -4,7 +4,7 @@ lean_explore/api/__init__.py,sha256=LK4g9wj7jCilTUfQcdQAxDf3F2GjMwzQZJYgnQ8ciGo,
4
4
  lean_explore/api/client.py,sha256=AgZG7pUY53Tl1WOhJgUdT0yxa_O1sHsals0pnjRD-Pc,4839
5
5
  lean_explore/cli/__init__.py,sha256=LK4g9wj7jCilTUfQcdQAxDf3F2GjMwzQZJYgnQ8ciGo,38
6
6
  lean_explore/cli/agent.py,sha256=jf1ebnViAqtKcZAGArqBf9YKHPbsOTpffOXr0Cd2M3Q,29933
7
- lean_explore/cli/config_utils.py,sha256=_g2aVMM1MyTWJCOVQj_jndI6ZA_Ct09WvpLsP2FFlSM,13643
7
+ lean_explore/cli/config_utils.py,sha256=RyIaDNP1UpUQZoy7HfaZ_JOXUgtzUP51Zrq_s6q7urY,16639
8
8
  lean_explore/cli/data_commands.py,sha256=mTBqFU7-fF4ZBGzCmNawZA_eHy0jyEMLlBEDEBXpxwY,21462
9
9
  lean_explore/cli/main.py,sha256=ZdbXy8x2VQ--JARqJMa9iFnrOhOCLcVgjpWhXkxj80o,24323
10
10
  lean_explore/local/__init__.py,sha256=LK4g9wj7jCilTUfQcdQAxDf3F2GjMwzQZJYgnQ8ciGo,38
@@ -18,9 +18,9 @@ lean_explore/shared/__init__.py,sha256=LK4g9wj7jCilTUfQcdQAxDf3F2GjMwzQZJYgnQ8ci
18
18
  lean_explore/shared/models/__init__.py,sha256=LK4g9wj7jCilTUfQcdQAxDf3F2GjMwzQZJYgnQ8ciGo,38
19
19
  lean_explore/shared/models/api.py,sha256=jejNDpgj-cu0KZTqkuOjM0useN4EvhvNB19lFFAOV94,4635
20
20
  lean_explore/shared/models/db.py,sha256=JYfIBnPrHZO2j7gHAVMlw9WSqVC2NinCG5KuBzdQWyk,16099
21
- lean_explore-0.2.0.dist-info/licenses/LICENSE,sha256=l4QLw1kIvEOjUktmmKm4dycK1E249Qs2s2AQTYbMXpY,11354
22
- lean_explore-0.2.0.dist-info/METADATA,sha256=5mCWCIY9zhB7Q2F1Y9mZ9efjKjVPYnQhx2OYP8Gb1sw,15611
23
- lean_explore-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- lean_explore-0.2.0.dist-info/entry_points.txt,sha256=JXl2Mo3BRX4jAU-Nxg_CWJR790pB_oi5qnt3Pv5iZnk,58
25
- lean_explore-0.2.0.dist-info/top_level.txt,sha256=h51BKWrFvB7iym-IlaNAAHX5MZfA8Gmg-aDuXGo0fQ8,13
26
- lean_explore-0.2.0.dist-info/RECORD,,
21
+ lean_explore-0.2.2.dist-info/licenses/LICENSE,sha256=l4QLw1kIvEOjUktmmKm4dycK1E249Qs2s2AQTYbMXpY,11354
22
+ lean_explore-0.2.2.dist-info/METADATA,sha256=SlZZqUVDTwZmx_LftmAb3yobtTbZMvFfeTQYB1Hnuvs,15512
23
+ lean_explore-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
+ lean_explore-0.2.2.dist-info/entry_points.txt,sha256=JXl2Mo3BRX4jAU-Nxg_CWJR790pB_oi5qnt3Pv5iZnk,58
25
+ lean_explore-0.2.2.dist-info/top_level.txt,sha256=h51BKWrFvB7iym-IlaNAAHX5MZfA8Gmg-aDuXGo0fQ8,13
26
+ lean_explore-0.2.2.dist-info/RECORD,,