m7n commited on
Commit
d1ed09d
·
0 Parent(s):

first commit

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. README.md +1 -0
  2. app.py +557 -0
  3. data_setup.py +117 -0
  4. openalex_env_map/lib/python3.10/site-packages/IPython/__init__.py +163 -0
  5. openalex_env_map/lib/python3.10/site-packages/IPython/__main__.py +15 -0
  6. openalex_env_map/lib/python3.10/site-packages/IPython/conftest.py +87 -0
  7. openalex_env_map/lib/python3.10/site-packages/IPython/consoleapp.py +12 -0
  8. openalex_env_map/lib/python3.10/site-packages/IPython/core/__init__.py +0 -0
  9. openalex_env_map/lib/python3.10/site-packages/IPython/core/alias.py +267 -0
  10. openalex_env_map/lib/python3.10/site-packages/IPython/core/application.py +492 -0
  11. openalex_env_map/lib/python3.10/site-packages/IPython/core/async_helpers.py +155 -0
  12. openalex_env_map/lib/python3.10/site-packages/IPython/core/autocall.py +70 -0
  13. openalex_env_map/lib/python3.10/site-packages/IPython/core/builtin_trap.py +86 -0
  14. openalex_env_map/lib/python3.10/site-packages/IPython/core/compilerop.py +214 -0
  15. openalex_env_map/lib/python3.10/site-packages/IPython/core/completer.py +0 -0
  16. openalex_env_map/lib/python3.10/site-packages/IPython/core/completerlib.py +382 -0
  17. openalex_env_map/lib/python3.10/site-packages/IPython/core/crashhandler.py +248 -0
  18. openalex_env_map/lib/python3.10/site-packages/IPython/core/debugger.py +1136 -0
  19. openalex_env_map/lib/python3.10/site-packages/IPython/core/display.py +1373 -0
  20. openalex_env_map/lib/python3.10/site-packages/IPython/core/display_functions.py +391 -0
  21. openalex_env_map/lib/python3.10/site-packages/IPython/core/display_trap.py +70 -0
  22. openalex_env_map/lib/python3.10/site-packages/IPython/core/displayhook.py +336 -0
  23. openalex_env_map/lib/python3.10/site-packages/IPython/core/displaypub.py +149 -0
  24. openalex_env_map/lib/python3.10/site-packages/IPython/core/error.py +60 -0
  25. openalex_env_map/lib/python3.10/site-packages/IPython/core/events.py +158 -0
  26. openalex_env_map/lib/python3.10/site-packages/IPython/core/excolors.py +192 -0
  27. openalex_env_map/lib/python3.10/site-packages/IPython/core/extensions.py +135 -0
  28. openalex_env_map/lib/python3.10/site-packages/IPython/core/formatters.py +1090 -0
  29. openalex_env_map/lib/python3.10/site-packages/IPython/core/getipython.py +24 -0
  30. openalex_env_map/lib/python3.10/site-packages/IPython/core/guarded_eval.py +895 -0
  31. openalex_env_map/lib/python3.10/site-packages/IPython/core/history.py +989 -0
  32. openalex_env_map/lib/python3.10/site-packages/IPython/core/historyapp.py +158 -0
  33. openalex_env_map/lib/python3.10/site-packages/IPython/core/hooks.py +173 -0
  34. openalex_env_map/lib/python3.10/site-packages/IPython/core/inputsplitter.py +799 -0
  35. openalex_env_map/lib/python3.10/site-packages/IPython/core/inputtransformer.py +577 -0
  36. openalex_env_map/lib/python3.10/site-packages/IPython/core/inputtransformer2.py +830 -0
  37. openalex_env_map/lib/python3.10/site-packages/IPython/core/interactiveshell.py +0 -0
  38. openalex_env_map/lib/python3.10/site-packages/IPython/core/latex_symbols.py +1301 -0
  39. openalex_env_map/lib/python3.10/site-packages/IPython/core/logger.py +231 -0
  40. openalex_env_map/lib/python3.10/site-packages/IPython/core/macro.py +53 -0
  41. openalex_env_map/lib/python3.10/site-packages/IPython/core/magic.py +759 -0
  42. openalex_env_map/lib/python3.10/site-packages/IPython/core/magic_arguments.py +310 -0
  43. openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/__init__.py +42 -0
  44. openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/ast_mod.py +330 -0
  45. openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/auto.py +144 -0
  46. openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/basic.py +666 -0
  47. openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/code.py +757 -0
  48. openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/config.py +140 -0
  49. openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/display.py +93 -0
  50. openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/execution.py +1624 -0
README.md ADDED
@@ -0,0 +1 @@
 
 
1
+ ...
app.py ADDED
@@ -0,0 +1,557 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ print(f"Starting up: {time.strftime('%Y-%m-%d %H:%M:%S')}")
3
+
4
+ # Standard library imports
5
+ import os
6
+ from pathlib import Path
7
+ from datetime import datetime
8
+ from itertools import chain
9
+
10
+ # Third-party imports
11
+ import numpy as np
12
+ import pandas as pd
13
+ import torch
14
+ import gradio as gr
15
+ from fastapi import FastAPI
16
+ from fastapi.staticfiles import StaticFiles
17
+ import uvicorn
18
+ import matplotlib.pyplot as plt
19
+ import tqdm
20
+ import colormaps
21
+ import matplotlib.colors as mcolors
22
+
23
+
24
+ import opinionated # for fonts
25
+ plt.style.use("opinionated_rc")
26
+
27
+ from sklearn.neighbors import NearestNeighbors
28
+
29
+
30
+ def is_running_in_hf_space():
31
+ return "SPACE_ID" in os.environ
32
+
33
+ if is_running_in_hf_space():
34
+ import spaces # necessary to run on Zero.
35
+
36
+ import datamapplot
37
+ import pyalex
38
+
39
+ # Local imports
40
+ from openalex_utils import (
41
+ openalex_url_to_pyalex_query,
42
+ get_field,
43
+ process_records_to_df,
44
+ openalex_url_to_filename
45
+ )
46
+ from styles import DATAMAP_CUSTOM_CSS
47
+ from data_setup import (
48
+ download_required_files,
49
+ setup_basemap_data,
50
+ setup_mapper,
51
+ setup_embedding_model,
52
+
53
+ )
54
+
55
+ # Configure OpenAlex
56
+ pyalex.config.email = "[email protected]"
57
+
58
+ print(f"Imports completed: {time.strftime('%Y-%m-%d %H:%M:%S')}")
59
+
60
+ # FastAPI setup
61
+ app = FastAPI()
62
+ static_dir = Path('./static')
63
+ static_dir.mkdir(parents=True, exist_ok=True)
64
+ app.mount("/static", StaticFiles(directory=static_dir), name="static")
65
+
66
+ # Gradio configuration
67
+ gr.set_static_paths(paths=["static/"])
68
+
69
+ # Resource configuration
70
+ REQUIRED_FILES = {
71
+ "100k_filtered_OA_sample_cluster_and_positions_supervised.pkl":
72
+ "https://huggingface.co/datasets/m7n/intermediate_sci_pickle/resolve/main/100k_filtered_OA_sample_cluster_and_positions_supervised.pkl",
73
+ "umap_mapper_250k_random_OA_discipline_tuned_specter_2_params.pkl":
74
+ "https://huggingface.co/datasets/m7n/intermediate_sci_pickle/resolve/main/umap_mapper_250k_random_OA_discipline_tuned_specter_2_params.pkl"
75
+ }
76
+ BASEMAP_PATH = "100k_filtered_OA_sample_cluster_and_positions_supervised.pkl"
77
+ MAPPER_PARAMS_PATH = "umap_mapper_250k_random_OA_discipline_tuned_specter_2_params.pkl"
78
+ MODEL_NAME = "m7n/discipline-tuned_specter_2_024"
79
+
80
+ # Initialize models and data
81
+ start_time = time.time()
82
+ print("Initializing resources...")
83
+
84
+ download_required_files(REQUIRED_FILES)
85
+ basedata_df = setup_basemap_data(BASEMAP_PATH)
86
+ mapper = setup_mapper(MAPPER_PARAMS_PATH)
87
+ model = setup_embedding_model(MODEL_NAME)
88
+
89
+ print(f"Resources initialized in {time.time() - start_time:.2f} seconds")
90
+
91
+
92
+
93
+ # Setting up decorators for embedding on HF-Zero:
94
+ def no_op_decorator(func):
95
+ """A no-op (no operation) decorator that simply returns the function."""
96
+ def wrapper(*args, **kwargs):
97
+ # Do nothing special
98
+ return func(*args, **kwargs)
99
+ return wrapper
100
+
101
+ # Decide which decorator to use based on environment
102
+ decorator_to_use = spaces.GPU(duration=60) if is_running_in_hf_space() else no_op_decorator
103
+
104
+
105
+ @decorator_to_use
106
+ def create_embeddings(texts_to_embedd):
107
+ """Create embeddings for the input texts using the loaded model."""
108
+ return model.encode(texts_to_embedd, show_progress_bar=True, batch_size=192)
109
+
110
+ def predict(text_input, sample_size_slider, reduce_sample_checkbox, sample_reduction_method,
111
+ plot_time_checkbox, locally_approximate_publication_date_checkbox,
112
+ download_csv_checkbox, download_png_checkbox, progress=gr.Progress()):
113
+ """
114
+ Main prediction pipeline that processes OpenAlex queries and creates visualizations.
115
+
116
+ Args:
117
+ text_input (str): OpenAlex query URL
118
+ sample_size_slider (int): Maximum number of samples to process
119
+ reduce_sample_checkbox (bool): Whether to reduce sample size
120
+ sample_reduction_method (str): Method for sample reduction ("Random" or "Order of Results")
121
+ plot_time_checkbox (bool): Whether to color points by publication date
122
+ locally_approximate_publication_date_checkbox (bool): Whether to approximate publication date locally before plotting.
123
+ progress (gr.Progress): Gradio progress tracker
124
+
125
+ Returns:
126
+ tuple: (link to visualization, iframe HTML)
127
+ """
128
+ # Check if input is empty or whitespace
129
+ print(f"Input: {text_input}")
130
+ if not text_input or text_input.isspace():
131
+ return "Error: Please enter a valid OpenAlex URL in the 'OpenAlex-search URL'-field", gr.DownloadButton(label=f"Download Interactive Visualization", value='html_file_path', visible=False)
132
+
133
+
134
+ # Check if the input is a valid OpenAlex URL
135
+
136
+
137
+
138
+ start_time = time.time()
139
+ print('Starting data projection pipeline')
140
+ progress(0.1, desc="Starting...")
141
+
142
+ # Query OpenAlex
143
+ query_start = time.time()
144
+ query, params = openalex_url_to_pyalex_query(text_input)
145
+
146
+ filename = openalex_url_to_filename(text_input)
147
+ print(f"Filename: {filename}")
148
+
149
+ query_length = query.count()
150
+ print(f'Requesting {query_length} entries...')
151
+
152
+ records = []
153
+ target_size = sample_size_slider if reduce_sample_checkbox and sample_reduction_method == "First n samples" else query_length
154
+
155
+
156
+ should_break = False
157
+ for page in query.paginate(per_page=200,n_max=None):
158
+ for record in page:
159
+ records.append(record)
160
+ progress(0.1 + (0.2 * len(records) / target_size), desc="Getting queried data...")
161
+ # print(len(records))
162
+ if reduce_sample_checkbox and sample_reduction_method == "First n samples" and len(records) >= target_size:
163
+ should_break = True
164
+ break
165
+ if should_break:
166
+ break
167
+
168
+ print(f"Query completed in {time.time() - query_start:.2f} seconds")
169
+
170
+ # Process records
171
+ processing_start = time.time()
172
+ records_df = process_records_to_df(records)
173
+
174
+ if reduce_sample_checkbox and sample_reduction_method != "All":
175
+ sample_size = min(sample_size_slider, len(records_df))
176
+ if sample_reduction_method == "n random samples":
177
+ records_df = records_df.sample(sample_size)
178
+ elif sample_reduction_method == "First n samples":
179
+ records_df = records_df.iloc[:sample_size]
180
+ print(f"Records processed in {time.time() - processing_start:.2f} seconds")
181
+
182
+ # Create embeddings
183
+ embedding_start = time.time()
184
+ progress(0.3, desc="Embedding Data...")
185
+ texts_to_embedd = [f"{title} {abstract}" for title, abstract
186
+ in zip(records_df['title'], records_df['abstract'])]
187
+ embeddings = create_embeddings(texts_to_embedd)
188
+ print(f"Embeddings created in {time.time() - embedding_start:.2f} seconds")
189
+
190
+ # Project embeddings
191
+ projection_start = time.time()
192
+ progress(0.5, desc="Project into UMAP-embedding...")
193
+ umap_embeddings = mapper.transform(embeddings)
194
+ records_df[['x','y']] = umap_embeddings
195
+ print(f"Projection completed in {time.time() - projection_start:.2f} seconds")
196
+
197
+ # Prepare visualization data
198
+ viz_prep_start = time.time()
199
+ progress(0.6, desc="Preparing visualization data...")
200
+
201
+ basedata_df['color'] = '#ced4d211'
202
+
203
+ if not plot_time_checkbox:
204
+ records_df['color'] = '#5e2784'
205
+ else:
206
+ cmap = colormaps.haline
207
+ if not locally_approximate_publication_date_checkbox:
208
+ # Create color mapping based on publication years
209
+ years = pd.to_numeric(records_df['publication_year'])
210
+ norm = mcolors.Normalize(vmin=years.min(), vmax=years.max())
211
+ records_df['color'] = [mcolors.to_hex(cmap(norm(year))) for year in years]
212
+
213
+ else:
214
+ n_neighbors = 10 # Adjust this value to control smoothing
215
+ nn = NearestNeighbors(n_neighbors=n_neighbors)
216
+ nn.fit(umap_embeddings)
217
+ distances, indices = nn.kneighbors(umap_embeddings)
218
+
219
+ # Calculate local average publication year for each point
220
+ local_years = np.array([
221
+ np.mean(records_df['publication_year'].iloc[idx])
222
+ for idx in indices
223
+ ])
224
+ norm = mcolors.Normalize(vmin=local_years.min(), vmax=local_years.max())
225
+ records_df['color'] = [mcolors.to_hex(cmap(norm(year))) for year in local_years]
226
+
227
+
228
+
229
+ stacked_df = pd.concat([basedata_df, records_df], axis=0, ignore_index=True)
230
+ stacked_df = stacked_df.fillna("Unlabelled")
231
+ stacked_df['parsed_field'] = [get_field(row) for ix, row in stacked_df.iterrows()]
232
+ extra_data = pd.DataFrame(stacked_df['doi'])
233
+ print(f"Visualization data prepared in {time.time() - viz_prep_start:.2f} seconds")
234
+
235
+ # Create and save plot
236
+ plot_start = time.time()
237
+ progress(0.7, desc="Creating plot...")
238
+
239
+
240
+ plot = datamapplot.create_interactive_plot(
241
+ stacked_df[['x','y']].values,
242
+ np.array(stacked_df['cluster_2_labels']),
243
+ np.array(['Unlabelled' if pd.isna(x) else x for x in stacked_df['parsed_field']]),
244
+
245
+ hover_text=[str(row['title']) for ix, row in stacked_df.iterrows()],
246
+ marker_color_array=stacked_df['color'],
247
+ use_medoids=True,
248
+ width=1000,
249
+ height=1000,
250
+ point_radius_min_pixels=1,
251
+ text_outline_width=5,
252
+ point_hover_color='#5e2784',
253
+ point_radius_max_pixels=7,
254
+ color_label_text=False,
255
+ font_family="Roboto Condensed",
256
+ font_weight=700,
257
+ tooltip_font_weight=600,
258
+ tooltip_font_family="Roboto Condensed",
259
+ extra_point_data=extra_data,
260
+ on_click="window.open(`{doi}`)",
261
+ custom_css=DATAMAP_CUSTOM_CSS,
262
+ initial_zoom_fraction=.8,
263
+ enable_search=False
264
+ )
265
+
266
+ # Save plot
267
+ html_file_name = f"{filename}.html"
268
+ html_file_path = static_dir / html_file_name
269
+ plot.save(html_file_path)
270
+ print(f"Plot created and saved in {time.time() - plot_start:.2f} seconds")
271
+
272
+
273
+
274
+ # Save additional files if requested
275
+ csv_file_path = static_dir / f"{filename}.csv"
276
+ png_file_path = static_dir / f"{filename}.png"
277
+
278
+ if download_csv_checkbox:
279
+ # Export relevant columns
280
+ export_df = records_df[['title', 'abstract', 'doi', 'publication_year', 'x', 'y']]
281
+ export_df.to_csv(csv_file_path, index=False)
282
+
283
+ if download_png_checkbox:
284
+ png_start_time = time.time()
285
+ print("Starting PNG generation...")
286
+
287
+ # Sample and prepare data
288
+ sample_prep_start = time.time()
289
+ sample_to_plot = basedata_df#.sample(20000)
290
+ labels1 = np.array(sample_to_plot['cluster_2_labels'])
291
+ labels2 = np.array(['Unlabelled' if pd.isna(x) else x for x in sample_to_plot['parsed_field']])
292
+
293
+ ratio = 0.6
294
+ mask = np.random.random(size=len(labels1)) < ratio
295
+ combined_labels = np.where(mask, labels1, labels2)
296
+
297
+ # Get the 30 most common labels
298
+ unique_labels, counts = np.unique(combined_labels, return_counts=True)
299
+ top_30_labels = set(unique_labels[np.argsort(counts)[-50:]])
300
+
301
+ # Replace less common labels with 'Unlabelled'
302
+ combined_labels = np.array(['Unlabelled' if label not in top_30_labels else label for label in combined_labels])
303
+
304
+ colors_base = ['#536878' for _ in range(len(labels1))]
305
+ print(f"Sample preparation completed in {time.time() - sample_prep_start:.2f} seconds")
306
+
307
+ # Create main plot
308
+ print(sample_to_plot[['x','y']].values)
309
+ print(combined_labels)
310
+
311
+ main_plot_start = time.time()
312
+ fig, ax = datamapplot.create_plot(
313
+ sample_to_plot[['x','y']].values,
314
+ combined_labels,
315
+ label_wrap_width=12,
316
+ label_over_points=True,
317
+ dynamic_label_size=True,
318
+ use_medoids=True,
319
+ point_size=2,
320
+ marker_color_array=colors_base,
321
+ force_matplotlib=True,
322
+ max_font_size=12,
323
+ min_font_size=4,
324
+ min_font_weight=100,
325
+ max_font_weight=300,
326
+ font_family="Roboto Condensed",
327
+ color_label_text=False, add_glow=False,
328
+ highlight_labels=list(np.unique(labels1)),
329
+ label_font_size=8,
330
+ highlight_label_keywords={"fontsize": 12, "fontweight": "bold", "bbox":{"boxstyle":"circle", "pad":0.75,'alpha':0.}},
331
+ )
332
+ print(f"Main plot creation completed in {time.time() - main_plot_start:.2f} seconds")
333
+
334
+ # Time-based visualization
335
+ scatter_start = time.time()
336
+ if plot_time_checkbox:
337
+ if locally_approximate_publication_date_checkbox:
338
+ scatter = plt.scatter(
339
+ umap_embeddings[:,0],
340
+ umap_embeddings[:,1],
341
+ c=local_years,
342
+ cmap=colormaps.haline,
343
+ alpha=0.8,
344
+ s=5
345
+ )
346
+ else:
347
+ years = pd.to_numeric(records_df['publication_year'])
348
+ scatter = plt.scatter(
349
+ umap_embeddings[:,0],
350
+ umap_embeddings[:,1],
351
+ c=years,
352
+ cmap=colormaps.haline,
353
+ alpha=0.8,
354
+ s=5
355
+ )
356
+ plt.colorbar(scatter, shrink=0.5, format='%d')
357
+ else:
358
+ scatter = plt.scatter(
359
+ umap_embeddings[:,0],
360
+ umap_embeddings[:,1],
361
+ c=records_df['color'],
362
+ alpha=0.8,
363
+ s=5
364
+ )
365
+ print(f"Scatter plot creation completed in {time.time() - scatter_start:.2f} seconds")
366
+
367
+ # Save plot
368
+ save_start = time.time()
369
+ plt.axis('off')
370
+ png_file_path = static_dir / f"{filename}.png"
371
+ plt.savefig(png_file_path, dpi=300, bbox_inches='tight')
372
+ plt.close()
373
+ print(f"Plot saving completed in {time.time() - save_start:.2f} seconds")
374
+
375
+ print(f"Total PNG generation completed in {time.time() - png_start_time:.2f} seconds")
376
+
377
+
378
+
379
+
380
+
381
+
382
+
383
+ progress(1.0, desc="Done!")
384
+ print(f"Total pipeline completed in {time.time() - start_time:.2f} seconds")
385
+
386
+ iframe = f"""<iframe src="/static/{html_file_name}" width="100%" height="1000px"></iframe>"""
387
+
388
+ # Return iframe and download buttons with appropriate visibility
389
+ return [
390
+ iframe,
391
+ gr.DownloadButton(label="Download Interactive Visualization", value=html_file_path, visible=True),
392
+ gr.DownloadButton(label="Download CSV Data", value=csv_file_path, visible=download_csv_checkbox),
393
+ gr.DownloadButton(label="Download Static Plot", value=png_file_path, visible=download_png_checkbox),
394
+ gr.Button(visible=False) # Return hidden state for cancel button
395
+ ]
396
+
397
+
398
+ theme = gr.themes.Monochrome(
399
+ font=[gr.themes.GoogleFont("Roboto Condensed"), "ui-sans-serif", "system-ui", "sans-serif"],
400
+
401
+ text_size="lg",
402
+
403
+ )
404
+
405
+
406
+ # Gradio interface setup
407
+ with gr.Blocks(theme=theme) as demo:
408
+ gr.Markdown("""
409
+ <div style="max-width: 100%; margin: 0 auto;">
410
+ <br>
411
+
412
+ # OpenAlex Mapper
413
+
414
+ OpenAlex Mapper is a way of projecting search queries from the amazing OpenAlex database on a background map of randomly sampled papers from OpenAlex, which allows you to easily investigate interdisciplinary connections. OpenAlex Mapper was developed by Maximilian Noichl and Andrea Loettgers at the Possible Life project.
415
+
416
+ To use OpenAlex Mapper, first head over to [OpenAlex](https://openalex.org/) and search for something that interests you. For example, you could search for all the papers that make use of the [Kuramoto model](https://openalex.org/works?page=1&filter=default.search%3A%22Kuramoto%20Model%22), for all the papers that were published by researchers at [Utrecht University in 2019](https://openalex.org/works?page=1&filter=authorships.institutions.lineage%3Ai193662353,publication_year%3A2019), or for all the papers that cite Wittgenstein's [Philosophical Investigations](https://openalex.org/works?page=1&filter=cites%3Aw4251395411). Then you copy the URL to that search query into the OpenAlex search URL box below and click "Run Query." It will take a moment to download all of these records from OpenAlex and embed them on our interactive map. After a little time, that map will appear and be available for you to interact with and download. You can find more explanations in the FAQs below.
417
+ </div>
418
+ """)
419
+
420
+ with gr.Row():
421
+ with gr.Column(scale=1):
422
+ with gr.Row():
423
+ run_btn = gr.Button("Run Query", variant='primary')
424
+ cancel_btn = gr.Button("Cancel", visible=False, variant='secondary')
425
+
426
+ # Create separate download buttons
427
+ html_download = gr.DownloadButton("Download Interactive Visualization", visible=False)
428
+ csv_download = gr.DownloadButton("Download CSV Data", visible=False)
429
+ png_download = gr.DownloadButton("Download Static Plot", visible=False)
430
+
431
+ text_input = gr.Textbox(label="OpenAlex-search URL",
432
+ info="Enter the URL to an OpenAlex-search.")
433
+
434
+ gr.Markdown("### Sample Settings")
435
+ reduce_sample_checkbox = gr.Checkbox(
436
+ label="Reduce Sample Size",
437
+ value=True,
438
+ info="Reduce sample size."
439
+ )
440
+ sample_reduction_method = gr.Dropdown(
441
+ ["All", "First n samples", "n random samples"],
442
+ label="Sample Selection Method",
443
+ value="First n samples",
444
+ info="How to choose the samples to keep."
445
+ )
446
+ sample_size_slider = gr.Slider(
447
+ label="Sample Size",
448
+ minimum=500,
449
+ maximum=20000,
450
+ step=10,
451
+ value=1000,
452
+ info="How many samples to keep.",
453
+ visible=True
454
+ )
455
+
456
+ gr.Markdown("### Plot Settings")
457
+ plot_time_checkbox = gr.Checkbox(
458
+ label="Plot Time",
459
+ value=True,
460
+ info="Colour points by their publication date."
461
+ )
462
+ locally_approximate_publication_date_checkbox = gr.Checkbox(
463
+ label="Locally Approximate Publication Date",
464
+ value=True,
465
+ info="Colour points by the average publicaion date in their area."
466
+ )
467
+
468
+ gr.Markdown("### Download Options")
469
+ download_csv_checkbox = gr.Checkbox(
470
+ label="Generate CSV Export",
471
+ value=False,
472
+ info="Export the data as CSV file"
473
+ )
474
+ download_png_checkbox = gr.Checkbox(
475
+ label="Generate Static PNG Plot",
476
+ value=False,
477
+ info="Export a static PNG visualization. This will make things slower!"
478
+ )
479
+
480
+
481
+
482
+
483
+ with gr.Column(scale=2):
484
+ html = gr.HTML(
485
+ value='<div style="width: 100%; height: 1000px; display: flex; justify-content: center; align-items: center; border: 1px solid #ccc; background-color: #f8f9fa;"><p style="font-size: 1.2em; color: #666;">The visualization map will appear here after running a query</p></div>',
486
+ label="HTML preview",
487
+ show_label=True
488
+ )
489
+ gr.Markdown("""
490
+ <div style="max-width: 100%; margin: 0 auto;">
491
+
492
+ # FAQs
493
+
494
+ ## Who made this?
495
+
496
+ This project was developed by [Maximilian Noichl](https://maxnoichl.eu) (Utrecht University), in cooperation with Andrea Loettger and Tarja Knuuttila at the [Possible Life project](http://www.possiblelife.eu/), at the University of Vienna. If this project is useful in any way for your research, we would appreciate citation of **...**
497
+
498
+ This project received funding from the European Research Council under the European Union's Horizon 2020 research and innovation programme (LIFEMODE project, grant agreement No. 818772).
499
+
500
+ ## How does it work?
501
+
502
+ The base map for this project is developed by randomly downloading 250,000 articles from OpenAlex, then embedding their abstracts using our [fine-tuned](https://huggingface.co/m7n/discipline-tuned_specter_2_024) version of the [specter-2](https://huggingface.co/allenai/specter2_aug2023refresh_base) language model, running these embeddings through [UMAP](https://umap-learn.readthedocs.io/en/latest/) to give us a two-dimensional representation, and displaying that in an interactive window using [datamapplot](https://datamapplot.readthedocs.io/en/latest/index.html). After the data for your query is downloaded from OpenAlex, it then undergoes the exact same process, but the pre-trained UMAP model from earlier is used to project your new data points onto this original map, showing where they would show up if they were included in the original sample. For more details, you can take a look at the method section of this paper: **...**
503
+
504
+ ## I think I found a mistake in the map.
505
+
506
+ There are various considerations to take into account when working with this map:
507
+
508
+ 1. The language model we use is fine-tuned to separate disciplines from each other, but of course, disciplines are weird, partially subjective social categories, so what the model has learned might not always correspond perfectly to what you would expect to see.
509
+
510
+ 2. When pressing down a really high-dimensional space into a low-dimensional one, there will be trade-offs. For example, we see this big ring structure of the sciences on the map, but in the middle of the map there is a overly stretchedstring of bioinformaticsthat stretches from computer science at the bottom up to the life sciences clusters at the top. This is one of the areas where the UMAP algorithm had trouble pressing our high-dimensional dataset into a low-dimensional space. For more information on how to read a UMAP plot, I recommend looking into ["Understanding UMAP"](https://pair-code.github.io/understanding-umap/) by Andy Coenen & Adam Pearce.
511
+
512
+ 3. Finally, the labels we're using for the regions of this plot are created from OpenAlex's own labels of sub-disciplines. They give a rough indication of the papers that could be expected in this broad area of the map, but they are not necessarily the perfect label for the articles that are precisely below them. They are just located at the median point of a usually much larger, much broader, and fuzzier category, so they should always be taken with quite a big grain of salt.
513
+ </div>
514
+ """)
515
+
516
+ def update_slider_visibility(method):
517
+ return gr.Slider(visible=(method != "All"))
518
+
519
+ sample_reduction_method.change(
520
+ fn=update_slider_visibility,
521
+ inputs=[sample_reduction_method],
522
+ outputs=[sample_size_slider]
523
+ )
524
+
525
+ def show_cancel_button():
526
+ return gr.Button(visible=True)
527
+
528
+ def hide_cancel_button():
529
+ return gr.Button(visible=False)
530
+
531
+ # Update the run button click event
532
+ run_event = run_btn.click(
533
+ fn=show_cancel_button,
534
+ outputs=cancel_btn,
535
+ queue=False
536
+ ).then(
537
+ fn=predict,
538
+ inputs=[text_input, sample_size_slider, reduce_sample_checkbox,
539
+ sample_reduction_method, plot_time_checkbox,
540
+ locally_approximate_publication_date_checkbox,
541
+ download_csv_checkbox, download_png_checkbox],
542
+ outputs=[html, html_download, csv_download, png_download, cancel_btn]
543
+ )
544
+
545
+ # Add cancel button click event
546
+ cancel_btn.click(
547
+ fn=hide_cancel_button,
548
+ outputs=cancel_btn,
549
+ cancels=[run_event],
550
+ queue=False # Important to make the button hide immediately
551
+ )
552
+
553
+ # Mount and run app
554
+ app = gr.mount_gradio_app(app, demo, path="/")
555
+
556
+ if __name__ == "__main__":
557
+ uvicorn.run(app, host="0.0.0.0", port=7860)
data_setup.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pickle
2
+ import requests
3
+ import umap
4
+ from numba.typed import List
5
+ import torch
6
+ from sentence_transformers import SentenceTransformer
7
+ import time
8
+ from pathlib import Path
9
+
10
+ def check_resources(files_dict, basemap_path, mapper_params_path):
11
+ """
12
+ Check if all required resources are present.
13
+
14
+ Args:
15
+ files_dict (dict): Dictionary mapping filenames to their download URLs
16
+ basemap_path (str): Path to the basemap pickle file
17
+ mapper_params_path (str): Path to the UMAP mapper parameters pickle file
18
+
19
+ Returns:
20
+ bool: True if all resources are present, False otherwise
21
+ """
22
+ all_files_present = True
23
+
24
+ # Check downloaded files
25
+ for filename in files_dict.keys():
26
+ if not Path(filename).exists():
27
+ print(f"Missing file: {filename}")
28
+ all_files_present = False
29
+
30
+ # Check basemap
31
+ if not Path(basemap_path).exists():
32
+ print(f"Missing basemap file: {basemap_path}")
33
+ all_files_present = False
34
+
35
+ # Check mapper params
36
+ if not Path(mapper_params_path).exists():
37
+ print(f"Missing mapper params file: {mapper_params_path}")
38
+ all_files_present = False
39
+
40
+ return all_files_present
41
+
42
+ def download_required_files(files_dict):
43
+ """
44
+ Download required files from URLs only if they don't exist.
45
+
46
+ Args:
47
+ files_dict (dict): Dictionary mapping filenames to their download URLs
48
+ """
49
+ print(f"Checking required files: {time.strftime('%Y-%m-%d %H:%M:%S')}")
50
+
51
+ files_to_download = {
52
+ filename: url
53
+ for filename, url in files_dict.items()
54
+ if not Path(filename).exists()
55
+ }
56
+
57
+ if not files_to_download:
58
+ print("All files already present, skipping downloads")
59
+ return
60
+
61
+ print(f"Downloading missing files: {list(files_to_download.keys())}")
62
+ for filename, url in files_to_download.items():
63
+ print(f"Downloading {filename}...")
64
+ response = requests.get(url)
65
+ with open(filename, "wb") as f:
66
+ f.write(response.content)
67
+
68
+ def setup_basemap_data(basemap_path):
69
+ """
70
+ Load and setup the base map data.
71
+
72
+ Args:
73
+ basemap_path (str): Path to the basemap pickle file
74
+ """
75
+ print(f"Getting basemap data: {time.strftime('%Y-%m-%d %H:%M:%S')}")
76
+ basedata_df = pickle.load(open(basemap_path, 'rb'))
77
+ return basedata_df
78
+
79
+ def setup_mapper(mapper_params_path):
80
+ """
81
+ Setup and configure the UMAP mapper.
82
+
83
+ Args:
84
+ mapper_params_path (str): Path to the UMAP mapper parameters pickle file
85
+ """
86
+ print(f"Getting Mapper: {time.strftime('%Y-%m-%d %H:%M:%S')}")
87
+
88
+ params_new = pickle.load(open(mapper_params_path, 'rb'))
89
+ print("setting up mapper...")
90
+ mapper = umap.UMAP()
91
+
92
+ umap_params = {k: v for k, v in params_new.get('umap_params', {}).items()
93
+ if k != 'target_backend'}
94
+ mapper.set_params(**umap_params)
95
+
96
+ for attr, value in params_new.get('umap_attributes', {}).items():
97
+ if attr != 'embedding_':
98
+ setattr(mapper, attr, value)
99
+
100
+ if 'embedding_' in params_new.get('umap_attributes', {}):
101
+ mapper.embedding_ = List(params_new['umap_attributes']['embedding_'])
102
+
103
+ return mapper
104
+
105
+ def setup_embedding_model(model_name):
106
+ """
107
+ Setup the SentenceTransformer model.
108
+
109
+ Args:
110
+ model_name (str): Name or path of the SentenceTransformer model
111
+ """
112
+ print(f"Setting up language model: {time.strftime('%Y-%m-%d %H:%M:%S')}")
113
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
114
+ print(f"Using device: {device}")
115
+
116
+ model = SentenceTransformer(model_name)
117
+ return model
openalex_env_map/lib/python3.10/site-packages/IPython/__init__.py ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PYTHON_ARGCOMPLETE_OK
2
+ """
3
+ IPython: tools for interactive and parallel computing in Python.
4
+
5
+ https://ipython.org
6
+ """
7
+ #-----------------------------------------------------------------------------
8
+ # Copyright (c) 2008-2011, IPython Development Team.
9
+ # Copyright (c) 2001-2007, Fernando Perez <[email protected]>
10
+ # Copyright (c) 2001, Janko Hauser <[email protected]>
11
+ # Copyright (c) 2001, Nathaniel Gray <[email protected]>
12
+ #
13
+ # Distributed under the terms of the Modified BSD License.
14
+ #
15
+ # The full license is in the file COPYING.txt, distributed with this software.
16
+ #-----------------------------------------------------------------------------
17
+
18
+ #-----------------------------------------------------------------------------
19
+ # Imports
20
+ #-----------------------------------------------------------------------------
21
+
22
+ import sys
23
+
24
+ #-----------------------------------------------------------------------------
25
+ # Setup everything
26
+ #-----------------------------------------------------------------------------
27
+
28
+ # Don't forget to also update setup.py when this changes!
29
+ if sys.version_info < (3, 10):
30
+ raise ImportError(
31
+ """
32
+ IPython 8.19+ supports Python 3.10 and above, following SPEC0.
33
+ IPython 8.13+ supports Python 3.9 and above, following NEP 29.
34
+ IPython 8.0-8.12 supports Python 3.8 and above, following NEP 29.
35
+ When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
36
+ Python 3.3 and 3.4 were supported up to IPython 6.x.
37
+ Python 3.5 was supported with IPython 7.0 to 7.9.
38
+ Python 3.6 was supported with IPython up to 7.16.
39
+ Python 3.7 was still supported with the 7.x branch.
40
+
41
+ See IPython `README.rst` file for more information:
42
+
43
+ https://github.com/ipython/ipython/blob/main/README.rst
44
+
45
+ """
46
+ )
47
+
48
+ #-----------------------------------------------------------------------------
49
+ # Setup the top level names
50
+ #-----------------------------------------------------------------------------
51
+
52
+ from .core.getipython import get_ipython
53
+ from .core import release
54
+ from .core.application import Application
55
+ from .terminal.embed import embed
56
+
57
+ from .core.interactiveshell import InteractiveShell
58
+ from .utils.sysinfo import sys_info
59
+ from .utils.frame import extract_module_locals
60
+
61
+ __all__ = ["start_ipython", "embed", "start_kernel", "embed_kernel"]
62
+
63
+ # Release data
64
+ __author__ = '%s <%s>' % (release.author, release.author_email)
65
+ __license__ = release.license
66
+ __version__ = release.version
67
+ version_info = release.version_info
68
+ # list of CVEs that should have been patched in this release.
69
+ # this is informational and should not be relied upon.
70
+ __patched_cves__ = {"CVE-2022-21699", "CVE-2023-24816"}
71
+
72
+
73
+ def embed_kernel(module=None, local_ns=None, **kwargs):
74
+ """Embed and start an IPython kernel in a given scope.
75
+
76
+ If you don't want the kernel to initialize the namespace
77
+ from the scope of the surrounding function,
78
+ and/or you want to load full IPython configuration,
79
+ you probably want `IPython.start_kernel()` instead.
80
+
81
+ Parameters
82
+ ----------
83
+ module : types.ModuleType, optional
84
+ The module to load into IPython globals (default: caller)
85
+ local_ns : dict, optional
86
+ The namespace to load into IPython user namespace (default: caller)
87
+ **kwargs : various, optional
88
+ Further keyword args are relayed to the IPKernelApp constructor,
89
+ such as `config`, a traitlets :class:`Config` object (see :ref:`configure_start_ipython`),
90
+ allowing configuration of the kernel (see :ref:`kernel_options`). Will only have an effect
91
+ on the first embed_kernel call for a given process.
92
+ """
93
+
94
+ (caller_module, caller_locals) = extract_module_locals(1)
95
+ if module is None:
96
+ module = caller_module
97
+ if local_ns is None:
98
+ local_ns = caller_locals
99
+
100
+ # Only import .zmq when we really need it
101
+ from ipykernel.embed import embed_kernel as real_embed_kernel
102
+ real_embed_kernel(module=module, local_ns=local_ns, **kwargs)
103
+
104
+ def start_ipython(argv=None, **kwargs):
105
+ """Launch a normal IPython instance (as opposed to embedded)
106
+
107
+ `IPython.embed()` puts a shell in a particular calling scope,
108
+ such as a function or method for debugging purposes,
109
+ which is often not desirable.
110
+
111
+ `start_ipython()` does full, regular IPython initialization,
112
+ including loading startup files, configuration, etc.
113
+ much of which is skipped by `embed()`.
114
+
115
+ This is a public API method, and will survive implementation changes.
116
+
117
+ Parameters
118
+ ----------
119
+ argv : list or None, optional
120
+ If unspecified or None, IPython will parse command-line options from sys.argv.
121
+ To prevent any command-line parsing, pass an empty list: `argv=[]`.
122
+ user_ns : dict, optional
123
+ specify this dictionary to initialize the IPython user namespace with particular values.
124
+ **kwargs : various, optional
125
+ Any other kwargs will be passed to the Application constructor,
126
+ such as `config`, a traitlets :class:`Config` object (see :ref:`configure_start_ipython`),
127
+ allowing configuration of the instance (see :ref:`terminal_options`).
128
+ """
129
+ from IPython.terminal.ipapp import launch_new_instance
130
+ return launch_new_instance(argv=argv, **kwargs)
131
+
132
+ def start_kernel(argv=None, **kwargs):
133
+ """Launch a normal IPython kernel instance (as opposed to embedded)
134
+
135
+ `IPython.embed_kernel()` puts a shell in a particular calling scope,
136
+ such as a function or method for debugging purposes,
137
+ which is often not desirable.
138
+
139
+ `start_kernel()` does full, regular IPython initialization,
140
+ including loading startup files, configuration, etc.
141
+ much of which is skipped by `embed_kernel()`.
142
+
143
+ Parameters
144
+ ----------
145
+ argv : list or None, optional
146
+ If unspecified or None, IPython will parse command-line options from sys.argv.
147
+ To prevent any command-line parsing, pass an empty list: `argv=[]`.
148
+ user_ns : dict, optional
149
+ specify this dictionary to initialize the IPython user namespace with particular values.
150
+ **kwargs : various, optional
151
+ Any other kwargs will be passed to the Application constructor,
152
+ such as `config`, a traitlets :class:`Config` object (see :ref:`configure_start_ipython`),
153
+ allowing configuration of the kernel (see :ref:`kernel_options`).
154
+ """
155
+ import warnings
156
+
157
+ warnings.warn(
158
+ "start_kernel is deprecated since IPython 8.0, use from `ipykernel.kernelapp.launch_new_instance`",
159
+ DeprecationWarning,
160
+ stacklevel=2,
161
+ )
162
+ from ipykernel.kernelapp import launch_new_instance
163
+ return launch_new_instance(argv=argv, **kwargs)
openalex_env_map/lib/python3.10/site-packages/IPython/__main__.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PYTHON_ARGCOMPLETE_OK
2
+ # encoding: utf-8
3
+ """Terminal-based IPython entry point.
4
+ """
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright (c) 2012, IPython Development Team.
7
+ #
8
+ # Distributed under the terms of the Modified BSD License.
9
+ #
10
+ # The full license is in the file COPYING.txt, distributed with this software.
11
+ # -----------------------------------------------------------------------------
12
+
13
+ from IPython import start_ipython
14
+
15
+ start_ipython()
openalex_env_map/lib/python3.10/site-packages/IPython/conftest.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import builtins
2
+ import inspect
3
+ import os
4
+ import pathlib
5
+ import shutil
6
+ import sys
7
+ import types
8
+
9
+ import pytest
10
+
11
+ # Must register before it gets imported
12
+ pytest.register_assert_rewrite("IPython.testing.tools")
13
+
14
+ from .testing import tools
15
+
16
+
17
+ def pytest_collection_modifyitems(items):
18
+ """This function is automatically run by pytest passing all collected test
19
+ functions.
20
+
21
+ We use it to add asyncio marker to all async tests and assert we don't use
22
+ test functions that are async generators which wouldn't make sense.
23
+ """
24
+ for item in items:
25
+ if inspect.iscoroutinefunction(item.obj):
26
+ item.add_marker("asyncio")
27
+ assert not inspect.isasyncgenfunction(item.obj)
28
+
29
+
30
+ def get_ipython():
31
+ from .terminal.interactiveshell import TerminalInteractiveShell
32
+ if TerminalInteractiveShell._instance:
33
+ return TerminalInteractiveShell.instance()
34
+
35
+ config = tools.default_config()
36
+ config.TerminalInteractiveShell.simple_prompt = True
37
+
38
+ # Create and initialize our test-friendly IPython instance.
39
+ shell = TerminalInteractiveShell.instance(config=config)
40
+ return shell
41
+
42
+
43
+ @pytest.fixture(scope='session', autouse=True)
44
+ def work_path():
45
+ path = pathlib.Path("./tmp-ipython-pytest-profiledir")
46
+ os.environ["IPYTHONDIR"] = str(path.absolute())
47
+ if path.exists():
48
+ raise ValueError('IPython dir temporary path already exists ! Did previous test run exit successfully ?')
49
+ path.mkdir()
50
+ yield
51
+ shutil.rmtree(str(path.resolve()))
52
+
53
+
54
+ def nopage(strng, start=0, screen_lines=0, pager_cmd=None):
55
+ if isinstance(strng, dict):
56
+ strng = strng.get("text/plain", "")
57
+ print(strng)
58
+
59
+
60
+ def xsys(self, cmd):
61
+ """Replace the default system call with a capturing one for doctest.
62
+ """
63
+ # We use getoutput, but we need to strip it because pexpect captures
64
+ # the trailing newline differently from commands.getoutput
65
+ print(self.getoutput(cmd, split=False, depth=1).rstrip(), end="", file=sys.stdout)
66
+ sys.stdout.flush()
67
+
68
+
69
+ # for things to work correctly we would need this as a session fixture;
70
+ # unfortunately this will fail on some test that get executed as _collection_
71
+ # time (before the fixture run), in particular parametrized test that contain
72
+ # yields. so for now execute at import time.
73
+ #@pytest.fixture(autouse=True, scope='session')
74
+ def inject():
75
+
76
+ builtins.get_ipython = get_ipython
77
+ builtins._ip = get_ipython()
78
+ builtins.ip = get_ipython()
79
+ builtins.ip.system = types.MethodType(xsys, ip)
80
+ builtins.ip.builtin_trap.activate()
81
+ from .core import page
82
+
83
+ page.pager_page = nopage
84
+ # yield
85
+
86
+
87
+ inject()
openalex_env_map/lib/python3.10/site-packages/IPython/consoleapp.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Shim to maintain backwards compatibility with old IPython.consoleapp imports.
3
+ """
4
+ # Copyright (c) IPython Development Team.
5
+ # Distributed under the terms of the Modified BSD License.
6
+
7
+ from warnings import warn
8
+
9
+ warn("The `IPython.consoleapp` package has been deprecated since IPython 4.0."
10
+ "You should import from jupyter_client.consoleapp instead.", stacklevel=2)
11
+
12
+ from jupyter_client.consoleapp import *
openalex_env_map/lib/python3.10/site-packages/IPython/core/__init__.py ADDED
File without changes
openalex_env_map/lib/python3.10/site-packages/IPython/core/alias.py ADDED
@@ -0,0 +1,267 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """
3
+ System command aliases.
4
+
5
+ Authors:
6
+
7
+ * Fernando Perez
8
+ * Brian Granger
9
+ """
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Copyright (C) 2008-2011 The IPython Development Team
13
+ #
14
+ # Distributed under the terms of the BSD License.
15
+ #
16
+ # The full license is in the file COPYING.txt, distributed with this software.
17
+ #-----------------------------------------------------------------------------
18
+
19
+ #-----------------------------------------------------------------------------
20
+ # Imports
21
+ #-----------------------------------------------------------------------------
22
+
23
+ import os
24
+ import re
25
+ import sys
26
+
27
+ from traitlets.config.configurable import Configurable
28
+ from .error import UsageError
29
+
30
+ from traitlets import List, Instance
31
+ from logging import error
32
+
33
+ import typing as t
34
+
35
+
36
+ #-----------------------------------------------------------------------------
37
+ # Utilities
38
+ #-----------------------------------------------------------------------------
39
+
40
+ # This is used as the pattern for calls to split_user_input.
41
+ shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
42
+
43
+ def default_aliases() -> t.List[t.Tuple[str, str]]:
44
+ """Return list of shell aliases to auto-define.
45
+ """
46
+ # Note: the aliases defined here should be safe to use on a kernel
47
+ # regardless of what frontend it is attached to. Frontends that use a
48
+ # kernel in-process can define additional aliases that will only work in
49
+ # their case. For example, things like 'less' or 'clear' that manipulate
50
+ # the terminal should NOT be declared here, as they will only work if the
51
+ # kernel is running inside a true terminal, and not over the network.
52
+
53
+ if os.name == 'posix':
54
+ default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
55
+ ('mv', 'mv'), ('rm', 'rm'), ('cp', 'cp'),
56
+ ('cat', 'cat'),
57
+ ]
58
+ # Useful set of ls aliases. The GNU and BSD options are a little
59
+ # different, so we make aliases that provide as similar as possible
60
+ # behavior in ipython, by passing the right flags for each platform
61
+ if sys.platform.startswith('linux'):
62
+ ls_aliases = [('ls', 'ls -F --color'),
63
+ # long ls
64
+ ('ll', 'ls -F -o --color'),
65
+ # ls normal files only
66
+ ('lf', 'ls -F -o --color %l | grep ^-'),
67
+ # ls symbolic links
68
+ ('lk', 'ls -F -o --color %l | grep ^l'),
69
+ # directories or links to directories,
70
+ ('ldir', 'ls -F -o --color %l | grep /$'),
71
+ # things which are executable
72
+ ('lx', 'ls -F -o --color %l | grep ^-..x'),
73
+ ]
74
+ elif sys.platform.startswith('openbsd') or sys.platform.startswith('netbsd'):
75
+ # OpenBSD, NetBSD. The ls implementation on these platforms do not support
76
+ # the -G switch and lack the ability to use colorized output.
77
+ ls_aliases = [('ls', 'ls -F'),
78
+ # long ls
79
+ ('ll', 'ls -F -l'),
80
+ # ls normal files only
81
+ ('lf', 'ls -F -l %l | grep ^-'),
82
+ # ls symbolic links
83
+ ('lk', 'ls -F -l %l | grep ^l'),
84
+ # directories or links to directories,
85
+ ('ldir', 'ls -F -l %l | grep /$'),
86
+ # things which are executable
87
+ ('lx', 'ls -F -l %l | grep ^-..x'),
88
+ ]
89
+ else:
90
+ # BSD, OSX, etc.
91
+ ls_aliases = [('ls', 'ls -F -G'),
92
+ # long ls
93
+ ('ll', 'ls -F -l -G'),
94
+ # ls normal files only
95
+ ('lf', 'ls -F -l -G %l | grep ^-'),
96
+ # ls symbolic links
97
+ ('lk', 'ls -F -l -G %l | grep ^l'),
98
+ # directories or links to directories,
99
+ ('ldir', 'ls -F -G -l %l | grep /$'),
100
+ # things which are executable
101
+ ('lx', 'ls -F -l -G %l | grep ^-..x'),
102
+ ]
103
+ default_aliases = default_aliases + ls_aliases
104
+ elif os.name in ['nt', 'dos']:
105
+ default_aliases = [('ls', 'dir /on'),
106
+ ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
107
+ ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
108
+ ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
109
+ ]
110
+ else:
111
+ default_aliases = []
112
+
113
+ return default_aliases
114
+
115
+
116
+ class AliasError(Exception):
117
+ pass
118
+
119
+
120
+ class InvalidAliasError(AliasError):
121
+ pass
122
+
123
+ class Alias(object):
124
+ """Callable object storing the details of one alias.
125
+
126
+ Instances are registered as magic functions to allow use of aliases.
127
+ """
128
+
129
+ # Prepare blacklist
130
+ blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
131
+
132
+ def __init__(self, shell, name, cmd):
133
+ self.shell = shell
134
+ self.name = name
135
+ self.cmd = cmd
136
+ self.__doc__ = "Alias for `!{}`".format(cmd)
137
+ self.nargs = self.validate()
138
+
139
+ def validate(self):
140
+ """Validate the alias, and return the number of arguments."""
141
+ if self.name in self.blacklist:
142
+ raise InvalidAliasError("The name %s can't be aliased "
143
+ "because it is a keyword or builtin." % self.name)
144
+ try:
145
+ caller = self.shell.magics_manager.magics['line'][self.name]
146
+ except KeyError:
147
+ pass
148
+ else:
149
+ if not isinstance(caller, Alias):
150
+ raise InvalidAliasError("The name %s can't be aliased "
151
+ "because it is another magic command." % self.name)
152
+
153
+ if not (isinstance(self.cmd, str)):
154
+ raise InvalidAliasError("An alias command must be a string, "
155
+ "got: %r" % self.cmd)
156
+
157
+ nargs = self.cmd.count('%s') - self.cmd.count('%%s')
158
+
159
+ if (nargs > 0) and (self.cmd.find('%l') >= 0):
160
+ raise InvalidAliasError('The %s and %l specifiers are mutually '
161
+ 'exclusive in alias definitions.')
162
+
163
+ return nargs
164
+
165
+ def __repr__(self):
166
+ return "<alias {} for {!r}>".format(self.name, self.cmd)
167
+
168
+ def __call__(self, rest=''):
169
+ cmd = self.cmd
170
+ nargs = self.nargs
171
+ # Expand the %l special to be the user's input line
172
+ if cmd.find('%l') >= 0:
173
+ cmd = cmd.replace('%l', rest)
174
+ rest = ''
175
+
176
+ if nargs==0:
177
+ if cmd.find('%%s') >= 1:
178
+ cmd = cmd.replace('%%s', '%s')
179
+ # Simple, argument-less aliases
180
+ cmd = '%s %s' % (cmd, rest)
181
+ else:
182
+ # Handle aliases with positional arguments
183
+ args = rest.split(None, nargs)
184
+ if len(args) < nargs:
185
+ raise UsageError('Alias <%s> requires %s arguments, %s given.' %
186
+ (self.name, nargs, len(args)))
187
+ cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
188
+
189
+ self.shell.system(cmd)
190
+
191
+ #-----------------------------------------------------------------------------
192
+ # Main AliasManager class
193
+ #-----------------------------------------------------------------------------
194
+
195
+ class AliasManager(Configurable):
196
+ default_aliases: List = List(default_aliases()).tag(config=True)
197
+ user_aliases: List = List(default_value=[]).tag(config=True)
198
+ shell = Instance(
199
+ "IPython.core.interactiveshell.InteractiveShellABC", allow_none=True
200
+ )
201
+
202
+ def __init__(self, shell=None, **kwargs):
203
+ super(AliasManager, self).__init__(shell=shell, **kwargs)
204
+ # For convenient access
205
+ if self.shell is not None:
206
+ self.linemagics = self.shell.magics_manager.magics["line"]
207
+ self.init_aliases()
208
+
209
+ def init_aliases(self):
210
+ # Load default & user aliases
211
+ for name, cmd in self.default_aliases + self.user_aliases:
212
+ if (
213
+ cmd.startswith("ls ")
214
+ and self.shell is not None
215
+ and self.shell.colors == "NoColor"
216
+ ):
217
+ cmd = cmd.replace(" --color", "")
218
+ self.soft_define_alias(name, cmd)
219
+
220
+ @property
221
+ def aliases(self):
222
+ return [(n, func.cmd) for (n, func) in self.linemagics.items()
223
+ if isinstance(func, Alias)]
224
+
225
+ def soft_define_alias(self, name, cmd):
226
+ """Define an alias, but don't raise on an AliasError."""
227
+ try:
228
+ self.define_alias(name, cmd)
229
+ except AliasError as e:
230
+ error("Invalid alias: %s" % e)
231
+
232
+ def define_alias(self, name, cmd):
233
+ """Define a new alias after validating it.
234
+
235
+ This will raise an :exc:`AliasError` if there are validation
236
+ problems.
237
+ """
238
+ caller = Alias(shell=self.shell, name=name, cmd=cmd)
239
+ self.shell.magics_manager.register_function(caller, magic_kind='line',
240
+ magic_name=name)
241
+
242
+ def get_alias(self, name):
243
+ """Return an alias, or None if no alias by that name exists."""
244
+ aname = self.linemagics.get(name, None)
245
+ return aname if isinstance(aname, Alias) else None
246
+
247
+ def is_alias(self, name):
248
+ """Return whether or not a given name has been defined as an alias"""
249
+ return self.get_alias(name) is not None
250
+
251
+ def undefine_alias(self, name):
252
+ if self.is_alias(name):
253
+ del self.linemagics[name]
254
+ else:
255
+ raise ValueError('%s is not an alias' % name)
256
+
257
+ def clear_aliases(self):
258
+ for name, _ in self.aliases:
259
+ self.undefine_alias(name)
260
+
261
+ def retrieve_alias(self, name):
262
+ """Retrieve the command to which an alias expands."""
263
+ caller = self.get_alias(name)
264
+ if caller:
265
+ return caller.cmd
266
+ else:
267
+ raise ValueError('%s is not an alias' % name)
openalex_env_map/lib/python3.10/site-packages/IPython/core/application.py ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """
3
+ An application for IPython.
4
+
5
+ All top-level applications should use the classes in this module for
6
+ handling configuration and creating configurables.
7
+
8
+ The job of an :class:`Application` is to create the master configuration
9
+ object and then create the configurable objects, passing the config to them.
10
+ """
11
+
12
+ # Copyright (c) IPython Development Team.
13
+ # Distributed under the terms of the Modified BSD License.
14
+
15
+ import atexit
16
+ from copy import deepcopy
17
+ import logging
18
+ import os
19
+ import shutil
20
+ import sys
21
+
22
+ from pathlib import Path
23
+
24
+ from traitlets.config.application import Application, catch_config_error
25
+ from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
26
+ from IPython.core import release, crashhandler
27
+ from IPython.core.profiledir import ProfileDir, ProfileDirError
28
+ from IPython.paths import get_ipython_dir, get_ipython_package_dir
29
+ from IPython.utils.path import ensure_dir_exists
30
+ from traitlets import (
31
+ List, Unicode, Type, Bool, Set, Instance, Undefined,
32
+ default, observe,
33
+ )
34
+
35
+ if os.name == "nt":
36
+ programdata = os.environ.get("PROGRAMDATA", None)
37
+ if programdata is not None:
38
+ SYSTEM_CONFIG_DIRS = [str(Path(programdata) / "ipython")]
39
+ else: # PROGRAMDATA is not defined by default on XP.
40
+ SYSTEM_CONFIG_DIRS = []
41
+ else:
42
+ SYSTEM_CONFIG_DIRS = [
43
+ "/usr/local/etc/ipython",
44
+ "/etc/ipython",
45
+ ]
46
+
47
+
48
+ ENV_CONFIG_DIRS = []
49
+ _env_config_dir = os.path.join(sys.prefix, 'etc', 'ipython')
50
+ if _env_config_dir not in SYSTEM_CONFIG_DIRS:
51
+ # only add ENV_CONFIG if sys.prefix is not already included
52
+ ENV_CONFIG_DIRS.append(_env_config_dir)
53
+
54
+
55
+ _envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
56
+ if _envvar in {None, ''}:
57
+ IPYTHON_SUPPRESS_CONFIG_ERRORS = None
58
+ else:
59
+ if _envvar.lower() in {'1','true'}:
60
+ IPYTHON_SUPPRESS_CONFIG_ERRORS = True
61
+ elif _envvar.lower() in {'0','false'} :
62
+ IPYTHON_SUPPRESS_CONFIG_ERRORS = False
63
+ else:
64
+ sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
65
+
66
+ # aliases and flags
67
+
68
+ base_aliases = {}
69
+ if isinstance(Application.aliases, dict):
70
+ # traitlets 5
71
+ base_aliases.update(Application.aliases)
72
+ base_aliases.update(
73
+ {
74
+ "profile-dir": "ProfileDir.location",
75
+ "profile": "BaseIPythonApplication.profile",
76
+ "ipython-dir": "BaseIPythonApplication.ipython_dir",
77
+ "log-level": "Application.log_level",
78
+ "config": "BaseIPythonApplication.extra_config_file",
79
+ }
80
+ )
81
+
82
+ base_flags = dict()
83
+ if isinstance(Application.flags, dict):
84
+ # traitlets 5
85
+ base_flags.update(Application.flags)
86
+ base_flags.update(
87
+ dict(
88
+ debug=(
89
+ {"Application": {"log_level": logging.DEBUG}},
90
+ "set log level to logging.DEBUG (maximize logging output)",
91
+ ),
92
+ quiet=(
93
+ {"Application": {"log_level": logging.CRITICAL}},
94
+ "set log level to logging.CRITICAL (minimize logging output)",
95
+ ),
96
+ init=(
97
+ {
98
+ "BaseIPythonApplication": {
99
+ "copy_config_files": True,
100
+ "auto_create": True,
101
+ }
102
+ },
103
+ """Initialize profile with default config files. This is equivalent
104
+ to running `ipython profile create <profile>` prior to startup.
105
+ """,
106
+ ),
107
+ )
108
+ )
109
+
110
+
111
+ class ProfileAwareConfigLoader(PyFileConfigLoader):
112
+ """A Python file config loader that is aware of IPython profiles."""
113
+ def load_subconfig(self, fname, path=None, profile=None):
114
+ if profile is not None:
115
+ try:
116
+ profile_dir = ProfileDir.find_profile_dir_by_name(
117
+ get_ipython_dir(),
118
+ profile,
119
+ )
120
+ except ProfileDirError:
121
+ return
122
+ path = profile_dir.location
123
+ return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
124
+
125
+ class BaseIPythonApplication(Application):
126
+ name = "ipython"
127
+ description = "IPython: an enhanced interactive Python shell."
128
+ version = Unicode(release.version)
129
+
130
+ aliases = base_aliases
131
+ flags = base_flags
132
+ classes = List([ProfileDir])
133
+
134
+ # enable `load_subconfig('cfg.py', profile='name')`
135
+ python_config_loader_class = ProfileAwareConfigLoader
136
+
137
+ # Track whether the config_file has changed,
138
+ # because some logic happens only if we aren't using the default.
139
+ config_file_specified = Set()
140
+
141
+ config_file_name = Unicode()
142
+ @default('config_file_name')
143
+ def _config_file_name_default(self):
144
+ return self.name.replace('-','_') + u'_config.py'
145
+ @observe('config_file_name')
146
+ def _config_file_name_changed(self, change):
147
+ if change['new'] != change['old']:
148
+ self.config_file_specified.add(change['new'])
149
+
150
+ # The directory that contains IPython's builtin profiles.
151
+ builtin_profile_dir = Unicode(
152
+ os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
153
+ )
154
+
155
+ config_file_paths = List(Unicode())
156
+ @default('config_file_paths')
157
+ def _config_file_paths_default(self):
158
+ return []
159
+
160
+ extra_config_file = Unicode(
161
+ help="""Path to an extra config file to load.
162
+
163
+ If specified, load this config file in addition to any other IPython config.
164
+ """).tag(config=True)
165
+ @observe('extra_config_file')
166
+ def _extra_config_file_changed(self, change):
167
+ old = change['old']
168
+ new = change['new']
169
+ try:
170
+ self.config_files.remove(old)
171
+ except ValueError:
172
+ pass
173
+ self.config_file_specified.add(new)
174
+ self.config_files.append(new)
175
+
176
+ profile = Unicode(u'default',
177
+ help="""The IPython profile to use."""
178
+ ).tag(config=True)
179
+
180
+ @observe('profile')
181
+ def _profile_changed(self, change):
182
+ self.builtin_profile_dir = os.path.join(
183
+ get_ipython_package_dir(), u'config', u'profile', change['new']
184
+ )
185
+
186
+ add_ipython_dir_to_sys_path = Bool(
187
+ False,
188
+ """Should the IPython profile directory be added to sys path ?
189
+
190
+ This option was non-existing before IPython 8.0, and ipython_dir was added to
191
+ sys path to allow import of extensions present there. This was historical
192
+ baggage from when pip did not exist. This now default to false,
193
+ but can be set to true for legacy reasons.
194
+ """,
195
+ ).tag(config=True)
196
+
197
+ ipython_dir = Unicode(
198
+ help="""
199
+ The name of the IPython directory. This directory is used for logging
200
+ configuration (through profiles), history storage, etc. The default
201
+ is usually $HOME/.ipython. This option can also be specified through
202
+ the environment variable IPYTHONDIR.
203
+ """
204
+ ).tag(config=True)
205
+ @default('ipython_dir')
206
+ def _ipython_dir_default(self):
207
+ d = get_ipython_dir()
208
+ self._ipython_dir_changed({
209
+ 'name': 'ipython_dir',
210
+ 'old': d,
211
+ 'new': d,
212
+ })
213
+ return d
214
+
215
+ _in_init_profile_dir = False
216
+
217
+ profile_dir = Instance(ProfileDir, allow_none=True)
218
+
219
+ @default('profile_dir')
220
+ def _profile_dir_default(self):
221
+ # avoid recursion
222
+ if self._in_init_profile_dir:
223
+ return
224
+ # profile_dir requested early, force initialization
225
+ self.init_profile_dir()
226
+ return self.profile_dir
227
+
228
+ overwrite = Bool(False,
229
+ help="""Whether to overwrite existing config files when copying"""
230
+ ).tag(config=True)
231
+
232
+ auto_create = Bool(False,
233
+ help="""Whether to create profile dir if it doesn't exist"""
234
+ ).tag(config=True)
235
+
236
+ config_files = List(Unicode())
237
+
238
+ @default('config_files')
239
+ def _config_files_default(self):
240
+ return [self.config_file_name]
241
+
242
+ copy_config_files = Bool(False,
243
+ help="""Whether to install the default config files into the profile dir.
244
+ If a new profile is being created, and IPython contains config files for that
245
+ profile, then they will be staged into the new directory. Otherwise,
246
+ default config files will be automatically generated.
247
+ """).tag(config=True)
248
+
249
+ verbose_crash = Bool(False,
250
+ help="""Create a massive crash report when IPython encounters what may be an
251
+ internal error. The default is to append a short message to the
252
+ usual traceback""").tag(config=True)
253
+
254
+ # The class to use as the crash handler.
255
+ crash_handler_class = Type(crashhandler.CrashHandler)
256
+
257
+ @catch_config_error
258
+ def __init__(self, **kwargs):
259
+ super(BaseIPythonApplication, self).__init__(**kwargs)
260
+ # ensure current working directory exists
261
+ try:
262
+ os.getcwd()
263
+ except:
264
+ # exit if cwd doesn't exist
265
+ self.log.error("Current working directory doesn't exist.")
266
+ self.exit(1)
267
+
268
+ #-------------------------------------------------------------------------
269
+ # Various stages of Application creation
270
+ #-------------------------------------------------------------------------
271
+
272
+ def init_crash_handler(self):
273
+ """Create a crash handler, typically setting sys.excepthook to it."""
274
+ self.crash_handler = self.crash_handler_class(self)
275
+ sys.excepthook = self.excepthook
276
+ def unset_crashhandler():
277
+ sys.excepthook = sys.__excepthook__
278
+ atexit.register(unset_crashhandler)
279
+
280
+ def excepthook(self, etype, evalue, tb):
281
+ """this is sys.excepthook after init_crashhandler
282
+
283
+ set self.verbose_crash=True to use our full crashhandler, instead of
284
+ a regular traceback with a short message (crash_handler_lite)
285
+ """
286
+
287
+ if self.verbose_crash:
288
+ return self.crash_handler(etype, evalue, tb)
289
+ else:
290
+ return crashhandler.crash_handler_lite(etype, evalue, tb)
291
+
292
+ @observe('ipython_dir')
293
+ def _ipython_dir_changed(self, change):
294
+ old = change['old']
295
+ new = change['new']
296
+ if old is not Undefined:
297
+ str_old = os.path.abspath(old)
298
+ if str_old in sys.path:
299
+ sys.path.remove(str_old)
300
+ if self.add_ipython_dir_to_sys_path:
301
+ str_path = os.path.abspath(new)
302
+ sys.path.append(str_path)
303
+ ensure_dir_exists(new)
304
+ readme = os.path.join(new, "README")
305
+ readme_src = os.path.join(
306
+ get_ipython_package_dir(), "config", "profile", "README"
307
+ )
308
+ if not os.path.exists(readme) and os.path.exists(readme_src):
309
+ shutil.copy(readme_src, readme)
310
+ for d in ("extensions", "nbextensions"):
311
+ path = os.path.join(new, d)
312
+ try:
313
+ ensure_dir_exists(path)
314
+ except OSError as e:
315
+ # this will not be EEXIST
316
+ self.log.error("couldn't create path %s: %s", path, e)
317
+ self.log.debug("IPYTHONDIR set to: %s", new)
318
+
319
+ def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
320
+ """Load the config file.
321
+
322
+ By default, errors in loading config are handled, and a warning
323
+ printed on screen. For testing, the suppress_errors option is set
324
+ to False, so errors will make tests fail.
325
+
326
+ `suppress_errors` default value is to be `None` in which case the
327
+ behavior default to the one of `traitlets.Application`.
328
+
329
+ The default value can be set :
330
+ - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
331
+ - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
332
+ - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
333
+
334
+ Any other value are invalid, and will make IPython exit with a non-zero return code.
335
+ """
336
+
337
+
338
+ self.log.debug("Searching path %s for config files", self.config_file_paths)
339
+ base_config = 'ipython_config.py'
340
+ self.log.debug("Attempting to load config file: %s" %
341
+ base_config)
342
+ try:
343
+ if suppress_errors is not None:
344
+ old_value = Application.raise_config_file_errors
345
+ Application.raise_config_file_errors = not suppress_errors;
346
+ Application.load_config_file(
347
+ self,
348
+ base_config,
349
+ path=self.config_file_paths
350
+ )
351
+ except ConfigFileNotFound:
352
+ # ignore errors loading parent
353
+ self.log.debug("Config file %s not found", base_config)
354
+ pass
355
+ if suppress_errors is not None:
356
+ Application.raise_config_file_errors = old_value
357
+
358
+ for config_file_name in self.config_files:
359
+ if not config_file_name or config_file_name == base_config:
360
+ continue
361
+ self.log.debug("Attempting to load config file: %s" %
362
+ self.config_file_name)
363
+ try:
364
+ Application.load_config_file(
365
+ self,
366
+ config_file_name,
367
+ path=self.config_file_paths
368
+ )
369
+ except ConfigFileNotFound:
370
+ # Only warn if the default config file was NOT being used.
371
+ if config_file_name in self.config_file_specified:
372
+ msg = self.log.warning
373
+ else:
374
+ msg = self.log.debug
375
+ msg("Config file not found, skipping: %s", config_file_name)
376
+ except Exception:
377
+ # For testing purposes.
378
+ if not suppress_errors:
379
+ raise
380
+ self.log.warning("Error loading config file: %s" %
381
+ self.config_file_name, exc_info=True)
382
+
383
+ def init_profile_dir(self):
384
+ """initialize the profile dir"""
385
+ self._in_init_profile_dir = True
386
+ if self.profile_dir is not None:
387
+ # already ran
388
+ return
389
+ if 'ProfileDir.location' not in self.config:
390
+ # location not specified, find by profile name
391
+ try:
392
+ p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
393
+ except ProfileDirError:
394
+ # not found, maybe create it (always create default profile)
395
+ if self.auto_create or self.profile == 'default':
396
+ try:
397
+ p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
398
+ except ProfileDirError:
399
+ self.log.fatal("Could not create profile: %r"%self.profile)
400
+ self.exit(1)
401
+ else:
402
+ self.log.info("Created profile dir: %r"%p.location)
403
+ else:
404
+ self.log.fatal("Profile %r not found."%self.profile)
405
+ self.exit(1)
406
+ else:
407
+ self.log.debug("Using existing profile dir: %r", p.location)
408
+ else:
409
+ location = self.config.ProfileDir.location
410
+ # location is fully specified
411
+ try:
412
+ p = ProfileDir.find_profile_dir(location, self.config)
413
+ except ProfileDirError:
414
+ # not found, maybe create it
415
+ if self.auto_create:
416
+ try:
417
+ p = ProfileDir.create_profile_dir(location, self.config)
418
+ except ProfileDirError:
419
+ self.log.fatal("Could not create profile directory: %r"%location)
420
+ self.exit(1)
421
+ else:
422
+ self.log.debug("Creating new profile dir: %r"%location)
423
+ else:
424
+ self.log.fatal("Profile directory %r not found."%location)
425
+ self.exit(1)
426
+ else:
427
+ self.log.debug("Using existing profile dir: %r", p.location)
428
+ # if profile_dir is specified explicitly, set profile name
429
+ dir_name = os.path.basename(p.location)
430
+ if dir_name.startswith('profile_'):
431
+ self.profile = dir_name[8:]
432
+
433
+ self.profile_dir = p
434
+ self.config_file_paths.append(p.location)
435
+ self._in_init_profile_dir = False
436
+
437
+ def init_config_files(self):
438
+ """[optionally] copy default config files into profile dir."""
439
+ self.config_file_paths.extend(ENV_CONFIG_DIRS)
440
+ self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
441
+ # copy config files
442
+ path = Path(self.builtin_profile_dir)
443
+ if self.copy_config_files:
444
+ src = self.profile
445
+
446
+ cfg = self.config_file_name
447
+ if path and (path / cfg).exists():
448
+ self.log.warning(
449
+ "Staging %r from %s into %r [overwrite=%s]"
450
+ % (cfg, src, self.profile_dir.location, self.overwrite)
451
+ )
452
+ self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
453
+ else:
454
+ self.stage_default_config_file()
455
+ else:
456
+ # Still stage *bundled* config files, but not generated ones
457
+ # This is necessary for `ipython profile=sympy` to load the profile
458
+ # on the first go
459
+ files = path.glob("*.py")
460
+ for fullpath in files:
461
+ cfg = fullpath.name
462
+ if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
463
+ # file was copied
464
+ self.log.warning("Staging bundled %s from %s into %r"%(
465
+ cfg, self.profile, self.profile_dir.location)
466
+ )
467
+
468
+
469
+ def stage_default_config_file(self):
470
+ """auto generate default config file, and stage it into the profile."""
471
+ s = self.generate_config_file()
472
+ config_file = Path(self.profile_dir.location) / self.config_file_name
473
+ if self.overwrite or not config_file.exists():
474
+ self.log.warning("Generating default config file: %r", (config_file))
475
+ config_file.write_text(s, encoding="utf-8")
476
+
477
+ @catch_config_error
478
+ def initialize(self, argv=None):
479
+ # don't hook up crash handler before parsing command-line
480
+ self.parse_command_line(argv)
481
+ self.init_crash_handler()
482
+ if self.subapp is not None:
483
+ # stop here if subapp is taking over
484
+ return
485
+ # save a copy of CLI config to re-load after config files
486
+ # so that it has highest priority
487
+ cl_config = deepcopy(self.config)
488
+ self.init_profile_dir()
489
+ self.init_config_files()
490
+ self.load_config_file()
491
+ # enforce cl-opts override configfile opts:
492
+ self.update_config(cl_config)
openalex_env_map/lib/python3.10/site-packages/IPython/core/async_helpers.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Async helper function that are invalid syntax on Python 3.5 and below.
3
+
4
+ This code is best effort, and may have edge cases not behaving as expected. In
5
+ particular it contain a number of heuristics to detect whether code is
6
+ effectively async and need to run in an event loop or not.
7
+
8
+ Some constructs (like top-level `return`, or `yield`) are taken care of
9
+ explicitly to actually raise a SyntaxError and stay as close as possible to
10
+ Python semantics.
11
+ """
12
+
13
+ import ast
14
+ import asyncio
15
+ import inspect
16
+ from functools import wraps
17
+
18
+ _asyncio_event_loop = None
19
+
20
+
21
+ def get_asyncio_loop():
22
+ """asyncio has deprecated get_event_loop
23
+
24
+ Replicate it here, with our desired semantics:
25
+
26
+ - always returns a valid, not-closed loop
27
+ - not thread-local like asyncio's,
28
+ because we only want one loop for IPython
29
+ - if called from inside a coroutine (e.g. in ipykernel),
30
+ return the running loop
31
+
32
+ .. versionadded:: 8.0
33
+ """
34
+ try:
35
+ return asyncio.get_running_loop()
36
+ except RuntimeError:
37
+ # not inside a coroutine,
38
+ # track our own global
39
+ pass
40
+
41
+ # not thread-local like asyncio's,
42
+ # because we only track one event loop to run for IPython itself,
43
+ # always in the main thread.
44
+ global _asyncio_event_loop
45
+ if _asyncio_event_loop is None or _asyncio_event_loop.is_closed():
46
+ _asyncio_event_loop = asyncio.new_event_loop()
47
+ return _asyncio_event_loop
48
+
49
+
50
+ class _AsyncIORunner:
51
+ def __call__(self, coro):
52
+ """
53
+ Handler for asyncio autoawait
54
+ """
55
+ return get_asyncio_loop().run_until_complete(coro)
56
+
57
+ def __str__(self):
58
+ return "asyncio"
59
+
60
+
61
+ _asyncio_runner = _AsyncIORunner()
62
+
63
+
64
+ class _AsyncIOProxy:
65
+ """Proxy-object for an asyncio
66
+
67
+ Any coroutine methods will be wrapped in event_loop.run_
68
+ """
69
+
70
+ def __init__(self, obj, event_loop):
71
+ self._obj = obj
72
+ self._event_loop = event_loop
73
+
74
+ def __repr__(self):
75
+ return f"<_AsyncIOProxy({self._obj!r})>"
76
+
77
+ def __getattr__(self, key):
78
+ attr = getattr(self._obj, key)
79
+ if inspect.iscoroutinefunction(attr):
80
+ # if it's a coroutine method,
81
+ # return a threadsafe wrapper onto the _current_ asyncio loop
82
+ @wraps(attr)
83
+ def _wrapped(*args, **kwargs):
84
+ concurrent_future = asyncio.run_coroutine_threadsafe(
85
+ attr(*args, **kwargs), self._event_loop
86
+ )
87
+ return asyncio.wrap_future(concurrent_future)
88
+
89
+ return _wrapped
90
+ else:
91
+ return attr
92
+
93
+ def __dir__(self):
94
+ return dir(self._obj)
95
+
96
+
97
+ def _curio_runner(coroutine):
98
+ """
99
+ handler for curio autoawait
100
+ """
101
+ import curio
102
+
103
+ return curio.run(coroutine)
104
+
105
+
106
+ def _trio_runner(async_fn):
107
+ import trio
108
+
109
+ async def loc(coro):
110
+ """
111
+ We need the dummy no-op async def to protect from
112
+ trio's internal. See https://github.com/python-trio/trio/issues/89
113
+ """
114
+ return await coro
115
+
116
+ return trio.run(loc, async_fn)
117
+
118
+
119
+ def _pseudo_sync_runner(coro):
120
+ """
121
+ A runner that does not really allow async execution, and just advance the coroutine.
122
+
123
+ See discussion in https://github.com/python-trio/trio/issues/608,
124
+
125
+ Credit to Nathaniel Smith
126
+ """
127
+ try:
128
+ coro.send(None)
129
+ except StopIteration as exc:
130
+ return exc.value
131
+ else:
132
+ # TODO: do not raise but return an execution result with the right info.
133
+ raise RuntimeError(
134
+ "{coro_name!r} needs a real async loop".format(coro_name=coro.__name__)
135
+ )
136
+
137
+
138
+ def _should_be_async(cell: str) -> bool:
139
+ """Detect if a block of code need to be wrapped in an `async def`
140
+
141
+ Attempt to parse the block of code, it it compile we're fine.
142
+ Otherwise we wrap if and try to compile.
143
+
144
+ If it works, assume it should be async. Otherwise Return False.
145
+
146
+ Not handled yet: If the block of code has a return statement as the top
147
+ level, it will be seen as async. This is a know limitation.
148
+ """
149
+ try:
150
+ code = compile(
151
+ cell, "<>", "exec", flags=getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
152
+ )
153
+ return inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
154
+ except (SyntaxError, MemoryError):
155
+ return False
openalex_env_map/lib/python3.10/site-packages/IPython/core/autocall.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """
3
+ Autocall capabilities for IPython.core.
4
+
5
+ Authors:
6
+
7
+ * Brian Granger
8
+ * Fernando Perez
9
+ * Thomas Kluyver
10
+
11
+ Notes
12
+ -----
13
+ """
14
+
15
+ #-----------------------------------------------------------------------------
16
+ # Copyright (C) 2008-2011 The IPython Development Team
17
+ #
18
+ # Distributed under the terms of the BSD License. The full license is in
19
+ # the file COPYING, distributed as part of this software.
20
+ #-----------------------------------------------------------------------------
21
+
22
+ #-----------------------------------------------------------------------------
23
+ # Imports
24
+ #-----------------------------------------------------------------------------
25
+
26
+
27
+ #-----------------------------------------------------------------------------
28
+ # Code
29
+ #-----------------------------------------------------------------------------
30
+
31
+ class IPyAutocall(object):
32
+ """ Instances of this class are always autocalled
33
+
34
+ This happens regardless of 'autocall' variable state. Use this to
35
+ develop macro-like mechanisms.
36
+ """
37
+ _ip = None
38
+ rewrite = True
39
+ def __init__(self, ip=None):
40
+ self._ip = ip
41
+
42
+ def set_ip(self, ip):
43
+ """Will be used to set _ip point to current ipython instance b/f call
44
+
45
+ Override this method if you don't want this to happen.
46
+
47
+ """
48
+ self._ip = ip
49
+
50
+
51
+ class ExitAutocall(IPyAutocall):
52
+ """An autocallable object which will be added to the user namespace so that
53
+ exit, exit(), quit or quit() are all valid ways to close the shell."""
54
+ rewrite = False
55
+
56
+ def __call__(self):
57
+ self._ip.ask_exit()
58
+
59
+ class ZMQExitAutocall(ExitAutocall):
60
+ """Exit IPython. Autocallable, so it needn't be explicitly called.
61
+
62
+ Parameters
63
+ ----------
64
+ keep_kernel : bool
65
+ If True, leave the kernel alive. Otherwise, tell the kernel to exit too
66
+ (default).
67
+ """
68
+ def __call__(self, keep_kernel=False):
69
+ self._ip.keepkernel_on_exit = keep_kernel
70
+ self._ip.ask_exit()
openalex_env_map/lib/python3.10/site-packages/IPython/core/builtin_trap.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ A context manager for managing things injected into :mod:`builtins`.
3
+ """
4
+ # Copyright (c) IPython Development Team.
5
+ # Distributed under the terms of the Modified BSD License.
6
+ import builtins as builtin_mod
7
+
8
+ from traitlets.config.configurable import Configurable
9
+
10
+ from traitlets import Instance
11
+
12
+
13
+ class __BuiltinUndefined(object): pass
14
+ BuiltinUndefined = __BuiltinUndefined()
15
+
16
+ class __HideBuiltin(object): pass
17
+ HideBuiltin = __HideBuiltin()
18
+
19
+
20
+ class BuiltinTrap(Configurable):
21
+
22
+ shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
23
+ allow_none=True)
24
+
25
+ def __init__(self, shell=None):
26
+ super(BuiltinTrap, self).__init__(shell=shell, config=None)
27
+ self._orig_builtins = {}
28
+ # We define this to track if a single BuiltinTrap is nested.
29
+ # Only turn off the trap when the outermost call to __exit__ is made.
30
+ self._nested_level = 0
31
+ self.shell = shell
32
+ # builtins we always add - if set to HideBuiltin, they will just
33
+ # be removed instead of being replaced by something else
34
+ self.auto_builtins = {'exit': HideBuiltin,
35
+ 'quit': HideBuiltin,
36
+ 'get_ipython': self.shell.get_ipython,
37
+ }
38
+
39
+ def __enter__(self):
40
+ if self._nested_level == 0:
41
+ self.activate()
42
+ self._nested_level += 1
43
+ # I return self, so callers can use add_builtin in a with clause.
44
+ return self
45
+
46
+ def __exit__(self, type, value, traceback):
47
+ if self._nested_level == 1:
48
+ self.deactivate()
49
+ self._nested_level -= 1
50
+ # Returning False will cause exceptions to propagate
51
+ return False
52
+
53
+ def add_builtin(self, key, value):
54
+ """Add a builtin and save the original."""
55
+ bdict = builtin_mod.__dict__
56
+ orig = bdict.get(key, BuiltinUndefined)
57
+ if value is HideBuiltin:
58
+ if orig is not BuiltinUndefined: #same as 'key in bdict'
59
+ self._orig_builtins[key] = orig
60
+ del bdict[key]
61
+ else:
62
+ self._orig_builtins[key] = orig
63
+ bdict[key] = value
64
+
65
+ def remove_builtin(self, key, orig):
66
+ """Remove an added builtin and re-set the original."""
67
+ if orig is BuiltinUndefined:
68
+ del builtin_mod.__dict__[key]
69
+ else:
70
+ builtin_mod.__dict__[key] = orig
71
+
72
+ def activate(self):
73
+ """Store ipython references in the __builtin__ namespace."""
74
+
75
+ add_builtin = self.add_builtin
76
+ for name, func in self.auto_builtins.items():
77
+ add_builtin(name, func)
78
+
79
+ def deactivate(self):
80
+ """Remove any builtins which might have been added by add_builtins, or
81
+ restore overwritten ones to their previous values."""
82
+ remove_builtin = self.remove_builtin
83
+ for key, val in self._orig_builtins.items():
84
+ remove_builtin(key, val)
85
+ self._orig_builtins.clear()
86
+ self._builtins_added = False
openalex_env_map/lib/python3.10/site-packages/IPython/core/compilerop.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Compiler tools with improved interactive support.
2
+
3
+ Provides compilation machinery similar to codeop, but with caching support so
4
+ we can provide interactive tracebacks.
5
+
6
+ Authors
7
+ -------
8
+ * Robert Kern
9
+ * Fernando Perez
10
+ * Thomas Kluyver
11
+ """
12
+
13
+ # Note: though it might be more natural to name this module 'compiler', that
14
+ # name is in the stdlib and name collisions with the stdlib tend to produce
15
+ # weird problems (often with third-party tools).
16
+
17
+ #-----------------------------------------------------------------------------
18
+ # Copyright (C) 2010-2011 The IPython Development Team.
19
+ #
20
+ # Distributed under the terms of the BSD License.
21
+ #
22
+ # The full license is in the file COPYING.txt, distributed with this software.
23
+ #-----------------------------------------------------------------------------
24
+
25
+ #-----------------------------------------------------------------------------
26
+ # Imports
27
+ #-----------------------------------------------------------------------------
28
+
29
+ # Stdlib imports
30
+ import __future__
31
+ from ast import PyCF_ONLY_AST
32
+ import codeop
33
+ import functools
34
+ import hashlib
35
+ import linecache
36
+ import operator
37
+ import time
38
+ from contextlib import contextmanager
39
+
40
+ #-----------------------------------------------------------------------------
41
+ # Constants
42
+ #-----------------------------------------------------------------------------
43
+
44
+ # Roughly equal to PyCF_MASK | PyCF_MASK_OBSOLETE as defined in pythonrun.h,
45
+ # this is used as a bitmask to extract future-related code flags.
46
+ PyCF_MASK = functools.reduce(operator.or_,
47
+ (getattr(__future__, fname).compiler_flag
48
+ for fname in __future__.all_feature_names))
49
+
50
+ #-----------------------------------------------------------------------------
51
+ # Local utilities
52
+ #-----------------------------------------------------------------------------
53
+
54
+ def code_name(code, number=0):
55
+ """ Compute a (probably) unique name for code for caching.
56
+
57
+ This now expects code to be unicode.
58
+ """
59
+ hash_digest = hashlib.sha1(code.encode("utf-8")).hexdigest()
60
+ # Include the number and 12 characters of the hash in the name. It's
61
+ # pretty much impossible that in a single session we'll have collisions
62
+ # even with truncated hashes, and the full one makes tracebacks too long
63
+ return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
64
+
65
+ #-----------------------------------------------------------------------------
66
+ # Classes and functions
67
+ #-----------------------------------------------------------------------------
68
+
69
+ class CachingCompiler(codeop.Compile):
70
+ """A compiler that caches code compiled from interactive statements.
71
+ """
72
+
73
+ def __init__(self):
74
+ codeop.Compile.__init__(self)
75
+
76
+ # Caching a dictionary { filename: execution_count } for nicely
77
+ # rendered tracebacks. The filename corresponds to the filename
78
+ # argument used for the builtins.compile function.
79
+ self._filename_map = {}
80
+
81
+ def ast_parse(self, source, filename='<unknown>', symbol='exec'):
82
+ """Parse code to an AST with the current compiler flags active.
83
+
84
+ Arguments are exactly the same as ast.parse (in the standard library),
85
+ and are passed to the built-in compile function."""
86
+ return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
87
+
88
+ def reset_compiler_flags(self):
89
+ """Reset compiler flags to default state."""
90
+ # This value is copied from codeop.Compile.__init__, so if that ever
91
+ # changes, it will need to be updated.
92
+ self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
93
+
94
+ @property
95
+ def compiler_flags(self):
96
+ """Flags currently active in the compilation process.
97
+ """
98
+ return self.flags
99
+
100
+ def get_code_name(self, raw_code, transformed_code, number):
101
+ """Compute filename given the code, and the cell number.
102
+
103
+ Parameters
104
+ ----------
105
+ raw_code : str
106
+ The raw cell code.
107
+ transformed_code : str
108
+ The executable Python source code to cache and compile.
109
+ number : int
110
+ A number which forms part of the code's name. Used for the execution
111
+ counter.
112
+
113
+ Returns
114
+ -------
115
+ The computed filename.
116
+ """
117
+ return code_name(transformed_code, number)
118
+
119
+ def format_code_name(self, name):
120
+ """Return a user-friendly label and name for a code block.
121
+
122
+ Parameters
123
+ ----------
124
+ name : str
125
+ The name for the code block returned from get_code_name
126
+
127
+ Returns
128
+ -------
129
+ A (label, name) pair that can be used in tracebacks, or None if the default formatting should be used.
130
+ """
131
+ if name in self._filename_map:
132
+ return "Cell", "In[%s]" % self._filename_map[name]
133
+
134
+ def cache(self, transformed_code, number=0, raw_code=None):
135
+ """Make a name for a block of code, and cache the code.
136
+
137
+ Parameters
138
+ ----------
139
+ transformed_code : str
140
+ The executable Python source code to cache and compile.
141
+ number : int
142
+ A number which forms part of the code's name. Used for the execution
143
+ counter.
144
+ raw_code : str
145
+ The raw code before transformation, if None, set to `transformed_code`.
146
+
147
+ Returns
148
+ -------
149
+ The name of the cached code (as a string). Pass this as the filename
150
+ argument to compilation, so that tracebacks are correctly hooked up.
151
+ """
152
+ if raw_code is None:
153
+ raw_code = transformed_code
154
+
155
+ name = self.get_code_name(raw_code, transformed_code, number)
156
+
157
+ # Save the execution count
158
+ self._filename_map[name] = number
159
+
160
+ # Since Python 2.5, setting mtime to `None` means the lines will
161
+ # never be removed by `linecache.checkcache`. This means all the
162
+ # monkeypatching has *never* been necessary, since this code was
163
+ # only added in 2010, at which point IPython had already stopped
164
+ # supporting Python 2.4.
165
+ #
166
+ # Note that `linecache.clearcache` and `linecache.updatecache` may
167
+ # still remove our code from the cache, but those show explicit
168
+ # intent, and we should not try to interfere. Normally the former
169
+ # is never called except when out of memory, and the latter is only
170
+ # called for lines *not* in the cache.
171
+ entry = (
172
+ len(transformed_code),
173
+ None,
174
+ [line + "\n" for line in transformed_code.splitlines()],
175
+ name,
176
+ )
177
+ linecache.cache[name] = entry
178
+ return name
179
+
180
+ @contextmanager
181
+ def extra_flags(self, flags):
182
+ ## bits that we'll set to 1
183
+ turn_on_bits = ~self.flags & flags
184
+
185
+
186
+ self.flags = self.flags | flags
187
+ try:
188
+ yield
189
+ finally:
190
+ # turn off only the bits we turned on so that something like
191
+ # __future__ that set flags stays.
192
+ self.flags &= ~turn_on_bits
193
+
194
+
195
+ def check_linecache_ipython(*args):
196
+ """Deprecated since IPython 8.6. Call linecache.checkcache() directly.
197
+
198
+ It was already not necessary to call this function directly. If no
199
+ CachingCompiler had been created, this function would fail badly. If
200
+ an instance had been created, this function would've been monkeypatched
201
+ into place.
202
+
203
+ As of IPython 8.6, the monkeypatching has gone away entirely. But there
204
+ were still internal callers of this function, so maybe external callers
205
+ also existed?
206
+ """
207
+ import warnings
208
+
209
+ warnings.warn(
210
+ "Deprecated Since IPython 8.6, Just call linecache.checkcache() directly.",
211
+ DeprecationWarning,
212
+ stacklevel=2,
213
+ )
214
+ linecache.checkcache()
openalex_env_map/lib/python3.10/site-packages/IPython/core/completer.py ADDED
The diff for this file is too large to render. See raw diff
 
openalex_env_map/lib/python3.10/site-packages/IPython/core/completerlib.py ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """Implementations for various useful completers.
3
+
4
+ These are all loaded by default by IPython.
5
+ """
6
+ #-----------------------------------------------------------------------------
7
+ # Copyright (C) 2010-2011 The IPython Development Team.
8
+ #
9
+ # Distributed under the terms of the BSD License.
10
+ #
11
+ # The full license is in the file COPYING.txt, distributed with this software.
12
+ #-----------------------------------------------------------------------------
13
+
14
+ #-----------------------------------------------------------------------------
15
+ # Imports
16
+ #-----------------------------------------------------------------------------
17
+
18
+ # Stdlib imports
19
+ import glob
20
+ import inspect
21
+ import os
22
+ import re
23
+ import sys
24
+ from importlib import import_module
25
+ from importlib.machinery import all_suffixes
26
+
27
+
28
+ # Third-party imports
29
+ from time import time
30
+ from zipimport import zipimporter
31
+
32
+ # Our own imports
33
+ from .completer import expand_user, compress_user
34
+ from .error import TryNext
35
+ from ..utils._process_common import arg_split
36
+
37
+ # FIXME: this should be pulled in with the right call via the component system
38
+ from IPython import get_ipython
39
+
40
+ from typing import List
41
+
42
+ #-----------------------------------------------------------------------------
43
+ # Globals and constants
44
+ #-----------------------------------------------------------------------------
45
+ _suffixes = all_suffixes()
46
+
47
+ # Time in seconds after which the rootmodules will be stored permanently in the
48
+ # ipython ip.db database (kept in the user's .ipython dir).
49
+ TIMEOUT_STORAGE = 2
50
+
51
+ # Time in seconds after which we give up
52
+ TIMEOUT_GIVEUP = 20
53
+
54
+ # Regular expression for the python import statement
55
+ import_re = re.compile(r'(?P<name>[^\W\d]\w*?)'
56
+ r'(?P<package>[/\\]__init__)?'
57
+ r'(?P<suffix>%s)$' %
58
+ r'|'.join(re.escape(s) for s in _suffixes))
59
+
60
+ # RE for the ipython %run command (python + ipython scripts)
61
+ magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$')
62
+
63
+ #-----------------------------------------------------------------------------
64
+ # Local utilities
65
+ #-----------------------------------------------------------------------------
66
+
67
+
68
+ def module_list(path: str) -> List[str]:
69
+ """
70
+ Return the list containing the names of the modules available in the given
71
+ folder.
72
+ """
73
+ # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
74
+ if path == '':
75
+ path = '.'
76
+
77
+ # A few local constants to be used in loops below
78
+ pjoin = os.path.join
79
+
80
+ if os.path.isdir(path):
81
+ # Build a list of all files in the directory and all files
82
+ # in its subdirectories. For performance reasons, do not
83
+ # recurse more than one level into subdirectories.
84
+ files: List[str] = []
85
+ for root, dirs, nondirs in os.walk(path, followlinks=True):
86
+ subdir = root[len(path)+1:]
87
+ if subdir:
88
+ files.extend(pjoin(subdir, f) for f in nondirs)
89
+ dirs[:] = [] # Do not recurse into additional subdirectories.
90
+ else:
91
+ files.extend(nondirs)
92
+
93
+ else:
94
+ try:
95
+ files = list(zipimporter(path)._files.keys()) # type: ignore
96
+ except Exception:
97
+ files = []
98
+
99
+ # Build a list of modules which match the import_re regex.
100
+ modules = []
101
+ for f in files:
102
+ m = import_re.match(f)
103
+ if m:
104
+ modules.append(m.group('name'))
105
+ return list(set(modules))
106
+
107
+
108
+ def get_root_modules():
109
+ """
110
+ Returns a list containing the names of all the modules available in the
111
+ folders of the pythonpath.
112
+
113
+ ip.db['rootmodules_cache'] maps sys.path entries to list of modules.
114
+ """
115
+ ip = get_ipython()
116
+ if ip is None:
117
+ # No global shell instance to store cached list of modules.
118
+ # Don't try to scan for modules every time.
119
+ return list(sys.builtin_module_names)
120
+
121
+ if getattr(ip.db, "_mock", False):
122
+ rootmodules_cache = {}
123
+ else:
124
+ rootmodules_cache = ip.db.get("rootmodules_cache", {})
125
+ rootmodules = list(sys.builtin_module_names)
126
+ start_time = time()
127
+ store = False
128
+ for path in sys.path:
129
+ try:
130
+ modules = rootmodules_cache[path]
131
+ except KeyError:
132
+ modules = module_list(path)
133
+ try:
134
+ modules.remove('__init__')
135
+ except ValueError:
136
+ pass
137
+ if path not in ('', '.'): # cwd modules should not be cached
138
+ rootmodules_cache[path] = modules
139
+ if time() - start_time > TIMEOUT_STORAGE and not store:
140
+ store = True
141
+ print("\nCaching the list of root modules, please wait!")
142
+ print("(This will only be done once - type '%rehashx' to "
143
+ "reset cache!)\n")
144
+ sys.stdout.flush()
145
+ if time() - start_time > TIMEOUT_GIVEUP:
146
+ print("This is taking too long, we give up.\n")
147
+ return []
148
+ rootmodules.extend(modules)
149
+ if store:
150
+ ip.db['rootmodules_cache'] = rootmodules_cache
151
+ rootmodules = list(set(rootmodules))
152
+ return rootmodules
153
+
154
+
155
+ def is_importable(module, attr: str, only_modules) -> bool:
156
+ if only_modules:
157
+ try:
158
+ mod = getattr(module, attr)
159
+ except ModuleNotFoundError:
160
+ # See gh-14434
161
+ return False
162
+ return inspect.ismodule(mod)
163
+ else:
164
+ return not(attr[:2] == '__' and attr[-2:] == '__')
165
+
166
+ def is_possible_submodule(module, attr):
167
+ try:
168
+ obj = getattr(module, attr)
169
+ except AttributeError:
170
+ # Is possibly an unimported submodule
171
+ return True
172
+ except TypeError:
173
+ # https://github.com/ipython/ipython/issues/9678
174
+ return False
175
+ return inspect.ismodule(obj)
176
+
177
+
178
+ def try_import(mod: str, only_modules=False) -> List[str]:
179
+ """
180
+ Try to import given module and return list of potential completions.
181
+ """
182
+ mod = mod.rstrip('.')
183
+ try:
184
+ m = import_module(mod)
185
+ except:
186
+ return []
187
+
188
+ m_is_init = '__init__' in (getattr(m, '__file__', '') or '')
189
+
190
+ completions = []
191
+ if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
192
+ completions.extend( [attr for attr in dir(m) if
193
+ is_importable(m, attr, only_modules)])
194
+
195
+ m_all = getattr(m, "__all__", [])
196
+ if only_modules:
197
+ completions.extend(attr for attr in m_all if is_possible_submodule(m, attr))
198
+ else:
199
+ completions.extend(m_all)
200
+
201
+ if m_is_init:
202
+ file_ = m.__file__
203
+ file_path = os.path.dirname(file_) # type: ignore
204
+ if file_path is not None:
205
+ completions.extend(module_list(file_path))
206
+ completions_set = {c for c in completions if isinstance(c, str)}
207
+ completions_set.discard('__init__')
208
+ return list(completions_set)
209
+
210
+
211
+ #-----------------------------------------------------------------------------
212
+ # Completion-related functions.
213
+ #-----------------------------------------------------------------------------
214
+
215
+ def quick_completer(cmd, completions):
216
+ r""" Easily create a trivial completer for a command.
217
+
218
+ Takes either a list of completions, or all completions in string (that will
219
+ be split on whitespace).
220
+
221
+ Example::
222
+
223
+ [d:\ipython]|1> import ipy_completers
224
+ [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
225
+ [d:\ipython]|3> foo b<TAB>
226
+ bar baz
227
+ [d:\ipython]|3> foo ba
228
+ """
229
+
230
+ if isinstance(completions, str):
231
+ completions = completions.split()
232
+
233
+ def do_complete(self, event):
234
+ return completions
235
+
236
+ get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
237
+
238
+ def module_completion(line):
239
+ """
240
+ Returns a list containing the completion possibilities for an import line.
241
+
242
+ The line looks like this :
243
+ 'import xml.d'
244
+ 'from xml.dom import'
245
+ """
246
+
247
+ words = line.split(' ')
248
+ nwords = len(words)
249
+
250
+ # from whatever <tab> -> 'import '
251
+ if nwords == 3 and words[0] == 'from':
252
+ return ['import ']
253
+
254
+ # 'from xy<tab>' or 'import xy<tab>'
255
+ if nwords < 3 and (words[0] in {'%aimport', 'import', 'from'}) :
256
+ if nwords == 1:
257
+ return get_root_modules()
258
+ mod = words[1].split('.')
259
+ if len(mod) < 2:
260
+ return get_root_modules()
261
+ completion_list = try_import('.'.join(mod[:-1]), True)
262
+ return ['.'.join(mod[:-1] + [el]) for el in completion_list]
263
+
264
+ # 'from xyz import abc<tab>'
265
+ if nwords >= 3 and words[0] == 'from':
266
+ mod = words[1]
267
+ return try_import(mod)
268
+
269
+ #-----------------------------------------------------------------------------
270
+ # Completers
271
+ #-----------------------------------------------------------------------------
272
+ # These all have the func(self, event) signature to be used as custom
273
+ # completers
274
+
275
+ def module_completer(self,event):
276
+ """Give completions after user has typed 'import ...' or 'from ...'"""
277
+
278
+ # This works in all versions of python. While 2.5 has
279
+ # pkgutil.walk_packages(), that particular routine is fairly dangerous,
280
+ # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
281
+ # of possibly problematic side effects.
282
+ # This search the folders in the sys.path for available modules.
283
+
284
+ return module_completion(event.line)
285
+
286
+ # FIXME: there's a lot of logic common to the run, cd and builtin file
287
+ # completers, that is currently reimplemented in each.
288
+
289
+ def magic_run_completer(self, event):
290
+ """Complete files that end in .py or .ipy or .ipynb for the %run command.
291
+ """
292
+ comps = arg_split(event.line, strict=False)
293
+ # relpath should be the current token that we need to complete.
294
+ if (len(comps) > 1) and (not event.line.endswith(' ')):
295
+ relpath = comps[-1].strip("'\"")
296
+ else:
297
+ relpath = ''
298
+
299
+ #print("\nev=", event) # dbg
300
+ #print("rp=", relpath) # dbg
301
+ #print('comps=', comps) # dbg
302
+
303
+ lglob = glob.glob
304
+ isdir = os.path.isdir
305
+ relpath, tilde_expand, tilde_val = expand_user(relpath)
306
+
307
+ # Find if the user has already typed the first filename, after which we
308
+ # should complete on all files, since after the first one other files may
309
+ # be arguments to the input script.
310
+
311
+ if any(magic_run_re.match(c) for c in comps):
312
+ matches = [f.replace('\\','/') + ('/' if isdir(f) else '')
313
+ for f in lglob(relpath+'*')]
314
+ else:
315
+ dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
316
+ pys = [f.replace('\\','/')
317
+ for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
318
+ lglob(relpath+'*.ipynb') + lglob(relpath + '*.pyw')]
319
+
320
+ matches = dirs + pys
321
+
322
+ #print('run comp:', dirs+pys) # dbg
323
+ return [compress_user(p, tilde_expand, tilde_val) for p in matches]
324
+
325
+
326
+ def cd_completer(self, event):
327
+ """Completer function for cd, which only returns directories."""
328
+ ip = get_ipython()
329
+ relpath = event.symbol
330
+
331
+ #print(event) # dbg
332
+ if event.line.endswith('-b') or ' -b ' in event.line:
333
+ # return only bookmark completions
334
+ bkms = self.db.get('bookmarks', None)
335
+ if bkms:
336
+ return bkms.keys()
337
+ else:
338
+ return []
339
+
340
+ if event.symbol == '-':
341
+ width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
342
+ # jump in directory history by number
343
+ fmt = '-%0' + width_dh +'d [%s]'
344
+ ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
345
+ if len(ents) > 1:
346
+ return ents
347
+ return []
348
+
349
+ if event.symbol.startswith('--'):
350
+ return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
351
+
352
+ # Expand ~ in path and normalize directory separators.
353
+ relpath, tilde_expand, tilde_val = expand_user(relpath)
354
+ relpath = relpath.replace('\\','/')
355
+
356
+ found = []
357
+ for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
358
+ if os.path.isdir(f)]:
359
+ if ' ' in d:
360
+ # we don't want to deal with any of that, complex code
361
+ # for this is elsewhere
362
+ raise TryNext
363
+
364
+ found.append(d)
365
+
366
+ if not found:
367
+ if os.path.isdir(relpath):
368
+ return [compress_user(relpath, tilde_expand, tilde_val)]
369
+
370
+ # if no completions so far, try bookmarks
371
+ bks = self.db.get('bookmarks',{})
372
+ bkmatches = [s for s in bks if s.startswith(event.symbol)]
373
+ if bkmatches:
374
+ return bkmatches
375
+
376
+ raise TryNext
377
+
378
+ return [compress_user(p, tilde_expand, tilde_val) for p in found]
379
+
380
+ def reset_completer(self, event):
381
+ "A completer for %reset magic"
382
+ return '-f -s in out array dhist'.split()
openalex_env_map/lib/python3.10/site-packages/IPython/core/crashhandler.py ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
+
4
+ Authors:
5
+
6
+ * Fernando Perez
7
+ * Brian E. Granger
8
+ """
9
+
10
+ #-----------------------------------------------------------------------------
11
+ # Copyright (C) 2001-2007 Fernando Perez. <[email protected]>
12
+ # Copyright (C) 2008-2011 The IPython Development Team
13
+ #
14
+ # Distributed under the terms of the BSD License. The full license is in
15
+ # the file COPYING, distributed as part of this software.
16
+ #-----------------------------------------------------------------------------
17
+
18
+ #-----------------------------------------------------------------------------
19
+ # Imports
20
+ #-----------------------------------------------------------------------------
21
+
22
+ import sys
23
+ import traceback
24
+ from pprint import pformat
25
+ from pathlib import Path
26
+
27
+ import builtins as builtin_mod
28
+
29
+ from IPython.core import ultratb
30
+ from IPython.core.application import Application
31
+ from IPython.core.release import author_email
32
+ from IPython.utils.sysinfo import sys_info
33
+
34
+ from IPython.core.release import __version__ as version
35
+
36
+ from typing import Optional, Dict
37
+ import types
38
+
39
+ #-----------------------------------------------------------------------------
40
+ # Code
41
+ #-----------------------------------------------------------------------------
42
+
43
+ # Template for the user message.
44
+ _default_message_template = """\
45
+ Oops, {app_name} crashed. We do our best to make it stable, but...
46
+
47
+ A crash report was automatically generated with the following information:
48
+ - A verbatim copy of the crash traceback.
49
+ - A copy of your input history during this session.
50
+ - Data on your current {app_name} configuration.
51
+
52
+ It was left in the file named:
53
+ \t'{crash_report_fname}'
54
+ If you can email this file to the developers, the information in it will help
55
+ them in understanding and correcting the problem.
56
+
57
+ You can mail it to: {contact_name} at {contact_email}
58
+ with the subject '{app_name} Crash Report'.
59
+
60
+ If you want to do it now, the following command will work (under Unix):
61
+ mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
62
+
63
+ In your email, please also include information about:
64
+ - The operating system under which the crash happened: Linux, macOS, Windows,
65
+ other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
66
+ Windows 10 Pro), and whether it is 32-bit or 64-bit;
67
+ - How {app_name} was installed: using pip or conda, from GitHub, as part of
68
+ a Docker container, or other, providing more detail if possible;
69
+ - How to reproduce the crash: what exact sequence of instructions can one
70
+ input to get the same crash? Ideally, find a minimal yet complete sequence
71
+ of instructions that yields the crash.
72
+
73
+ To ensure accurate tracking of this issue, please file a report about it at:
74
+ {bug_tracker}
75
+ """
76
+
77
+ _lite_message_template = """
78
+ If you suspect this is an IPython {version} bug, please report it at:
79
+ https://github.com/ipython/ipython/issues
80
+ or send an email to the mailing list at {email}
81
+
82
+ You can print a more detailed traceback right now with "%tb", or use "%debug"
83
+ to interactively debug it.
84
+
85
+ Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
86
+ {config}Application.verbose_crash=True
87
+ """
88
+
89
+
90
+ class CrashHandler:
91
+ """Customizable crash handlers for IPython applications.
92
+
93
+ Instances of this class provide a :meth:`__call__` method which can be
94
+ used as a ``sys.excepthook``. The :meth:`__call__` signature is::
95
+
96
+ def __call__(self, etype, evalue, etb)
97
+ """
98
+
99
+ message_template = _default_message_template
100
+ section_sep = '\n\n'+'*'*75+'\n\n'
101
+ info: Dict[str, Optional[str]]
102
+
103
+ def __init__(
104
+ self,
105
+ app: Application,
106
+ contact_name: Optional[str] = None,
107
+ contact_email: Optional[str] = None,
108
+ bug_tracker: Optional[str] = None,
109
+ show_crash_traceback: bool = True,
110
+ call_pdb: bool = False,
111
+ ):
112
+ """Create a new crash handler
113
+
114
+ Parameters
115
+ ----------
116
+ app : Application
117
+ A running :class:`Application` instance, which will be queried at
118
+ crash time for internal information.
119
+ contact_name : str
120
+ A string with the name of the person to contact.
121
+ contact_email : str
122
+ A string with the email address of the contact.
123
+ bug_tracker : str
124
+ A string with the URL for your project's bug tracker.
125
+ show_crash_traceback : bool
126
+ If false, don't print the crash traceback on stderr, only generate
127
+ the on-disk report
128
+ call_pdb
129
+ Whether to call pdb on crash
130
+
131
+ Attributes
132
+ ----------
133
+ These instances contain some non-argument attributes which allow for
134
+ further customization of the crash handler's behavior. Please see the
135
+ source for further details.
136
+
137
+ """
138
+ self.crash_report_fname = "Crash_report_%s.txt" % app.name
139
+ self.app = app
140
+ self.call_pdb = call_pdb
141
+ #self.call_pdb = True # dbg
142
+ self.show_crash_traceback = show_crash_traceback
143
+ self.info = dict(app_name = app.name,
144
+ contact_name = contact_name,
145
+ contact_email = contact_email,
146
+ bug_tracker = bug_tracker,
147
+ crash_report_fname = self.crash_report_fname)
148
+
149
+ def __call__(
150
+ self,
151
+ etype: type[BaseException],
152
+ evalue: BaseException,
153
+ etb: types.TracebackType,
154
+ ) -> None:
155
+ """Handle an exception, call for compatible with sys.excepthook"""
156
+
157
+ # do not allow the crash handler to be called twice without reinstalling it
158
+ # this prevents unlikely errors in the crash handling from entering an
159
+ # infinite loop.
160
+ sys.excepthook = sys.__excepthook__
161
+
162
+ # Report tracebacks shouldn't use color in general (safer for users)
163
+ color_scheme = 'NoColor'
164
+
165
+ # Use this ONLY for developer debugging (keep commented out for release)
166
+ # color_scheme = 'Linux' # dbg
167
+ ipython_dir = getattr(self.app, "ipython_dir", None)
168
+ if ipython_dir is not None:
169
+ assert isinstance(ipython_dir, str)
170
+ rptdir = Path(ipython_dir)
171
+ else:
172
+ rptdir = Path.cwd()
173
+ if not rptdir.is_dir():
174
+ rptdir = Path.cwd()
175
+ report_name = rptdir / self.crash_report_fname
176
+ # write the report filename into the instance dict so it can get
177
+ # properly expanded out in the user message template
178
+ self.crash_report_fname = str(report_name)
179
+ self.info["crash_report_fname"] = str(report_name)
180
+ TBhandler = ultratb.VerboseTB(
181
+ color_scheme=color_scheme,
182
+ long_header=True,
183
+ call_pdb=self.call_pdb,
184
+ )
185
+ if self.call_pdb:
186
+ TBhandler(etype,evalue,etb)
187
+ return
188
+ else:
189
+ traceback = TBhandler.text(etype,evalue,etb,context=31)
190
+
191
+ # print traceback to screen
192
+ if self.show_crash_traceback:
193
+ print(traceback, file=sys.stderr)
194
+
195
+ # and generate a complete report on disk
196
+ try:
197
+ report = open(report_name, "w", encoding="utf-8")
198
+ except:
199
+ print('Could not create crash report on disk.', file=sys.stderr)
200
+ return
201
+
202
+ with report:
203
+ # Inform user on stderr of what happened
204
+ print('\n'+'*'*70+'\n', file=sys.stderr)
205
+ print(self.message_template.format(**self.info), file=sys.stderr)
206
+
207
+ # Construct report on disk
208
+ report.write(self.make_report(str(traceback)))
209
+
210
+ builtin_mod.input("Hit <Enter> to quit (your terminal may close):")
211
+
212
+ def make_report(self, traceback: str) -> str:
213
+ """Return a string containing a crash report."""
214
+
215
+ sec_sep = self.section_sep
216
+
217
+ report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
218
+ rpt_add = report.append
219
+ rpt_add(sys_info())
220
+
221
+ try:
222
+ config = pformat(self.app.config)
223
+ rpt_add(sec_sep)
224
+ rpt_add("Application name: %s\n\n" % self.app.name)
225
+ rpt_add("Current user configuration structure:\n\n")
226
+ rpt_add(config)
227
+ except:
228
+ pass
229
+ rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
230
+
231
+ return ''.join(report)
232
+
233
+
234
+ def crash_handler_lite(
235
+ etype: type[BaseException], evalue: BaseException, tb: types.TracebackType
236
+ ) -> None:
237
+ """a light excepthook, adding a small message to the usual traceback"""
238
+ traceback.print_exception(etype, evalue, tb)
239
+
240
+ from IPython.core.interactiveshell import InteractiveShell
241
+ if InteractiveShell.initialized():
242
+ # we are in a Shell environment, give %magic example
243
+ config = "%config "
244
+ else:
245
+ # we are not in a shell, show generic config
246
+ config = "c."
247
+ print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
248
+
openalex_env_map/lib/python3.10/site-packages/IPython/core/debugger.py ADDED
@@ -0,0 +1,1136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Pdb debugger class.
3
+
4
+
5
+ This is an extension to PDB which adds a number of new features.
6
+ Note that there is also the `IPython.terminal.debugger` class which provides UI
7
+ improvements.
8
+
9
+ We also strongly recommend to use this via the `ipdb` package, which provides
10
+ extra configuration options.
11
+
12
+ Among other things, this subclass of PDB:
13
+ - supports many IPython magics like pdef/psource
14
+ - hide frames in tracebacks based on `__tracebackhide__`
15
+ - allows to skip frames based on `__debuggerskip__`
16
+
17
+
18
+ Global Configuration
19
+ --------------------
20
+
21
+ The IPython debugger will by read the global ``~/.pdbrc`` file.
22
+ That is to say you can list all commands supported by ipdb in your `~/.pdbrc`
23
+ configuration file, to globally configure pdb.
24
+
25
+ Example::
26
+
27
+ # ~/.pdbrc
28
+ skip_predicates debuggerskip false
29
+ skip_hidden false
30
+ context 25
31
+
32
+ Features
33
+ --------
34
+
35
+ The IPython debugger can hide and skip frames when printing or moving through
36
+ the stack. This can have a performance impact, so can be configures.
37
+
38
+ The skipping and hiding frames are configurable via the `skip_predicates`
39
+ command.
40
+
41
+ By default, frames from readonly files will be hidden, frames containing
42
+ ``__tracebackhide__ = True`` will be hidden.
43
+
44
+ Frames containing ``__debuggerskip__`` will be stepped over, frames whose parent
45
+ frames value of ``__debuggerskip__`` is ``True`` will also be skipped.
46
+
47
+ >>> def helpers_helper():
48
+ ... pass
49
+ ...
50
+ ... def helper_1():
51
+ ... print("don't step in me")
52
+ ... helpers_helpers() # will be stepped over unless breakpoint set.
53
+ ...
54
+ ...
55
+ ... def helper_2():
56
+ ... print("in me neither")
57
+ ...
58
+
59
+ One can define a decorator that wraps a function between the two helpers:
60
+
61
+ >>> def pdb_skipped_decorator(function):
62
+ ...
63
+ ...
64
+ ... def wrapped_fn(*args, **kwargs):
65
+ ... __debuggerskip__ = True
66
+ ... helper_1()
67
+ ... __debuggerskip__ = False
68
+ ... result = function(*args, **kwargs)
69
+ ... __debuggerskip__ = True
70
+ ... helper_2()
71
+ ... # setting __debuggerskip__ to False again is not necessary
72
+ ... return result
73
+ ...
74
+ ... return wrapped_fn
75
+
76
+ When decorating a function, ipdb will directly step into ``bar()`` by
77
+ default:
78
+
79
+ >>> @foo_decorator
80
+ ... def bar(x, y):
81
+ ... return x * y
82
+
83
+
84
+ You can toggle the behavior with
85
+
86
+ ipdb> skip_predicates debuggerskip false
87
+
88
+ or configure it in your ``.pdbrc``
89
+
90
+
91
+
92
+ License
93
+ -------
94
+
95
+ Modified from the standard pdb.Pdb class to avoid including readline, so that
96
+ the command line completion of other programs which include this isn't
97
+ damaged.
98
+
99
+ In the future, this class will be expanded with improvements over the standard
100
+ pdb.
101
+
102
+ The original code in this file is mainly lifted out of cmd.py in Python 2.2,
103
+ with minor changes. Licensing should therefore be under the standard Python
104
+ terms. For details on the PSF (Python Software Foundation) standard license,
105
+ see:
106
+
107
+ https://docs.python.org/2/license.html
108
+
109
+
110
+ All the changes since then are under the same license as IPython.
111
+
112
+ """
113
+
114
+ #*****************************************************************************
115
+ #
116
+ # This file is licensed under the PSF license.
117
+ #
118
+ # Copyright (C) 2001 Python Software Foundation, www.python.org
119
+ # Copyright (C) 2005-2006 Fernando Perez. <[email protected]>
120
+ #
121
+ #
122
+ #*****************************************************************************
123
+
124
+ from __future__ import annotations
125
+
126
+ import inspect
127
+ import linecache
128
+ import os
129
+ import re
130
+ import sys
131
+ from contextlib import contextmanager
132
+ from functools import lru_cache
133
+
134
+ from IPython import get_ipython
135
+ from IPython.core.excolors import exception_colors
136
+ from IPython.utils import PyColorize, coloransi, py3compat
137
+
138
+ from typing import TYPE_CHECKING
139
+
140
+ if TYPE_CHECKING:
141
+ # otherwise circular import
142
+ from IPython.core.interactiveshell import InteractiveShell
143
+
144
+ # skip module docstests
145
+ __skip_doctest__ = True
146
+
147
+ prompt = 'ipdb> '
148
+
149
+ # We have to check this directly from sys.argv, config struct not yet available
150
+ from pdb import Pdb as OldPdb
151
+
152
+ # Allow the set_trace code to operate outside of an ipython instance, even if
153
+ # it does so with some limitations. The rest of this support is implemented in
154
+ # the Tracer constructor.
155
+
156
+ DEBUGGERSKIP = "__debuggerskip__"
157
+
158
+
159
+ # this has been implemented in Pdb in Python 3.13 (https://github.com/python/cpython/pull/106676
160
+ # on lower python versions, we backported the feature.
161
+ CHAIN_EXCEPTIONS = sys.version_info < (3, 13)
162
+
163
+
164
+ def make_arrow(pad):
165
+ """generate the leading arrow in front of traceback or debugger"""
166
+ if pad >= 2:
167
+ return '-'*(pad-2) + '> '
168
+ elif pad == 1:
169
+ return '>'
170
+ return ''
171
+
172
+
173
+ def BdbQuit_excepthook(et, ev, tb, excepthook=None):
174
+ """Exception hook which handles `BdbQuit` exceptions.
175
+
176
+ All other exceptions are processed using the `excepthook`
177
+ parameter.
178
+ """
179
+ raise ValueError(
180
+ "`BdbQuit_excepthook` is deprecated since version 5.1. It is still around only because it is still imported by ipdb.",
181
+ )
182
+
183
+
184
+ RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
185
+
186
+
187
+ def strip_indentation(multiline_string):
188
+ return RGX_EXTRA_INDENT.sub('', multiline_string)
189
+
190
+
191
+ def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
192
+ """Make new_fn have old_fn's doc string. This is particularly useful
193
+ for the ``do_...`` commands that hook into the help system.
194
+ Adapted from from a comp.lang.python posting
195
+ by Duncan Booth."""
196
+ def wrapper(*args, **kw):
197
+ return new_fn(*args, **kw)
198
+ if old_fn.__doc__:
199
+ wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
200
+ return wrapper
201
+
202
+
203
+ class Pdb(OldPdb):
204
+ """Modified Pdb class, does not load readline.
205
+
206
+ for a standalone version that uses prompt_toolkit, see
207
+ `IPython.terminal.debugger.TerminalPdb` and
208
+ `IPython.terminal.debugger.set_trace()`
209
+
210
+
211
+ This debugger can hide and skip frames that are tagged according to some predicates.
212
+ See the `skip_predicates` commands.
213
+
214
+ """
215
+
216
+ shell: InteractiveShell
217
+
218
+ if CHAIN_EXCEPTIONS:
219
+ MAX_CHAINED_EXCEPTION_DEPTH = 999
220
+
221
+ default_predicates = {
222
+ "tbhide": True,
223
+ "readonly": False,
224
+ "ipython_internal": True,
225
+ "debuggerskip": True,
226
+ }
227
+
228
+ def __init__(self, completekey=None, stdin=None, stdout=None, context=5, **kwargs):
229
+ """Create a new IPython debugger.
230
+
231
+ Parameters
232
+ ----------
233
+ completekey : default None
234
+ Passed to pdb.Pdb.
235
+ stdin : default None
236
+ Passed to pdb.Pdb.
237
+ stdout : default None
238
+ Passed to pdb.Pdb.
239
+ context : int
240
+ Number of lines of source code context to show when
241
+ displaying stacktrace information.
242
+ **kwargs
243
+ Passed to pdb.Pdb.
244
+
245
+ Notes
246
+ -----
247
+ The possibilities are python version dependent, see the python
248
+ docs for more info.
249
+ """
250
+
251
+ # Parent constructor:
252
+ try:
253
+ self.context = int(context)
254
+ if self.context <= 0:
255
+ raise ValueError("Context must be a positive integer")
256
+ except (TypeError, ValueError) as e:
257
+ raise ValueError("Context must be a positive integer") from e
258
+
259
+ # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
260
+ OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
261
+
262
+ # IPython changes...
263
+ self.shell = get_ipython()
264
+
265
+ if self.shell is None:
266
+ save_main = sys.modules['__main__']
267
+ # No IPython instance running, we must create one
268
+ from IPython.terminal.interactiveshell import \
269
+ TerminalInteractiveShell
270
+ self.shell = TerminalInteractiveShell.instance()
271
+ # needed by any code which calls __import__("__main__") after
272
+ # the debugger was entered. See also #9941.
273
+ sys.modules["__main__"] = save_main
274
+
275
+
276
+ color_scheme = self.shell.colors
277
+
278
+ self.aliases = {}
279
+
280
+ # Create color table: we copy the default one from the traceback
281
+ # module and add a few attributes needed for debugging
282
+ self.color_scheme_table = exception_colors()
283
+
284
+ # shorthands
285
+ C = coloransi.TermColors
286
+ cst = self.color_scheme_table
287
+
288
+
289
+ # Add a python parser so we can syntax highlight source while
290
+ # debugging.
291
+ self.parser = PyColorize.Parser(style=color_scheme)
292
+ self.set_colors(color_scheme)
293
+
294
+ # Set the prompt - the default prompt is '(Pdb)'
295
+ self.prompt = prompt
296
+ self.skip_hidden = True
297
+ self.report_skipped = True
298
+
299
+ # list of predicates we use to skip frames
300
+ self._predicates = self.default_predicates
301
+
302
+ if CHAIN_EXCEPTIONS:
303
+ self._chained_exceptions = tuple()
304
+ self._chained_exception_index = 0
305
+
306
+ #
307
+ def set_colors(self, scheme):
308
+ """Shorthand access to the color table scheme selector method."""
309
+ self.color_scheme_table.set_active_scheme(scheme)
310
+ self.parser.style = scheme
311
+
312
+ def set_trace(self, frame=None):
313
+ if frame is None:
314
+ frame = sys._getframe().f_back
315
+ self.initial_frame = frame
316
+ return super().set_trace(frame)
317
+
318
+ def _hidden_predicate(self, frame):
319
+ """
320
+ Given a frame return whether it it should be hidden or not by IPython.
321
+ """
322
+
323
+ if self._predicates["readonly"]:
324
+ fname = frame.f_code.co_filename
325
+ # we need to check for file existence and interactively define
326
+ # function would otherwise appear as RO.
327
+ if os.path.isfile(fname) and not os.access(fname, os.W_OK):
328
+ return True
329
+
330
+ if self._predicates["tbhide"]:
331
+ if frame in (self.curframe, getattr(self, "initial_frame", None)):
332
+ return False
333
+ frame_locals = self._get_frame_locals(frame)
334
+ if "__tracebackhide__" not in frame_locals:
335
+ return False
336
+ return frame_locals["__tracebackhide__"]
337
+ return False
338
+
339
+ def hidden_frames(self, stack):
340
+ """
341
+ Given an index in the stack return whether it should be skipped.
342
+
343
+ This is used in up/down and where to skip frames.
344
+ """
345
+ # The f_locals dictionary is updated from the actual frame
346
+ # locals whenever the .f_locals accessor is called, so we
347
+ # avoid calling it here to preserve self.curframe_locals.
348
+ # Furthermore, there is no good reason to hide the current frame.
349
+ ip_hide = [self._hidden_predicate(s[0]) for s in stack]
350
+ ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
351
+ if ip_start and self._predicates["ipython_internal"]:
352
+ ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
353
+ return ip_hide
354
+
355
+ if CHAIN_EXCEPTIONS:
356
+
357
+ def _get_tb_and_exceptions(self, tb_or_exc):
358
+ """
359
+ Given a tracecack or an exception, return a tuple of chained exceptions
360
+ and current traceback to inspect.
361
+ This will deal with selecting the right ``__cause__`` or ``__context__``
362
+ as well as handling cycles, and return a flattened list of exceptions we
363
+ can jump to with do_exceptions.
364
+ """
365
+ _exceptions = []
366
+ if isinstance(tb_or_exc, BaseException):
367
+ traceback, current = tb_or_exc.__traceback__, tb_or_exc
368
+
369
+ while current is not None:
370
+ if current in _exceptions:
371
+ break
372
+ _exceptions.append(current)
373
+ if current.__cause__ is not None:
374
+ current = current.__cause__
375
+ elif (
376
+ current.__context__ is not None
377
+ and not current.__suppress_context__
378
+ ):
379
+ current = current.__context__
380
+
381
+ if len(_exceptions) >= self.MAX_CHAINED_EXCEPTION_DEPTH:
382
+ self.message(
383
+ f"More than {self.MAX_CHAINED_EXCEPTION_DEPTH}"
384
+ " chained exceptions found, not all exceptions"
385
+ "will be browsable with `exceptions`."
386
+ )
387
+ break
388
+ else:
389
+ traceback = tb_or_exc
390
+ return tuple(reversed(_exceptions)), traceback
391
+
392
+ @contextmanager
393
+ def _hold_exceptions(self, exceptions):
394
+ """
395
+ Context manager to ensure proper cleaning of exceptions references
396
+ When given a chained exception instead of a traceback,
397
+ pdb may hold references to many objects which may leak memory.
398
+ We use this context manager to make sure everything is properly cleaned
399
+ """
400
+ try:
401
+ self._chained_exceptions = exceptions
402
+ self._chained_exception_index = len(exceptions) - 1
403
+ yield
404
+ finally:
405
+ # we can't put those in forget as otherwise they would
406
+ # be cleared on exception change
407
+ self._chained_exceptions = tuple()
408
+ self._chained_exception_index = 0
409
+
410
+ def do_exceptions(self, arg):
411
+ """exceptions [number]
412
+ List or change current exception in an exception chain.
413
+ Without arguments, list all the current exception in the exception
414
+ chain. Exceptions will be numbered, with the current exception indicated
415
+ with an arrow.
416
+ If given an integer as argument, switch to the exception at that index.
417
+ """
418
+ if not self._chained_exceptions:
419
+ self.message(
420
+ "Did not find chained exceptions. To move between"
421
+ " exceptions, pdb/post_mortem must be given an exception"
422
+ " object rather than a traceback."
423
+ )
424
+ return
425
+ if not arg:
426
+ for ix, exc in enumerate(self._chained_exceptions):
427
+ prompt = ">" if ix == self._chained_exception_index else " "
428
+ rep = repr(exc)
429
+ if len(rep) > 80:
430
+ rep = rep[:77] + "..."
431
+ indicator = (
432
+ " -"
433
+ if self._chained_exceptions[ix].__traceback__ is None
434
+ else f"{ix:>3}"
435
+ )
436
+ self.message(f"{prompt} {indicator} {rep}")
437
+ else:
438
+ try:
439
+ number = int(arg)
440
+ except ValueError:
441
+ self.error("Argument must be an integer")
442
+ return
443
+ if 0 <= number < len(self._chained_exceptions):
444
+ if self._chained_exceptions[number].__traceback__ is None:
445
+ self.error(
446
+ "This exception does not have a traceback, cannot jump to it"
447
+ )
448
+ return
449
+
450
+ self._chained_exception_index = number
451
+ self.setup(None, self._chained_exceptions[number].__traceback__)
452
+ self.print_stack_entry(self.stack[self.curindex])
453
+ else:
454
+ self.error("No exception with that number")
455
+
456
+ def interaction(self, frame, tb_or_exc):
457
+ try:
458
+ if CHAIN_EXCEPTIONS:
459
+ # this context manager is part of interaction in 3.13
460
+ _chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc)
461
+ if isinstance(tb_or_exc, BaseException):
462
+ assert tb is not None, "main exception must have a traceback"
463
+ with self._hold_exceptions(_chained_exceptions):
464
+ OldPdb.interaction(self, frame, tb)
465
+ else:
466
+ OldPdb.interaction(self, frame, tb_or_exc)
467
+
468
+ except KeyboardInterrupt:
469
+ self.stdout.write("\n" + self.shell.get_exception_only())
470
+
471
+ def precmd(self, line):
472
+ """Perform useful escapes on the command before it is executed."""
473
+
474
+ if line.endswith("??"):
475
+ line = "pinfo2 " + line[:-2]
476
+ elif line.endswith("?"):
477
+ line = "pinfo " + line[:-1]
478
+
479
+ line = super().precmd(line)
480
+
481
+ return line
482
+
483
+ def new_do_quit(self, arg):
484
+ return OldPdb.do_quit(self, arg)
485
+
486
+ do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
487
+
488
+ def print_stack_trace(self, context=None):
489
+ Colors = self.color_scheme_table.active_colors
490
+ ColorsNormal = Colors.Normal
491
+ if context is None:
492
+ context = self.context
493
+ try:
494
+ context = int(context)
495
+ if context <= 0:
496
+ raise ValueError("Context must be a positive integer")
497
+ except (TypeError, ValueError) as e:
498
+ raise ValueError("Context must be a positive integer") from e
499
+ try:
500
+ skipped = 0
501
+ for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
502
+ if hidden and self.skip_hidden:
503
+ skipped += 1
504
+ continue
505
+ if skipped:
506
+ print(
507
+ f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
508
+ )
509
+ skipped = 0
510
+ self.print_stack_entry(frame_lineno, context=context)
511
+ if skipped:
512
+ print(
513
+ f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
514
+ )
515
+ except KeyboardInterrupt:
516
+ pass
517
+
518
+ def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
519
+ context=None):
520
+ if context is None:
521
+ context = self.context
522
+ try:
523
+ context = int(context)
524
+ if context <= 0:
525
+ raise ValueError("Context must be a positive integer")
526
+ except (TypeError, ValueError) as e:
527
+ raise ValueError("Context must be a positive integer") from e
528
+ print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
529
+
530
+ # vds: >>
531
+ frame, lineno = frame_lineno
532
+ filename = frame.f_code.co_filename
533
+ self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
534
+ # vds: <<
535
+
536
+ def _get_frame_locals(self, frame):
537
+ """ "
538
+ Accessing f_local of current frame reset the namespace, so we want to avoid
539
+ that or the following can happen
540
+
541
+ ipdb> foo
542
+ "old"
543
+ ipdb> foo = "new"
544
+ ipdb> foo
545
+ "new"
546
+ ipdb> where
547
+ ipdb> foo
548
+ "old"
549
+
550
+ So if frame is self.current_frame we instead return self.curframe_locals
551
+
552
+ """
553
+ if frame is getattr(self, "curframe", None):
554
+ return self.curframe_locals
555
+ else:
556
+ return frame.f_locals
557
+
558
+ def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
559
+ if context is None:
560
+ context = self.context
561
+ try:
562
+ context = int(context)
563
+ if context <= 0:
564
+ print("Context must be a positive integer", file=self.stdout)
565
+ except (TypeError, ValueError):
566
+ print("Context must be a positive integer", file=self.stdout)
567
+
568
+ import reprlib
569
+
570
+ ret = []
571
+
572
+ Colors = self.color_scheme_table.active_colors
573
+ ColorsNormal = Colors.Normal
574
+ tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
575
+ tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
576
+ tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
577
+ tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
578
+
579
+ frame, lineno = frame_lineno
580
+
581
+ return_value = ''
582
+ loc_frame = self._get_frame_locals(frame)
583
+ if "__return__" in loc_frame:
584
+ rv = loc_frame["__return__"]
585
+ # return_value += '->'
586
+ return_value += reprlib.repr(rv) + "\n"
587
+ ret.append(return_value)
588
+
589
+ #s = filename + '(' + `lineno` + ')'
590
+ filename = self.canonic(frame.f_code.co_filename)
591
+ link = tpl_link % py3compat.cast_unicode(filename)
592
+
593
+ if frame.f_code.co_name:
594
+ func = frame.f_code.co_name
595
+ else:
596
+ func = "<lambda>"
597
+
598
+ call = ""
599
+ if func != "?":
600
+ if "__args__" in loc_frame:
601
+ args = reprlib.repr(loc_frame["__args__"])
602
+ else:
603
+ args = '()'
604
+ call = tpl_call % (func, args)
605
+
606
+ # The level info should be generated in the same format pdb uses, to
607
+ # avoid breaking the pdbtrack functionality of python-mode in *emacs.
608
+ if frame is self.curframe:
609
+ ret.append('> ')
610
+ else:
611
+ ret.append(" ")
612
+ ret.append("%s(%s)%s\n" % (link, lineno, call))
613
+
614
+ start = lineno - 1 - context//2
615
+ lines = linecache.getlines(filename)
616
+ start = min(start, len(lines) - context)
617
+ start = max(start, 0)
618
+ lines = lines[start : start + context]
619
+
620
+ for i, line in enumerate(lines):
621
+ show_arrow = start + 1 + i == lineno
622
+ linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
623
+ ret.append(
624
+ self.__format_line(
625
+ linetpl, filename, start + 1 + i, line, arrow=show_arrow
626
+ )
627
+ )
628
+ return "".join(ret)
629
+
630
+ def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
631
+ bp_mark = ""
632
+ bp_mark_color = ""
633
+
634
+ new_line, err = self.parser.format2(line, 'str')
635
+ if not err:
636
+ line = new_line
637
+
638
+ bp = None
639
+ if lineno in self.get_file_breaks(filename):
640
+ bps = self.get_breaks(filename, lineno)
641
+ bp = bps[-1]
642
+
643
+ if bp:
644
+ Colors = self.color_scheme_table.active_colors
645
+ bp_mark = str(bp.number)
646
+ bp_mark_color = Colors.breakpoint_enabled
647
+ if not bp.enabled:
648
+ bp_mark_color = Colors.breakpoint_disabled
649
+
650
+ numbers_width = 7
651
+ if arrow:
652
+ # This is the line with the error
653
+ pad = numbers_width - len(str(lineno)) - len(bp_mark)
654
+ num = '%s%s' % (make_arrow(pad), str(lineno))
655
+ else:
656
+ num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
657
+
658
+ return tpl_line % (bp_mark_color + bp_mark, num, line)
659
+
660
+ def print_list_lines(self, filename, first, last):
661
+ """The printing (as opposed to the parsing part of a 'list'
662
+ command."""
663
+ try:
664
+ Colors = self.color_scheme_table.active_colors
665
+ ColorsNormal = Colors.Normal
666
+ tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
667
+ tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
668
+ src = []
669
+ if filename == "<string>" and hasattr(self, "_exec_filename"):
670
+ filename = self._exec_filename
671
+
672
+ for lineno in range(first, last+1):
673
+ line = linecache.getline(filename, lineno)
674
+ if not line:
675
+ break
676
+
677
+ if lineno == self.curframe.f_lineno:
678
+ line = self.__format_line(
679
+ tpl_line_em, filename, lineno, line, arrow=True
680
+ )
681
+ else:
682
+ line = self.__format_line(
683
+ tpl_line, filename, lineno, line, arrow=False
684
+ )
685
+
686
+ src.append(line)
687
+ self.lineno = lineno
688
+
689
+ print(''.join(src), file=self.stdout)
690
+
691
+ except KeyboardInterrupt:
692
+ pass
693
+
694
+ def do_skip_predicates(self, args):
695
+ """
696
+ Turn on/off individual predicates as to whether a frame should be hidden/skip.
697
+
698
+ The global option to skip (or not) hidden frames is set with skip_hidden
699
+
700
+ To change the value of a predicate
701
+
702
+ skip_predicates key [true|false]
703
+
704
+ Call without arguments to see the current values.
705
+
706
+ To permanently change the value of an option add the corresponding
707
+ command to your ``~/.pdbrc`` file. If you are programmatically using the
708
+ Pdb instance you can also change the ``default_predicates`` class
709
+ attribute.
710
+ """
711
+ if not args.strip():
712
+ print("current predicates:")
713
+ for p, v in self._predicates.items():
714
+ print(" ", p, ":", v)
715
+ return
716
+ type_value = args.strip().split(" ")
717
+ if len(type_value) != 2:
718
+ print(
719
+ f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}"
720
+ )
721
+ return
722
+
723
+ type_, value = type_value
724
+ if type_ not in self._predicates:
725
+ print(f"{type_!r} not in {set(self._predicates.keys())}")
726
+ return
727
+ if value.lower() not in ("true", "yes", "1", "no", "false", "0"):
728
+ print(
729
+ f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')"
730
+ )
731
+ return
732
+
733
+ self._predicates[type_] = value.lower() in ("true", "yes", "1")
734
+ if not any(self._predicates.values()):
735
+ print(
736
+ "Warning, all predicates set to False, skip_hidden may not have any effects."
737
+ )
738
+
739
+ def do_skip_hidden(self, arg):
740
+ """
741
+ Change whether or not we should skip frames with the
742
+ __tracebackhide__ attribute.
743
+ """
744
+ if not arg.strip():
745
+ print(
746
+ f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change."
747
+ )
748
+ elif arg.strip().lower() in ("true", "yes"):
749
+ self.skip_hidden = True
750
+ elif arg.strip().lower() in ("false", "no"):
751
+ self.skip_hidden = False
752
+ if not any(self._predicates.values()):
753
+ print(
754
+ "Warning, all predicates set to False, skip_hidden may not have any effects."
755
+ )
756
+
757
+ def do_list(self, arg):
758
+ """Print lines of code from the current stack frame
759
+ """
760
+ self.lastcmd = 'list'
761
+ last = None
762
+ if arg and arg != ".":
763
+ try:
764
+ x = eval(arg, {}, {})
765
+ if type(x) == type(()):
766
+ first, last = x
767
+ first = int(first)
768
+ last = int(last)
769
+ if last < first:
770
+ # Assume it's a count
771
+ last = first + last
772
+ else:
773
+ first = max(1, int(x) - 5)
774
+ except:
775
+ print('*** Error in argument:', repr(arg), file=self.stdout)
776
+ return
777
+ elif self.lineno is None or arg == ".":
778
+ first = max(1, self.curframe.f_lineno - 5)
779
+ else:
780
+ first = self.lineno + 1
781
+ if last is None:
782
+ last = first + 10
783
+ self.print_list_lines(self.curframe.f_code.co_filename, first, last)
784
+
785
+ # vds: >>
786
+ lineno = first
787
+ filename = self.curframe.f_code.co_filename
788
+ self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
789
+ # vds: <<
790
+
791
+ do_l = do_list
792
+
793
+ def getsourcelines(self, obj):
794
+ lines, lineno = inspect.findsource(obj)
795
+ if inspect.isframe(obj) and obj.f_globals is self._get_frame_locals(obj):
796
+ # must be a module frame: do not try to cut a block out of it
797
+ return lines, 1
798
+ elif inspect.ismodule(obj):
799
+ return lines, 1
800
+ return inspect.getblock(lines[lineno:]), lineno+1
801
+
802
+ def do_longlist(self, arg):
803
+ """Print lines of code from the current stack frame.
804
+
805
+ Shows more lines than 'list' does.
806
+ """
807
+ self.lastcmd = 'longlist'
808
+ try:
809
+ lines, lineno = self.getsourcelines(self.curframe)
810
+ except OSError as err:
811
+ self.error(err)
812
+ return
813
+ last = lineno + len(lines)
814
+ self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
815
+ do_ll = do_longlist
816
+
817
+ def do_debug(self, arg):
818
+ """debug code
819
+ Enter a recursive debugger that steps through the code
820
+ argument (which is an arbitrary expression or statement to be
821
+ executed in the current environment).
822
+ """
823
+ trace_function = sys.gettrace()
824
+ sys.settrace(None)
825
+ globals = self.curframe.f_globals
826
+ locals = self.curframe_locals
827
+ p = self.__class__(completekey=self.completekey,
828
+ stdin=self.stdin, stdout=self.stdout)
829
+ p.use_rawinput = self.use_rawinput
830
+ p.prompt = "(%s) " % self.prompt.strip()
831
+ self.message("ENTERING RECURSIVE DEBUGGER")
832
+ sys.call_tracing(p.run, (arg, globals, locals))
833
+ self.message("LEAVING RECURSIVE DEBUGGER")
834
+ sys.settrace(trace_function)
835
+ self.lastcmd = p.lastcmd
836
+
837
+ def do_pdef(self, arg):
838
+ """Print the call signature for any callable object.
839
+
840
+ The debugger interface to %pdef"""
841
+ namespaces = [
842
+ ("Locals", self.curframe_locals),
843
+ ("Globals", self.curframe.f_globals),
844
+ ]
845
+ self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
846
+
847
+ def do_pdoc(self, arg):
848
+ """Print the docstring for an object.
849
+
850
+ The debugger interface to %pdoc."""
851
+ namespaces = [
852
+ ("Locals", self.curframe_locals),
853
+ ("Globals", self.curframe.f_globals),
854
+ ]
855
+ self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
856
+
857
+ def do_pfile(self, arg):
858
+ """Print (or run through pager) the file where an object is defined.
859
+
860
+ The debugger interface to %pfile.
861
+ """
862
+ namespaces = [
863
+ ("Locals", self.curframe_locals),
864
+ ("Globals", self.curframe.f_globals),
865
+ ]
866
+ self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
867
+
868
+ def do_pinfo(self, arg):
869
+ """Provide detailed information about an object.
870
+
871
+ The debugger interface to %pinfo, i.e., obj?."""
872
+ namespaces = [
873
+ ("Locals", self.curframe_locals),
874
+ ("Globals", self.curframe.f_globals),
875
+ ]
876
+ self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
877
+
878
+ def do_pinfo2(self, arg):
879
+ """Provide extra detailed information about an object.
880
+
881
+ The debugger interface to %pinfo2, i.e., obj??."""
882
+ namespaces = [
883
+ ("Locals", self.curframe_locals),
884
+ ("Globals", self.curframe.f_globals),
885
+ ]
886
+ self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
887
+
888
+ def do_psource(self, arg):
889
+ """Print (or run through pager) the source code for an object."""
890
+ namespaces = [
891
+ ("Locals", self.curframe_locals),
892
+ ("Globals", self.curframe.f_globals),
893
+ ]
894
+ self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
895
+
896
+ def do_where(self, arg):
897
+ """w(here)
898
+ Print a stack trace, with the most recent frame at the bottom.
899
+ An arrow indicates the "current frame", which determines the
900
+ context of most commands. 'bt' is an alias for this command.
901
+
902
+ Take a number as argument as an (optional) number of context line to
903
+ print"""
904
+ if arg:
905
+ try:
906
+ context = int(arg)
907
+ except ValueError as err:
908
+ self.error(err)
909
+ return
910
+ self.print_stack_trace(context)
911
+ else:
912
+ self.print_stack_trace()
913
+
914
+ do_w = do_where
915
+
916
+ def break_anywhere(self, frame):
917
+ """
918
+ _stop_in_decorator_internals is overly restrictive, as we may still want
919
+ to trace function calls, so we need to also update break_anywhere so
920
+ that is we don't `stop_here`, because of debugger skip, we may still
921
+ stop at any point inside the function
922
+
923
+ """
924
+
925
+ sup = super().break_anywhere(frame)
926
+ if sup:
927
+ return sup
928
+ if self._predicates["debuggerskip"]:
929
+ if DEBUGGERSKIP in frame.f_code.co_varnames:
930
+ return True
931
+ if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
932
+ return True
933
+ return False
934
+
935
+ def _is_in_decorator_internal_and_should_skip(self, frame):
936
+ """
937
+ Utility to tell us whether we are in a decorator internal and should stop.
938
+
939
+ """
940
+ # if we are disabled don't skip
941
+ if not self._predicates["debuggerskip"]:
942
+ return False
943
+
944
+ return self._cachable_skip(frame)
945
+
946
+ @lru_cache(1024)
947
+ def _cached_one_parent_frame_debuggerskip(self, frame):
948
+ """
949
+ Cache looking up for DEBUGGERSKIP on parent frame.
950
+
951
+ This should speedup walking through deep frame when one of the highest
952
+ one does have a debugger skip.
953
+
954
+ This is likely to introduce fake positive though.
955
+ """
956
+ while getattr(frame, "f_back", None):
957
+ frame = frame.f_back
958
+ if self._get_frame_locals(frame).get(DEBUGGERSKIP):
959
+ return True
960
+ return None
961
+
962
+ @lru_cache(1024)
963
+ def _cachable_skip(self, frame):
964
+ # if frame is tagged, skip by default.
965
+ if DEBUGGERSKIP in frame.f_code.co_varnames:
966
+ return True
967
+
968
+ # if one of the parent frame value set to True skip as well.
969
+ if self._cached_one_parent_frame_debuggerskip(frame):
970
+ return True
971
+
972
+ return False
973
+
974
+ def stop_here(self, frame):
975
+ if self._is_in_decorator_internal_and_should_skip(frame) is True:
976
+ return False
977
+
978
+ hidden = False
979
+ if self.skip_hidden:
980
+ hidden = self._hidden_predicate(frame)
981
+ if hidden:
982
+ if self.report_skipped:
983
+ Colors = self.color_scheme_table.active_colors
984
+ ColorsNormal = Colors.Normal
985
+ print(
986
+ f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n"
987
+ )
988
+ return super().stop_here(frame)
989
+
990
+ def do_up(self, arg):
991
+ """u(p) [count]
992
+ Move the current frame count (default one) levels up in the
993
+ stack trace (to an older frame).
994
+
995
+ Will skip hidden frames.
996
+ """
997
+ # modified version of upstream that skips
998
+ # frames with __tracebackhide__
999
+ if self.curindex == 0:
1000
+ self.error("Oldest frame")
1001
+ return
1002
+ try:
1003
+ count = int(arg or 1)
1004
+ except ValueError:
1005
+ self.error("Invalid frame count (%s)" % arg)
1006
+ return
1007
+ skipped = 0
1008
+ if count < 0:
1009
+ _newframe = 0
1010
+ else:
1011
+ counter = 0
1012
+ hidden_frames = self.hidden_frames(self.stack)
1013
+ for i in range(self.curindex - 1, -1, -1):
1014
+ if hidden_frames[i] and self.skip_hidden:
1015
+ skipped += 1
1016
+ continue
1017
+ counter += 1
1018
+ if counter >= count:
1019
+ break
1020
+ else:
1021
+ # if no break occurred.
1022
+ self.error(
1023
+ "all frames above hidden, use `skip_hidden False` to get get into those."
1024
+ )
1025
+ return
1026
+
1027
+ Colors = self.color_scheme_table.active_colors
1028
+ ColorsNormal = Colors.Normal
1029
+ _newframe = i
1030
+ self._select_frame(_newframe)
1031
+ if skipped:
1032
+ print(
1033
+ f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
1034
+ )
1035
+
1036
+ def do_down(self, arg):
1037
+ """d(own) [count]
1038
+ Move the current frame count (default one) levels down in the
1039
+ stack trace (to a newer frame).
1040
+
1041
+ Will skip hidden frames.
1042
+ """
1043
+ if self.curindex + 1 == len(self.stack):
1044
+ self.error("Newest frame")
1045
+ return
1046
+ try:
1047
+ count = int(arg or 1)
1048
+ except ValueError:
1049
+ self.error("Invalid frame count (%s)" % arg)
1050
+ return
1051
+ if count < 0:
1052
+ _newframe = len(self.stack) - 1
1053
+ else:
1054
+ counter = 0
1055
+ skipped = 0
1056
+ hidden_frames = self.hidden_frames(self.stack)
1057
+ for i in range(self.curindex + 1, len(self.stack)):
1058
+ if hidden_frames[i] and self.skip_hidden:
1059
+ skipped += 1
1060
+ continue
1061
+ counter += 1
1062
+ if counter >= count:
1063
+ break
1064
+ else:
1065
+ self.error(
1066
+ "all frames below hidden, use `skip_hidden False` to get get into those."
1067
+ )
1068
+ return
1069
+
1070
+ Colors = self.color_scheme_table.active_colors
1071
+ ColorsNormal = Colors.Normal
1072
+ if skipped:
1073
+ print(
1074
+ f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
1075
+ )
1076
+ _newframe = i
1077
+
1078
+ self._select_frame(_newframe)
1079
+
1080
+ do_d = do_down
1081
+ do_u = do_up
1082
+
1083
+ def do_context(self, context):
1084
+ """context number_of_lines
1085
+ Set the number of lines of source code to show when displaying
1086
+ stacktrace information.
1087
+ """
1088
+ try:
1089
+ new_context = int(context)
1090
+ if new_context <= 0:
1091
+ raise ValueError()
1092
+ self.context = new_context
1093
+ except ValueError:
1094
+ self.error(
1095
+ f"The 'context' command requires a positive integer argument (current value {self.context})."
1096
+ )
1097
+
1098
+
1099
+ class InterruptiblePdb(Pdb):
1100
+ """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
1101
+
1102
+ def cmdloop(self, intro=None):
1103
+ """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
1104
+ try:
1105
+ return OldPdb.cmdloop(self, intro=intro)
1106
+ except KeyboardInterrupt:
1107
+ self.stop_here = lambda frame: False
1108
+ self.do_quit("")
1109
+ sys.settrace(None)
1110
+ self.quitting = False
1111
+ raise
1112
+
1113
+ def _cmdloop(self):
1114
+ while True:
1115
+ try:
1116
+ # keyboard interrupts allow for an easy way to cancel
1117
+ # the current command, so allow them during interactive input
1118
+ self.allow_kbdint = True
1119
+ self.cmdloop()
1120
+ self.allow_kbdint = False
1121
+ break
1122
+ except KeyboardInterrupt:
1123
+ self.message('--KeyboardInterrupt--')
1124
+ raise
1125
+
1126
+
1127
+ def set_trace(frame=None, header=None):
1128
+ """
1129
+ Start debugging from `frame`.
1130
+
1131
+ If frame is not specified, debugging starts from caller's frame.
1132
+ """
1133
+ pdb = Pdb()
1134
+ if header is not None:
1135
+ pdb.message(header)
1136
+ pdb.set_trace(frame or sys._getframe().f_back)
openalex_env_map/lib/python3.10/site-packages/IPython/core/display.py ADDED
@@ -0,0 +1,1373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """Top-level display functions for displaying object in different formats."""
3
+
4
+ # Copyright (c) IPython Development Team.
5
+ # Distributed under the terms of the Modified BSD License.
6
+
7
+
8
+ from binascii import b2a_base64, hexlify
9
+ import html
10
+ import json
11
+ import mimetypes
12
+ import os
13
+ import struct
14
+ import warnings
15
+ from copy import deepcopy
16
+ from os.path import splitext
17
+ from pathlib import Path, PurePath
18
+
19
+ from typing import Optional
20
+
21
+ from IPython.testing.skipdoctest import skip_doctest
22
+ from . import display_functions
23
+
24
+
25
+ __all__ = [
26
+ "display_pretty",
27
+ "display_html",
28
+ "display_markdown",
29
+ "display_svg",
30
+ "display_png",
31
+ "display_jpeg",
32
+ "display_webp",
33
+ "display_latex",
34
+ "display_json",
35
+ "display_javascript",
36
+ "display_pdf",
37
+ "DisplayObject",
38
+ "TextDisplayObject",
39
+ "Pretty",
40
+ "HTML",
41
+ "Markdown",
42
+ "Math",
43
+ "Latex",
44
+ "SVG",
45
+ "ProgressBar",
46
+ "JSON",
47
+ "GeoJSON",
48
+ "Javascript",
49
+ "Image",
50
+ "set_matplotlib_formats",
51
+ "set_matplotlib_close",
52
+ "Video",
53
+ ]
54
+
55
+ _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
56
+
57
+ __all__ = __all__ + _deprecated_names
58
+
59
+
60
+ # ----- warn to import from IPython.display -----
61
+
62
+ from warnings import warn
63
+
64
+
65
+ def __getattr__(name):
66
+ if name in _deprecated_names:
67
+ warn(
68
+ f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython.display",
69
+ DeprecationWarning,
70
+ stacklevel=2,
71
+ )
72
+ return getattr(display_functions, name)
73
+
74
+ if name in globals().keys():
75
+ return globals()[name]
76
+ else:
77
+ raise AttributeError(f"module {__name__} has no attribute {name}")
78
+
79
+
80
+ #-----------------------------------------------------------------------------
81
+ # utility functions
82
+ #-----------------------------------------------------------------------------
83
+
84
+ def _safe_exists(path):
85
+ """Check path, but don't let exceptions raise"""
86
+ try:
87
+ return os.path.exists(path)
88
+ except Exception:
89
+ return False
90
+
91
+
92
+ def _display_mimetype(mimetype, objs, raw=False, metadata=None):
93
+ """internal implementation of all display_foo methods
94
+
95
+ Parameters
96
+ ----------
97
+ mimetype : str
98
+ The mimetype to be published (e.g. 'image/png')
99
+ *objs : object
100
+ The Python objects to display, or if raw=True raw text data to
101
+ display.
102
+ raw : bool
103
+ Are the data objects raw data or Python objects that need to be
104
+ formatted before display? [default: False]
105
+ metadata : dict (optional)
106
+ Metadata to be associated with the specific mimetype output.
107
+ """
108
+ if metadata:
109
+ metadata = {mimetype: metadata}
110
+ if raw:
111
+ # turn list of pngdata into list of { 'image/png': pngdata }
112
+ objs = [ {mimetype: obj} for obj in objs ]
113
+ display_functions.display(*objs, raw=raw, metadata=metadata, include=[mimetype])
114
+
115
+ #-----------------------------------------------------------------------------
116
+ # Main functions
117
+ #-----------------------------------------------------------------------------
118
+
119
+
120
+ def display_pretty(*objs, **kwargs):
121
+ """Display the pretty (default) representation of an object.
122
+
123
+ Parameters
124
+ ----------
125
+ *objs : object
126
+ The Python objects to display, or if raw=True raw text data to
127
+ display.
128
+ raw : bool
129
+ Are the data objects raw data or Python objects that need to be
130
+ formatted before display? [default: False]
131
+ metadata : dict (optional)
132
+ Metadata to be associated with the specific mimetype output.
133
+ """
134
+ _display_mimetype('text/plain', objs, **kwargs)
135
+
136
+
137
+ def display_html(*objs, **kwargs):
138
+ """Display the HTML representation of an object.
139
+
140
+ Note: If raw=False and the object does not have a HTML
141
+ representation, no HTML will be shown.
142
+
143
+ Parameters
144
+ ----------
145
+ *objs : object
146
+ The Python objects to display, or if raw=True raw HTML data to
147
+ display.
148
+ raw : bool
149
+ Are the data objects raw data or Python objects that need to be
150
+ formatted before display? [default: False]
151
+ metadata : dict (optional)
152
+ Metadata to be associated with the specific mimetype output.
153
+ """
154
+ _display_mimetype('text/html', objs, **kwargs)
155
+
156
+
157
+ def display_markdown(*objs, **kwargs):
158
+ """Displays the Markdown representation of an object.
159
+
160
+ Parameters
161
+ ----------
162
+ *objs : object
163
+ The Python objects to display, or if raw=True raw markdown data to
164
+ display.
165
+ raw : bool
166
+ Are the data objects raw data or Python objects that need to be
167
+ formatted before display? [default: False]
168
+ metadata : dict (optional)
169
+ Metadata to be associated with the specific mimetype output.
170
+ """
171
+
172
+ _display_mimetype('text/markdown', objs, **kwargs)
173
+
174
+
175
+ def display_svg(*objs, **kwargs):
176
+ """Display the SVG representation of an object.
177
+
178
+ Parameters
179
+ ----------
180
+ *objs : object
181
+ The Python objects to display, or if raw=True raw svg data to
182
+ display.
183
+ raw : bool
184
+ Are the data objects raw data or Python objects that need to be
185
+ formatted before display? [default: False]
186
+ metadata : dict (optional)
187
+ Metadata to be associated with the specific mimetype output.
188
+ """
189
+ _display_mimetype('image/svg+xml', objs, **kwargs)
190
+
191
+
192
+ def display_png(*objs, **kwargs):
193
+ """Display the PNG representation of an object.
194
+
195
+ Parameters
196
+ ----------
197
+ *objs : object
198
+ The Python objects to display, or if raw=True raw png data to
199
+ display.
200
+ raw : bool
201
+ Are the data objects raw data or Python objects that need to be
202
+ formatted before display? [default: False]
203
+ metadata : dict (optional)
204
+ Metadata to be associated with the specific mimetype output.
205
+ """
206
+ _display_mimetype('image/png', objs, **kwargs)
207
+
208
+
209
+ def display_jpeg(*objs, **kwargs):
210
+ """Display the JPEG representation of an object.
211
+
212
+ Parameters
213
+ ----------
214
+ *objs : object
215
+ The Python objects to display, or if raw=True raw JPEG data to
216
+ display.
217
+ raw : bool
218
+ Are the data objects raw data or Python objects that need to be
219
+ formatted before display? [default: False]
220
+ metadata : dict (optional)
221
+ Metadata to be associated with the specific mimetype output.
222
+ """
223
+ _display_mimetype('image/jpeg', objs, **kwargs)
224
+
225
+
226
+ def display_webp(*objs, **kwargs):
227
+ """Display the WEBP representation of an object.
228
+
229
+ Parameters
230
+ ----------
231
+ *objs : object
232
+ The Python objects to display, or if raw=True raw JPEG data to
233
+ display.
234
+ raw : bool
235
+ Are the data objects raw data or Python objects that need to be
236
+ formatted before display? [default: False]
237
+ metadata : dict (optional)
238
+ Metadata to be associated with the specific mimetype output.
239
+ """
240
+ _display_mimetype("image/webp", objs, **kwargs)
241
+
242
+
243
+ def display_latex(*objs, **kwargs):
244
+ """Display the LaTeX representation of an object.
245
+
246
+ Parameters
247
+ ----------
248
+ *objs : object
249
+ The Python objects to display, or if raw=True raw latex data to
250
+ display.
251
+ raw : bool
252
+ Are the data objects raw data or Python objects that need to be
253
+ formatted before display? [default: False]
254
+ metadata : dict (optional)
255
+ Metadata to be associated with the specific mimetype output.
256
+ """
257
+ _display_mimetype('text/latex', objs, **kwargs)
258
+
259
+
260
+ def display_json(*objs, **kwargs):
261
+ """Display the JSON representation of an object.
262
+
263
+ Note that not many frontends support displaying JSON.
264
+
265
+ Parameters
266
+ ----------
267
+ *objs : object
268
+ The Python objects to display, or if raw=True raw json data to
269
+ display.
270
+ raw : bool
271
+ Are the data objects raw data or Python objects that need to be
272
+ formatted before display? [default: False]
273
+ metadata : dict (optional)
274
+ Metadata to be associated with the specific mimetype output.
275
+ """
276
+ _display_mimetype('application/json', objs, **kwargs)
277
+
278
+
279
+ def display_javascript(*objs, **kwargs):
280
+ """Display the Javascript representation of an object.
281
+
282
+ Parameters
283
+ ----------
284
+ *objs : object
285
+ The Python objects to display, or if raw=True raw javascript data to
286
+ display.
287
+ raw : bool
288
+ Are the data objects raw data or Python objects that need to be
289
+ formatted before display? [default: False]
290
+ metadata : dict (optional)
291
+ Metadata to be associated with the specific mimetype output.
292
+ """
293
+ _display_mimetype('application/javascript', objs, **kwargs)
294
+
295
+
296
+ def display_pdf(*objs, **kwargs):
297
+ """Display the PDF representation of an object.
298
+
299
+ Parameters
300
+ ----------
301
+ *objs : object
302
+ The Python objects to display, or if raw=True raw javascript data to
303
+ display.
304
+ raw : bool
305
+ Are the data objects raw data or Python objects that need to be
306
+ formatted before display? [default: False]
307
+ metadata : dict (optional)
308
+ Metadata to be associated with the specific mimetype output.
309
+ """
310
+ _display_mimetype('application/pdf', objs, **kwargs)
311
+
312
+
313
+ #-----------------------------------------------------------------------------
314
+ # Smart classes
315
+ #-----------------------------------------------------------------------------
316
+
317
+
318
+ class DisplayObject(object):
319
+ """An object that wraps data to be displayed."""
320
+
321
+ _read_flags = 'r'
322
+ _show_mem_addr = False
323
+ metadata = None
324
+
325
+ def __init__(self, data=None, url=None, filename=None, metadata=None):
326
+ """Create a display object given raw data.
327
+
328
+ When this object is returned by an expression or passed to the
329
+ display function, it will result in the data being displayed
330
+ in the frontend. The MIME type of the data should match the
331
+ subclasses used, so the Png subclass should be used for 'image/png'
332
+ data. If the data is a URL, the data will first be downloaded
333
+ and then displayed.
334
+
335
+ Parameters
336
+ ----------
337
+ data : unicode, str or bytes
338
+ The raw data or a URL or file to load the data from
339
+ url : unicode
340
+ A URL to download the data from.
341
+ filename : unicode
342
+ Path to a local file to load the data from.
343
+ metadata : dict
344
+ Dict of metadata associated to be the object when displayed
345
+ """
346
+ if isinstance(data, (Path, PurePath)):
347
+ data = str(data)
348
+
349
+ if data is not None and isinstance(data, str):
350
+ if data.startswith('http') and url is None:
351
+ url = data
352
+ filename = None
353
+ data = None
354
+ elif _safe_exists(data) and filename is None:
355
+ url = None
356
+ filename = data
357
+ data = None
358
+
359
+ self.url = url
360
+ self.filename = filename
361
+ # because of @data.setter methods in
362
+ # subclasses ensure url and filename are set
363
+ # before assigning to self.data
364
+ self.data = data
365
+
366
+ if metadata is not None:
367
+ self.metadata = metadata
368
+ elif self.metadata is None:
369
+ self.metadata = {}
370
+
371
+ self.reload()
372
+ self._check_data()
373
+
374
+ def __repr__(self):
375
+ if not self._show_mem_addr:
376
+ cls = self.__class__
377
+ r = "<%s.%s object>" % (cls.__module__, cls.__name__)
378
+ else:
379
+ r = super(DisplayObject, self).__repr__()
380
+ return r
381
+
382
+ def _check_data(self):
383
+ """Override in subclasses if there's something to check."""
384
+ pass
385
+
386
+ def _data_and_metadata(self):
387
+ """shortcut for returning metadata with shape information, if defined"""
388
+ if self.metadata:
389
+ return self.data, deepcopy(self.metadata)
390
+ else:
391
+ return self.data
392
+
393
+ def reload(self):
394
+ """Reload the raw data from file or URL."""
395
+ if self.filename is not None:
396
+ encoding = None if "b" in self._read_flags else "utf-8"
397
+ with open(self.filename, self._read_flags, encoding=encoding) as f:
398
+ self.data = f.read()
399
+ elif self.url is not None:
400
+ # Deferred import
401
+ from urllib.request import urlopen
402
+ response = urlopen(self.url)
403
+ data = response.read()
404
+ # extract encoding from header, if there is one:
405
+ encoding = None
406
+ if 'content-type' in response.headers:
407
+ for sub in response.headers['content-type'].split(';'):
408
+ sub = sub.strip()
409
+ if sub.startswith('charset'):
410
+ encoding = sub.split('=')[-1].strip()
411
+ break
412
+ if 'content-encoding' in response.headers:
413
+ # TODO: do deflate?
414
+ if 'gzip' in response.headers['content-encoding']:
415
+ import gzip
416
+ from io import BytesIO
417
+
418
+ # assume utf-8 if encoding is not specified
419
+ with gzip.open(
420
+ BytesIO(data), "rt", encoding=encoding or "utf-8"
421
+ ) as fp:
422
+ encoding = None
423
+ data = fp.read()
424
+
425
+ # decode data, if an encoding was specified
426
+ # We only touch self.data once since
427
+ # subclasses such as SVG have @data.setter methods
428
+ # that transform self.data into ... well svg.
429
+ if encoding:
430
+ self.data = data.decode(encoding, 'replace')
431
+ else:
432
+ self.data = data
433
+
434
+
435
+ class TextDisplayObject(DisplayObject):
436
+ """Create a text display object given raw data.
437
+
438
+ Parameters
439
+ ----------
440
+ data : str or unicode
441
+ The raw data or a URL or file to load the data from.
442
+ url : unicode
443
+ A URL to download the data from.
444
+ filename : unicode
445
+ Path to a local file to load the data from.
446
+ metadata : dict
447
+ Dict of metadata associated to be the object when displayed
448
+ """
449
+ def _check_data(self):
450
+ if self.data is not None and not isinstance(self.data, str):
451
+ raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
452
+
453
+ class Pretty(TextDisplayObject):
454
+
455
+ def _repr_pretty_(self, pp, cycle):
456
+ return pp.text(self.data)
457
+
458
+
459
+ class HTML(TextDisplayObject):
460
+
461
+ def __init__(self, data=None, url=None, filename=None, metadata=None):
462
+ def warn():
463
+ if not data:
464
+ return False
465
+
466
+ #
467
+ # Avoid calling lower() on the entire data, because it could be a
468
+ # long string and we're only interested in its beginning and end.
469
+ #
470
+ prefix = data[:10].lower()
471
+ suffix = data[-10:].lower()
472
+ return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
473
+
474
+ if warn():
475
+ warnings.warn("Consider using IPython.display.IFrame instead")
476
+ super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
477
+
478
+ def _repr_html_(self):
479
+ return self._data_and_metadata()
480
+
481
+ def __html__(self):
482
+ """
483
+ This method exists to inform other HTML-using modules (e.g. Markupsafe,
484
+ htmltag, etc) that this object is HTML and does not need things like
485
+ special characters (<>&) escaped.
486
+ """
487
+ return self._repr_html_()
488
+
489
+
490
+ class Markdown(TextDisplayObject):
491
+
492
+ def _repr_markdown_(self):
493
+ return self._data_and_metadata()
494
+
495
+
496
+ class Math(TextDisplayObject):
497
+
498
+ def _repr_latex_(self):
499
+ s = r"$\displaystyle %s$" % self.data.strip('$')
500
+ if self.metadata:
501
+ return s, deepcopy(self.metadata)
502
+ else:
503
+ return s
504
+
505
+
506
+ class Latex(TextDisplayObject):
507
+
508
+ def _repr_latex_(self):
509
+ return self._data_and_metadata()
510
+
511
+
512
+ class SVG(DisplayObject):
513
+ """Embed an SVG into the display.
514
+
515
+ Note if you just want to view a svg image via a URL use `:class:Image` with
516
+ a url=URL keyword argument.
517
+ """
518
+
519
+ _read_flags = 'rb'
520
+ # wrap data in a property, which extracts the <svg> tag, discarding
521
+ # document headers
522
+ _data: Optional[str] = None
523
+
524
+ @property
525
+ def data(self):
526
+ return self._data
527
+
528
+ @data.setter
529
+ def data(self, svg):
530
+ if svg is None:
531
+ self._data = None
532
+ return
533
+ # parse into dom object
534
+ from xml.dom import minidom
535
+ x = minidom.parseString(svg)
536
+ # get svg tag (should be 1)
537
+ found_svg = x.getElementsByTagName('svg')
538
+ if found_svg:
539
+ svg = found_svg[0].toxml()
540
+ else:
541
+ # fallback on the input, trust the user
542
+ # but this is probably an error.
543
+ pass
544
+ if isinstance(svg, bytes):
545
+ self._data = svg.decode(errors="replace")
546
+ else:
547
+ self._data = svg
548
+
549
+ def _repr_svg_(self):
550
+ return self._data_and_metadata()
551
+
552
+ class ProgressBar(DisplayObject):
553
+ """Progressbar supports displaying a progressbar like element
554
+ """
555
+ def __init__(self, total):
556
+ """Creates a new progressbar
557
+
558
+ Parameters
559
+ ----------
560
+ total : int
561
+ maximum size of the progressbar
562
+ """
563
+ self.total = total
564
+ self._progress = 0
565
+ self.html_width = '60ex'
566
+ self.text_width = 60
567
+ self._display_id = hexlify(os.urandom(8)).decode('ascii')
568
+
569
+ def __repr__(self):
570
+ fraction = self.progress / self.total
571
+ filled = '=' * int(fraction * self.text_width)
572
+ rest = ' ' * (self.text_width - len(filled))
573
+ return '[{}{}] {}/{}'.format(
574
+ filled, rest,
575
+ self.progress, self.total,
576
+ )
577
+
578
+ def _repr_html_(self):
579
+ return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
580
+ self.html_width, self.total, self.progress)
581
+
582
+ def display(self):
583
+ display_functions.display(self, display_id=self._display_id)
584
+
585
+ def update(self):
586
+ display_functions.display(self, display_id=self._display_id, update=True)
587
+
588
+ @property
589
+ def progress(self):
590
+ return self._progress
591
+
592
+ @progress.setter
593
+ def progress(self, value):
594
+ self._progress = value
595
+ self.update()
596
+
597
+ def __iter__(self):
598
+ self.display()
599
+ self._progress = -1 # First iteration is 0
600
+ return self
601
+
602
+ def __next__(self):
603
+ """Returns current value and increments display by one."""
604
+ self.progress += 1
605
+ if self.progress < self.total:
606
+ return self.progress
607
+ else:
608
+ raise StopIteration()
609
+
610
+ class JSON(DisplayObject):
611
+ """JSON expects a JSON-able dict or list
612
+
613
+ not an already-serialized JSON string.
614
+
615
+ Scalar types (None, number, string) are not allowed, only dict or list containers.
616
+ """
617
+ # wrap data in a property, which warns about passing already-serialized JSON
618
+ _data = None
619
+ def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
620
+ """Create a JSON display object given raw data.
621
+
622
+ Parameters
623
+ ----------
624
+ data : dict or list
625
+ JSON data to display. Not an already-serialized JSON string.
626
+ Scalar types (None, number, string) are not allowed, only dict
627
+ or list containers.
628
+ url : unicode
629
+ A URL to download the data from.
630
+ filename : unicode
631
+ Path to a local file to load the data from.
632
+ expanded : boolean
633
+ Metadata to control whether a JSON display component is expanded.
634
+ metadata : dict
635
+ Specify extra metadata to attach to the json display object.
636
+ root : str
637
+ The name of the root element of the JSON tree
638
+ """
639
+ self.metadata = {
640
+ 'expanded': expanded,
641
+ 'root': root,
642
+ }
643
+ if metadata:
644
+ self.metadata.update(metadata)
645
+ if kwargs:
646
+ self.metadata.update(kwargs)
647
+ super(JSON, self).__init__(data=data, url=url, filename=filename)
648
+
649
+ def _check_data(self):
650
+ if self.data is not None and not isinstance(self.data, (dict, list)):
651
+ raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
652
+
653
+ @property
654
+ def data(self):
655
+ return self._data
656
+
657
+ @data.setter
658
+ def data(self, data):
659
+ if isinstance(data, (Path, PurePath)):
660
+ data = str(data)
661
+
662
+ if isinstance(data, str):
663
+ if self.filename is None and self.url is None:
664
+ warnings.warn("JSON expects JSONable dict or list, not JSON strings")
665
+ data = json.loads(data)
666
+ self._data = data
667
+
668
+ def _data_and_metadata(self):
669
+ return self.data, self.metadata
670
+
671
+ def _repr_json_(self):
672
+ return self._data_and_metadata()
673
+
674
+
675
+ _css_t = """var link = document.createElement("link");
676
+ link.rel = "stylesheet";
677
+ link.type = "text/css";
678
+ link.href = "%s";
679
+ document.head.appendChild(link);
680
+ """
681
+
682
+ _lib_t1 = """new Promise(function(resolve, reject) {
683
+ var script = document.createElement("script");
684
+ script.onload = resolve;
685
+ script.onerror = reject;
686
+ script.src = "%s";
687
+ document.head.appendChild(script);
688
+ }).then(() => {
689
+ """
690
+
691
+ _lib_t2 = """
692
+ });"""
693
+
694
+ class GeoJSON(JSON):
695
+ """GeoJSON expects JSON-able dict
696
+
697
+ not an already-serialized JSON string.
698
+
699
+ Scalar types (None, number, string) are not allowed, only dict containers.
700
+ """
701
+
702
+ def __init__(self, *args, **kwargs):
703
+ """Create a GeoJSON display object given raw data.
704
+
705
+ Parameters
706
+ ----------
707
+ data : dict or list
708
+ VegaLite data. Not an already-serialized JSON string.
709
+ Scalar types (None, number, string) are not allowed, only dict
710
+ or list containers.
711
+ url_template : string
712
+ Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
713
+ layer_options : dict
714
+ Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
715
+ url : unicode
716
+ A URL to download the data from.
717
+ filename : unicode
718
+ Path to a local file to load the data from.
719
+ metadata : dict
720
+ Specify extra metadata to attach to the json display object.
721
+
722
+ Examples
723
+ --------
724
+ The following will display an interactive map of Mars with a point of
725
+ interest on frontend that do support GeoJSON display.
726
+
727
+ >>> from IPython.display import GeoJSON
728
+
729
+ >>> GeoJSON(data={
730
+ ... "type": "Feature",
731
+ ... "geometry": {
732
+ ... "type": "Point",
733
+ ... "coordinates": [-81.327, 296.038]
734
+ ... }
735
+ ... },
736
+ ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
737
+ ... layer_options={
738
+ ... "basemap_id": "celestia_mars-shaded-16k_global",
739
+ ... "attribution" : "Celestia/praesepe",
740
+ ... "minZoom" : 0,
741
+ ... "maxZoom" : 18,
742
+ ... })
743
+ <IPython.core.display.GeoJSON object>
744
+
745
+ In the terminal IPython, you will only see the text representation of
746
+ the GeoJSON object.
747
+
748
+ """
749
+
750
+ super(GeoJSON, self).__init__(*args, **kwargs)
751
+
752
+
753
+ def _ipython_display_(self):
754
+ bundle = {
755
+ 'application/geo+json': self.data,
756
+ 'text/plain': '<IPython.display.GeoJSON object>'
757
+ }
758
+ metadata = {
759
+ 'application/geo+json': self.metadata
760
+ }
761
+ display_functions.display(bundle, metadata=metadata, raw=True)
762
+
763
+ class Javascript(TextDisplayObject):
764
+
765
+ def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
766
+ """Create a Javascript display object given raw data.
767
+
768
+ When this object is returned by an expression or passed to the
769
+ display function, it will result in the data being displayed
770
+ in the frontend. If the data is a URL, the data will first be
771
+ downloaded and then displayed.
772
+
773
+ In the Notebook, the containing element will be available as `element`,
774
+ and jQuery will be available. Content appended to `element` will be
775
+ visible in the output area.
776
+
777
+ Parameters
778
+ ----------
779
+ data : unicode, str or bytes
780
+ The Javascript source code or a URL to download it from.
781
+ url : unicode
782
+ A URL to download the data from.
783
+ filename : unicode
784
+ Path to a local file to load the data from.
785
+ lib : list or str
786
+ A sequence of Javascript library URLs to load asynchronously before
787
+ running the source code. The full URLs of the libraries should
788
+ be given. A single Javascript library URL can also be given as a
789
+ string.
790
+ css : list or str
791
+ A sequence of css files to load before running the source code.
792
+ The full URLs of the css files should be given. A single css URL
793
+ can also be given as a string.
794
+ """
795
+ if isinstance(lib, str):
796
+ lib = [lib]
797
+ elif lib is None:
798
+ lib = []
799
+ if isinstance(css, str):
800
+ css = [css]
801
+ elif css is None:
802
+ css = []
803
+ if not isinstance(lib, (list,tuple)):
804
+ raise TypeError('expected sequence, got: %r' % lib)
805
+ if not isinstance(css, (list,tuple)):
806
+ raise TypeError('expected sequence, got: %r' % css)
807
+ self.lib = lib
808
+ self.css = css
809
+ super(Javascript, self).__init__(data=data, url=url, filename=filename)
810
+
811
+ def _repr_javascript_(self):
812
+ r = ''
813
+ for c in self.css:
814
+ r += _css_t % c
815
+ for l in self.lib:
816
+ r += _lib_t1 % l
817
+ r += self.data
818
+ r += _lib_t2*len(self.lib)
819
+ return r
820
+
821
+
822
+ # constants for identifying png/jpeg/gif/webp data
823
+ _PNG = b"\x89PNG\r\n\x1a\n"
824
+ _JPEG = b"\xff\xd8"
825
+ _GIF1 = b"GIF87a"
826
+ _GIF2 = b"GIF89a"
827
+ _WEBP = b"WEBP"
828
+
829
+
830
+ def _pngxy(data):
831
+ """read the (width, height) from a PNG header"""
832
+ ihdr = data.index(b'IHDR')
833
+ # next 8 bytes are width/height
834
+ return struct.unpack('>ii', data[ihdr+4:ihdr+12])
835
+
836
+
837
+ def _jpegxy(data):
838
+ """read the (width, height) from a JPEG header"""
839
+ # adapted from http://www.64lines.com/jpeg-width-height
840
+
841
+ idx = 4
842
+ while True:
843
+ block_size = struct.unpack('>H', data[idx:idx+2])[0]
844
+ idx = idx + block_size
845
+ if data[idx:idx+2] == b'\xFF\xC0':
846
+ # found Start of Frame
847
+ iSOF = idx
848
+ break
849
+ else:
850
+ # read another block
851
+ idx += 2
852
+
853
+ h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
854
+ return w, h
855
+
856
+
857
+ def _gifxy(data):
858
+ """read the (width, height) from a GIF header"""
859
+ return struct.unpack('<HH', data[6:10])
860
+
861
+
862
+ def _webpxy(data):
863
+ """read the (width, height) from a WEBP header"""
864
+ if data[12:16] == b"VP8 ":
865
+ width, height = struct.unpack("<HH", data[24:30])
866
+ width = width & 0x3FFF
867
+ height = height & 0x3FFF
868
+ return (width, height)
869
+ elif data[12:16] == b"VP8L":
870
+ size_info = struct.unpack("<I", data[21:25])[0]
871
+ width = 1 + ((size_info & 0x3F) << 8) | (size_info >> 24)
872
+ height = 1 + (
873
+ (((size_info >> 8) & 0xF) << 10)
874
+ | (((size_info >> 14) & 0x3FC) << 2)
875
+ | ((size_info >> 22) & 0x3)
876
+ )
877
+ return (width, height)
878
+ else:
879
+ raise ValueError("Not a valid WEBP header")
880
+
881
+
882
+ class Image(DisplayObject):
883
+
884
+ _read_flags = "rb"
885
+ _FMT_JPEG = "jpeg"
886
+ _FMT_PNG = "png"
887
+ _FMT_GIF = "gif"
888
+ _FMT_WEBP = "webp"
889
+ _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF, _FMT_WEBP]
890
+ _MIMETYPES = {
891
+ _FMT_PNG: "image/png",
892
+ _FMT_JPEG: "image/jpeg",
893
+ _FMT_GIF: "image/gif",
894
+ _FMT_WEBP: "image/webp",
895
+ }
896
+
897
+ def __init__(
898
+ self,
899
+ data=None,
900
+ url=None,
901
+ filename=None,
902
+ format=None,
903
+ embed=None,
904
+ width=None,
905
+ height=None,
906
+ retina=False,
907
+ unconfined=False,
908
+ metadata=None,
909
+ alt=None,
910
+ ):
911
+ """Create a PNG/JPEG/GIF/WEBP image object given raw data.
912
+
913
+ When this object is returned by an input cell or passed to the
914
+ display function, it will result in the image being displayed
915
+ in the frontend.
916
+
917
+ Parameters
918
+ ----------
919
+ data : unicode, str or bytes
920
+ The raw image data or a URL or filename to load the data from.
921
+ This always results in embedded image data.
922
+
923
+ url : unicode
924
+ A URL to download the data from. If you specify `url=`,
925
+ the image data will not be embedded unless you also specify `embed=True`.
926
+
927
+ filename : unicode
928
+ Path to a local file to load the data from.
929
+ Images from a file are always embedded.
930
+
931
+ format : unicode
932
+ The format of the image data (png/jpeg/jpg/gif/webp). If a filename or URL is given
933
+ for format will be inferred from the filename extension.
934
+
935
+ embed : bool
936
+ Should the image data be embedded using a data URI (True) or be
937
+ loaded using an <img> tag. Set this to True if you want the image
938
+ to be viewable later with no internet connection in the notebook.
939
+
940
+ Default is `True`, unless the keyword argument `url` is set, then
941
+ default value is `False`.
942
+
943
+ Note that QtConsole is not able to display images if `embed` is set to `False`
944
+
945
+ width : int
946
+ Width in pixels to which to constrain the image in html
947
+
948
+ height : int
949
+ Height in pixels to which to constrain the image in html
950
+
951
+ retina : bool
952
+ Automatically set the width and height to half of the measured
953
+ width and height.
954
+ This only works for embedded images because it reads the width/height
955
+ from image data.
956
+ For non-embedded images, you can just set the desired display width
957
+ and height directly.
958
+
959
+ unconfined : bool
960
+ Set unconfined=True to disable max-width confinement of the image.
961
+
962
+ metadata : dict
963
+ Specify extra metadata to attach to the image.
964
+
965
+ alt : unicode
966
+ Alternative text for the image, for use by screen readers.
967
+
968
+ Examples
969
+ --------
970
+ embedded image data, works in qtconsole and notebook
971
+ when passed positionally, the first arg can be any of raw image data,
972
+ a URL, or a filename from which to load image data.
973
+ The result is always embedding image data for inline images.
974
+
975
+ >>> Image('https://www.google.fr/images/srpr/logo3w.png') # doctest: +SKIP
976
+ <IPython.core.display.Image object>
977
+
978
+ >>> Image('/path/to/image.jpg')
979
+ <IPython.core.display.Image object>
980
+
981
+ >>> Image(b'RAW_PNG_DATA...')
982
+ <IPython.core.display.Image object>
983
+
984
+ Specifying Image(url=...) does not embed the image data,
985
+ it only generates ``<img>`` tag with a link to the source.
986
+ This will not work in the qtconsole or offline.
987
+
988
+ >>> Image(url='https://www.google.fr/images/srpr/logo3w.png')
989
+ <IPython.core.display.Image object>
990
+
991
+ """
992
+ if isinstance(data, (Path, PurePath)):
993
+ data = str(data)
994
+
995
+ if filename is not None:
996
+ ext = self._find_ext(filename)
997
+ elif url is not None:
998
+ ext = self._find_ext(url)
999
+ elif data is None:
1000
+ raise ValueError("No image data found. Expecting filename, url, or data.")
1001
+ elif isinstance(data, str) and (
1002
+ data.startswith('http') or _safe_exists(data)
1003
+ ):
1004
+ ext = self._find_ext(data)
1005
+ else:
1006
+ ext = None
1007
+
1008
+ if format is None:
1009
+ if ext is not None:
1010
+ if ext == u'jpg' or ext == u'jpeg':
1011
+ format = self._FMT_JPEG
1012
+ elif ext == u'png':
1013
+ format = self._FMT_PNG
1014
+ elif ext == u'gif':
1015
+ format = self._FMT_GIF
1016
+ elif ext == "webp":
1017
+ format = self._FMT_WEBP
1018
+ else:
1019
+ format = ext.lower()
1020
+ elif isinstance(data, bytes):
1021
+ # infer image type from image data header,
1022
+ # only if format has not been specified.
1023
+ if data[:2] == _JPEG:
1024
+ format = self._FMT_JPEG
1025
+ elif data[:8] == _PNG:
1026
+ format = self._FMT_PNG
1027
+ elif data[8:12] == _WEBP:
1028
+ format = self._FMT_WEBP
1029
+ elif data[:6] == _GIF1 or data[:6] == _GIF2:
1030
+ format = self._FMT_GIF
1031
+
1032
+ # failed to detect format, default png
1033
+ if format is None:
1034
+ format = self._FMT_PNG
1035
+
1036
+ if format.lower() == 'jpg':
1037
+ # jpg->jpeg
1038
+ format = self._FMT_JPEG
1039
+
1040
+ self.format = format.lower()
1041
+ self.embed = embed if embed is not None else (url is None)
1042
+
1043
+ if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1044
+ raise ValueError("Cannot embed the '%s' image format" % (self.format))
1045
+ if self.embed:
1046
+ self._mimetype = self._MIMETYPES.get(self.format)
1047
+
1048
+ self.width = width
1049
+ self.height = height
1050
+ self.retina = retina
1051
+ self.unconfined = unconfined
1052
+ self.alt = alt
1053
+ super(Image, self).__init__(data=data, url=url, filename=filename,
1054
+ metadata=metadata)
1055
+
1056
+ if self.width is None and self.metadata.get('width', {}):
1057
+ self.width = metadata['width']
1058
+
1059
+ if self.height is None and self.metadata.get('height', {}):
1060
+ self.height = metadata['height']
1061
+
1062
+ if self.alt is None and self.metadata.get("alt", {}):
1063
+ self.alt = metadata["alt"]
1064
+
1065
+ if retina:
1066
+ self._retina_shape()
1067
+
1068
+
1069
+ def _retina_shape(self):
1070
+ """load pixel-doubled width and height from image data"""
1071
+ if not self.embed:
1072
+ return
1073
+ if self.format == self._FMT_PNG:
1074
+ w, h = _pngxy(self.data)
1075
+ elif self.format == self._FMT_JPEG:
1076
+ w, h = _jpegxy(self.data)
1077
+ elif self.format == self._FMT_GIF:
1078
+ w, h = _gifxy(self.data)
1079
+ else:
1080
+ # retina only supports png
1081
+ return
1082
+ self.width = w // 2
1083
+ self.height = h // 2
1084
+
1085
+ def reload(self):
1086
+ """Reload the raw data from file or URL."""
1087
+ if self.embed:
1088
+ super(Image,self).reload()
1089
+ if self.retina:
1090
+ self._retina_shape()
1091
+
1092
+ def _repr_html_(self):
1093
+ if not self.embed:
1094
+ width = height = klass = alt = ""
1095
+ if self.width:
1096
+ width = ' width="%d"' % self.width
1097
+ if self.height:
1098
+ height = ' height="%d"' % self.height
1099
+ if self.unconfined:
1100
+ klass = ' class="unconfined"'
1101
+ if self.alt:
1102
+ alt = ' alt="%s"' % html.escape(self.alt)
1103
+ return '<img src="{url}"{width}{height}{klass}{alt}/>'.format(
1104
+ url=self.url,
1105
+ width=width,
1106
+ height=height,
1107
+ klass=klass,
1108
+ alt=alt,
1109
+ )
1110
+
1111
+ def _repr_mimebundle_(self, include=None, exclude=None):
1112
+ """Return the image as a mimebundle
1113
+
1114
+ Any new mimetype support should be implemented here.
1115
+ """
1116
+ if self.embed:
1117
+ mimetype = self._mimetype
1118
+ data, metadata = self._data_and_metadata(always_both=True)
1119
+ if metadata:
1120
+ metadata = {mimetype: metadata}
1121
+ return {mimetype: data}, metadata
1122
+ else:
1123
+ return {'text/html': self._repr_html_()}
1124
+
1125
+ def _data_and_metadata(self, always_both=False):
1126
+ """shortcut for returning metadata with shape information, if defined"""
1127
+ try:
1128
+ b64_data = b2a_base64(self.data, newline=False).decode("ascii")
1129
+ except TypeError as e:
1130
+ raise FileNotFoundError(
1131
+ "No such file or directory: '%s'" % (self.data)) from e
1132
+ md = {}
1133
+ if self.metadata:
1134
+ md.update(self.metadata)
1135
+ if self.width:
1136
+ md['width'] = self.width
1137
+ if self.height:
1138
+ md['height'] = self.height
1139
+ if self.unconfined:
1140
+ md['unconfined'] = self.unconfined
1141
+ if self.alt:
1142
+ md["alt"] = self.alt
1143
+ if md or always_both:
1144
+ return b64_data, md
1145
+ else:
1146
+ return b64_data
1147
+
1148
+ def _repr_png_(self):
1149
+ if self.embed and self.format == self._FMT_PNG:
1150
+ return self._data_and_metadata()
1151
+
1152
+ def _repr_jpeg_(self):
1153
+ if self.embed and self.format == self._FMT_JPEG:
1154
+ return self._data_and_metadata()
1155
+
1156
+ def _find_ext(self, s):
1157
+ base, ext = splitext(s)
1158
+
1159
+ if not ext:
1160
+ return base
1161
+
1162
+ # `splitext` includes leading period, so we skip it
1163
+ return ext[1:].lower()
1164
+
1165
+
1166
+ class Video(DisplayObject):
1167
+
1168
+ def __init__(self, data=None, url=None, filename=None, embed=False,
1169
+ mimetype=None, width=None, height=None, html_attributes="controls"):
1170
+ """Create a video object given raw data or an URL.
1171
+
1172
+ When this object is returned by an input cell or passed to the
1173
+ display function, it will result in the video being displayed
1174
+ in the frontend.
1175
+
1176
+ Parameters
1177
+ ----------
1178
+ data : unicode, str or bytes
1179
+ The raw video data or a URL or filename to load the data from.
1180
+ Raw data will require passing ``embed=True``.
1181
+
1182
+ url : unicode
1183
+ A URL for the video. If you specify ``url=``,
1184
+ the image data will not be embedded.
1185
+
1186
+ filename : unicode
1187
+ Path to a local file containing the video.
1188
+ Will be interpreted as a local URL unless ``embed=True``.
1189
+
1190
+ embed : bool
1191
+ Should the video be embedded using a data URI (True) or be
1192
+ loaded using a <video> tag (False).
1193
+
1194
+ Since videos are large, embedding them should be avoided, if possible.
1195
+ You must confirm embedding as your intention by passing ``embed=True``.
1196
+
1197
+ Local files can be displayed with URLs without embedding the content, via::
1198
+
1199
+ Video('./video.mp4')
1200
+
1201
+ mimetype : unicode
1202
+ Specify the mimetype for embedded videos.
1203
+ Default will be guessed from file extension, if available.
1204
+
1205
+ width : int
1206
+ Width in pixels to which to constrain the video in HTML.
1207
+ If not supplied, defaults to the width of the video.
1208
+
1209
+ height : int
1210
+ Height in pixels to which to constrain the video in html.
1211
+ If not supplied, defaults to the height of the video.
1212
+
1213
+ html_attributes : str
1214
+ Attributes for the HTML ``<video>`` block.
1215
+ Default: ``"controls"`` to get video controls.
1216
+ Other examples: ``"controls muted"`` for muted video with controls,
1217
+ ``"loop autoplay"`` for looping autoplaying video without controls.
1218
+
1219
+ Examples
1220
+ --------
1221
+ ::
1222
+
1223
+ Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1224
+ Video('path/to/video.mp4')
1225
+ Video('path/to/video.mp4', embed=True)
1226
+ Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1227
+ Video(b'raw-videodata', embed=True)
1228
+ """
1229
+ if isinstance(data, (Path, PurePath)):
1230
+ data = str(data)
1231
+
1232
+ if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1233
+ url = data
1234
+ data = None
1235
+ elif data is not None and os.path.exists(data):
1236
+ filename = data
1237
+ data = None
1238
+
1239
+ if data and not embed:
1240
+ msg = ''.join([
1241
+ "To embed videos, you must pass embed=True ",
1242
+ "(this may make your notebook files huge)\n",
1243
+ "Consider passing Video(url='...')",
1244
+ ])
1245
+ raise ValueError(msg)
1246
+
1247
+ self.mimetype = mimetype
1248
+ self.embed = embed
1249
+ self.width = width
1250
+ self.height = height
1251
+ self.html_attributes = html_attributes
1252
+ super(Video, self).__init__(data=data, url=url, filename=filename)
1253
+
1254
+ def _repr_html_(self):
1255
+ width = height = ''
1256
+ if self.width:
1257
+ width = ' width="%d"' % self.width
1258
+ if self.height:
1259
+ height = ' height="%d"' % self.height
1260
+
1261
+ # External URLs and potentially local files are not embedded into the
1262
+ # notebook output.
1263
+ if not self.embed:
1264
+ url = self.url if self.url is not None else self.filename
1265
+ output = """<video src="{0}" {1} {2} {3}>
1266
+ Your browser does not support the <code>video</code> element.
1267
+ </video>""".format(url, self.html_attributes, width, height)
1268
+ return output
1269
+
1270
+ # Embedded videos are base64-encoded.
1271
+ mimetype = self.mimetype
1272
+ if self.filename is not None:
1273
+ if not mimetype:
1274
+ mimetype, _ = mimetypes.guess_type(self.filename)
1275
+
1276
+ with open(self.filename, 'rb') as f:
1277
+ video = f.read()
1278
+ else:
1279
+ video = self.data
1280
+ if isinstance(video, str):
1281
+ # unicode input is already b64-encoded
1282
+ b64_video = video
1283
+ else:
1284
+ b64_video = b2a_base64(video, newline=False).decode("ascii").rstrip()
1285
+
1286
+ output = """<video {0} {1} {2}>
1287
+ <source src="data:{3};base64,{4}" type="{3}">
1288
+ Your browser does not support the video tag.
1289
+ </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1290
+ return output
1291
+
1292
+ def reload(self):
1293
+ # TODO
1294
+ pass
1295
+
1296
+
1297
+ @skip_doctest
1298
+ def set_matplotlib_formats(*formats, **kwargs):
1299
+ """
1300
+ .. deprecated:: 7.23
1301
+
1302
+ use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
1303
+
1304
+ Select figure formats for the inline backend. Optionally pass quality for JPEG.
1305
+
1306
+ For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1307
+
1308
+ In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1309
+
1310
+ To set this in your config files use the following::
1311
+
1312
+ c.InlineBackend.figure_formats = {'png', 'jpeg'}
1313
+ c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1314
+
1315
+ Parameters
1316
+ ----------
1317
+ *formats : strs
1318
+ One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1319
+ **kwargs
1320
+ Keyword args will be relayed to ``figure.canvas.print_figure``.
1321
+ """
1322
+ warnings.warn(
1323
+ "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
1324
+ "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
1325
+ DeprecationWarning,
1326
+ stacklevel=2,
1327
+ )
1328
+
1329
+ from matplotlib_inline.backend_inline import (
1330
+ set_matplotlib_formats as set_matplotlib_formats_orig,
1331
+ )
1332
+
1333
+ set_matplotlib_formats_orig(*formats, **kwargs)
1334
+
1335
+ @skip_doctest
1336
+ def set_matplotlib_close(close=True):
1337
+ """
1338
+ .. deprecated:: 7.23
1339
+
1340
+ use `matplotlib_inline.backend_inline.set_matplotlib_close()`
1341
+
1342
+ Set whether the inline backend closes all figures automatically or not.
1343
+
1344
+ By default, the inline backend used in the IPython Notebook will close all
1345
+ matplotlib figures automatically after each cell is run. This means that
1346
+ plots in different cells won't interfere. Sometimes, you may want to make
1347
+ a plot in one cell and then refine it in later cells. This can be accomplished
1348
+ by::
1349
+
1350
+ In [1]: set_matplotlib_close(False)
1351
+
1352
+ To set this in your config files use the following::
1353
+
1354
+ c.InlineBackend.close_figures = False
1355
+
1356
+ Parameters
1357
+ ----------
1358
+ close : bool
1359
+ Should all matplotlib figures be automatically closed after each cell is
1360
+ run?
1361
+ """
1362
+ warnings.warn(
1363
+ "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
1364
+ "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
1365
+ DeprecationWarning,
1366
+ stacklevel=2,
1367
+ )
1368
+
1369
+ from matplotlib_inline.backend_inline import (
1370
+ set_matplotlib_close as set_matplotlib_close_orig,
1371
+ )
1372
+
1373
+ set_matplotlib_close_orig(close)
openalex_env_map/lib/python3.10/site-packages/IPython/core/display_functions.py ADDED
@@ -0,0 +1,391 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """Top-level display functions for displaying object in different formats."""
3
+
4
+ # Copyright (c) IPython Development Team.
5
+ # Distributed under the terms of the Modified BSD License.
6
+
7
+
8
+ from binascii import b2a_hex
9
+ import os
10
+ import sys
11
+ import warnings
12
+
13
+ __all__ = ['display', 'clear_output', 'publish_display_data', 'update_display', 'DisplayHandle']
14
+
15
+ #-----------------------------------------------------------------------------
16
+ # utility functions
17
+ #-----------------------------------------------------------------------------
18
+
19
+
20
+ def _merge(d1, d2):
21
+ """Like update, but merges sub-dicts instead of clobbering at the top level.
22
+
23
+ Updates d1 in-place
24
+ """
25
+
26
+ if not isinstance(d2, dict) or not isinstance(d1, dict):
27
+ return d2
28
+ for key, value in d2.items():
29
+ d1[key] = _merge(d1.get(key), value)
30
+ return d1
31
+
32
+
33
+ #-----------------------------------------------------------------------------
34
+ # Main functions
35
+ #-----------------------------------------------------------------------------
36
+
37
+ class _Sentinel:
38
+ def __repr__(self):
39
+ return "<deprecated>"
40
+
41
+
42
+ _sentinel = _Sentinel()
43
+
44
+ # use * to indicate transient is keyword-only
45
+ def publish_display_data(
46
+ data, metadata=None, source=_sentinel, *, transient=None, **kwargs
47
+ ):
48
+ """Publish data and metadata to all frontends.
49
+
50
+ See the ``display_data`` message in the messaging documentation for
51
+ more details about this message type.
52
+
53
+ Keys of data and metadata can be any mime-type.
54
+
55
+ Parameters
56
+ ----------
57
+ data : dict
58
+ A dictionary having keys that are valid MIME types (like
59
+ 'text/plain' or 'image/svg+xml') and values that are the data for
60
+ that MIME type. The data itself must be a JSON'able data
61
+ structure. Minimally all data should have the 'text/plain' data,
62
+ which can be displayed by all frontends. If more than the plain
63
+ text is given, it is up to the frontend to decide which
64
+ representation to use.
65
+ metadata : dict
66
+ A dictionary for metadata related to the data. This can contain
67
+ arbitrary key, value pairs that frontends can use to interpret
68
+ the data. mime-type keys matching those in data can be used
69
+ to specify metadata about particular representations.
70
+ source : str, deprecated
71
+ Unused.
72
+ transient : dict, keyword-only
73
+ A dictionary of transient data, such as display_id.
74
+ """
75
+ from IPython.core.interactiveshell import InteractiveShell
76
+
77
+ if source is not _sentinel:
78
+ warnings.warn(
79
+ "The `source` parameter emit a deprecation warning since"
80
+ " IPython 8.0, it had no effects for a long time and will "
81
+ " be removed in future versions.",
82
+ DeprecationWarning,
83
+ stacklevel=2,
84
+ )
85
+ display_pub = InteractiveShell.instance().display_pub
86
+
87
+ # only pass transient if supplied,
88
+ # to avoid errors with older ipykernel.
89
+ # TODO: We could check for ipykernel version and provide a detailed upgrade message.
90
+ if transient:
91
+ kwargs['transient'] = transient
92
+
93
+ display_pub.publish(
94
+ data=data,
95
+ metadata=metadata,
96
+ **kwargs
97
+ )
98
+
99
+
100
+ def _new_id():
101
+ """Generate a new random text id with urandom"""
102
+ return b2a_hex(os.urandom(16)).decode('ascii')
103
+
104
+
105
+ def display(
106
+ *objs,
107
+ include=None,
108
+ exclude=None,
109
+ metadata=None,
110
+ transient=None,
111
+ display_id=None,
112
+ raw=False,
113
+ clear=False,
114
+ **kwargs,
115
+ ):
116
+ """Display a Python object in all frontends.
117
+
118
+ By default all representations will be computed and sent to the frontends.
119
+ Frontends can decide which representation is used and how.
120
+
121
+ In terminal IPython this will be similar to using :func:`print`, for use in richer
122
+ frontends see Jupyter notebook examples with rich display logic.
123
+
124
+ Parameters
125
+ ----------
126
+ *objs : object
127
+ The Python objects to display.
128
+ raw : bool, optional
129
+ Are the objects to be displayed already mimetype-keyed dicts of raw display data,
130
+ or Python objects that need to be formatted before display? [default: False]
131
+ include : list, tuple or set, optional
132
+ A list of format type strings (MIME types) to include in the
133
+ format data dict. If this is set *only* the format types included
134
+ in this list will be computed.
135
+ exclude : list, tuple or set, optional
136
+ A list of format type strings (MIME types) to exclude in the format
137
+ data dict. If this is set all format types will be computed,
138
+ except for those included in this argument.
139
+ metadata : dict, optional
140
+ A dictionary of metadata to associate with the output.
141
+ mime-type keys in this dictionary will be associated with the individual
142
+ representation formats, if they exist.
143
+ transient : dict, optional
144
+ A dictionary of transient data to associate with the output.
145
+ Data in this dict should not be persisted to files (e.g. notebooks).
146
+ display_id : str, bool optional
147
+ Set an id for the display.
148
+ This id can be used for updating this display area later via update_display.
149
+ If given as `True`, generate a new `display_id`
150
+ clear : bool, optional
151
+ Should the output area be cleared before displaying anything? If True,
152
+ this will wait for additional output before clearing. [default: False]
153
+ **kwargs : additional keyword-args, optional
154
+ Additional keyword-arguments are passed through to the display publisher.
155
+
156
+ Returns
157
+ -------
158
+ handle: DisplayHandle
159
+ Returns a handle on updatable displays for use with :func:`update_display`,
160
+ if `display_id` is given. Returns :any:`None` if no `display_id` is given
161
+ (default).
162
+
163
+ Examples
164
+ --------
165
+ >>> class Json(object):
166
+ ... def __init__(self, json):
167
+ ... self.json = json
168
+ ... def _repr_pretty_(self, pp, cycle):
169
+ ... import json
170
+ ... pp.text(json.dumps(self.json, indent=2))
171
+ ... def __repr__(self):
172
+ ... return str(self.json)
173
+ ...
174
+
175
+ >>> d = Json({1:2, 3: {4:5}})
176
+
177
+ >>> print(d)
178
+ {1: 2, 3: {4: 5}}
179
+
180
+ >>> display(d)
181
+ {
182
+ "1": 2,
183
+ "3": {
184
+ "4": 5
185
+ }
186
+ }
187
+
188
+ >>> def int_formatter(integer, pp, cycle):
189
+ ... pp.text('I'*integer)
190
+
191
+ >>> plain = get_ipython().display_formatter.formatters['text/plain']
192
+ >>> plain.for_type(int, int_formatter)
193
+ <function _repr_pprint at 0x...>
194
+ >>> display(7-5)
195
+ II
196
+
197
+ >>> del plain.type_printers[int]
198
+ >>> display(7-5)
199
+ 2
200
+
201
+ See Also
202
+ --------
203
+ :func:`update_display`
204
+
205
+ Notes
206
+ -----
207
+ In Python, objects can declare their textual representation using the
208
+ `__repr__` method. IPython expands on this idea and allows objects to declare
209
+ other, rich representations including:
210
+
211
+ - HTML
212
+ - JSON
213
+ - PNG
214
+ - JPEG
215
+ - SVG
216
+ - LaTeX
217
+
218
+ A single object can declare some or all of these representations; all are
219
+ handled by IPython's display system.
220
+
221
+ The main idea of the first approach is that you have to implement special
222
+ display methods when you define your class, one for each representation you
223
+ want to use. Here is a list of the names of the special methods and the
224
+ values they must return:
225
+
226
+ - `_repr_html_`: return raw HTML as a string, or a tuple (see below).
227
+ - `_repr_json_`: return a JSONable dict, or a tuple (see below).
228
+ - `_repr_jpeg_`: return raw JPEG data, or a tuple (see below).
229
+ - `_repr_png_`: return raw PNG data, or a tuple (see below).
230
+ - `_repr_svg_`: return raw SVG data as a string, or a tuple (see below).
231
+ - `_repr_latex_`: return LaTeX commands in a string surrounded by "$",
232
+ or a tuple (see below).
233
+ - `_repr_mimebundle_`: return a full mimebundle containing the mapping
234
+ from all mimetypes to data.
235
+ Use this for any mime-type not listed above.
236
+
237
+ The above functions may also return the object's metadata alonside the
238
+ data. If the metadata is available, the functions will return a tuple
239
+ containing the data and metadata, in that order. If there is no metadata
240
+ available, then the functions will return the data only.
241
+
242
+ When you are directly writing your own classes, you can adapt them for
243
+ display in IPython by following the above approach. But in practice, you
244
+ often need to work with existing classes that you can't easily modify.
245
+
246
+ You can refer to the documentation on integrating with the display system in
247
+ order to register custom formatters for already existing types
248
+ (:ref:`integrating_rich_display`).
249
+
250
+ .. versionadded:: 5.4 display available without import
251
+ .. versionadded:: 6.1 display available without import
252
+
253
+ Since IPython 5.4 and 6.1 :func:`display` is automatically made available to
254
+ the user without import. If you are using display in a document that might
255
+ be used in a pure python context or with older version of IPython, use the
256
+ following import at the top of your file::
257
+
258
+ from IPython.display import display
259
+
260
+ """
261
+ from IPython.core.interactiveshell import InteractiveShell
262
+
263
+ if not InteractiveShell.initialized():
264
+ # Directly print objects.
265
+ print(*objs)
266
+ return
267
+
268
+ if transient is None:
269
+ transient = {}
270
+ if metadata is None:
271
+ metadata={}
272
+ if display_id:
273
+ if display_id is True:
274
+ display_id = _new_id()
275
+ transient['display_id'] = display_id
276
+ if kwargs.get('update') and 'display_id' not in transient:
277
+ raise TypeError('display_id required for update_display')
278
+ if transient:
279
+ kwargs['transient'] = transient
280
+
281
+ if not objs and display_id:
282
+ # if given no objects, but still a request for a display_id,
283
+ # we assume the user wants to insert an empty output that
284
+ # can be updated later
285
+ objs = [{}]
286
+ raw = True
287
+
288
+ if not raw:
289
+ format = InteractiveShell.instance().display_formatter.format
290
+
291
+ if clear:
292
+ clear_output(wait=True)
293
+
294
+ for obj in objs:
295
+ if raw:
296
+ publish_display_data(data=obj, metadata=metadata, **kwargs)
297
+ else:
298
+ format_dict, md_dict = format(obj, include=include, exclude=exclude)
299
+ if not format_dict:
300
+ # nothing to display (e.g. _ipython_display_ took over)
301
+ continue
302
+ if metadata:
303
+ # kwarg-specified metadata gets precedence
304
+ _merge(md_dict, metadata)
305
+ publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
306
+ if display_id:
307
+ return DisplayHandle(display_id)
308
+
309
+
310
+ # use * for keyword-only display_id arg
311
+ def update_display(obj, *, display_id, **kwargs):
312
+ """Update an existing display by id
313
+
314
+ Parameters
315
+ ----------
316
+ obj
317
+ The object with which to update the display
318
+ display_id : keyword-only
319
+ The id of the display to update
320
+
321
+ See Also
322
+ --------
323
+ :func:`display`
324
+ """
325
+ kwargs['update'] = True
326
+ display(obj, display_id=display_id, **kwargs)
327
+
328
+
329
+ class DisplayHandle(object):
330
+ """A handle on an updatable display
331
+
332
+ Call `.update(obj)` to display a new object.
333
+
334
+ Call `.display(obj`) to add a new instance of this display,
335
+ and update existing instances.
336
+
337
+ See Also
338
+ --------
339
+
340
+ :func:`display`, :func:`update_display`
341
+
342
+ """
343
+
344
+ def __init__(self, display_id=None):
345
+ if display_id is None:
346
+ display_id = _new_id()
347
+ self.display_id = display_id
348
+
349
+ def __repr__(self):
350
+ return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
351
+
352
+ def display(self, obj, **kwargs):
353
+ """Make a new display with my id, updating existing instances.
354
+
355
+ Parameters
356
+ ----------
357
+ obj
358
+ object to display
359
+ **kwargs
360
+ additional keyword arguments passed to display
361
+ """
362
+ display(obj, display_id=self.display_id, **kwargs)
363
+
364
+ def update(self, obj, **kwargs):
365
+ """Update existing displays with my id
366
+
367
+ Parameters
368
+ ----------
369
+ obj
370
+ object to display
371
+ **kwargs
372
+ additional keyword arguments passed to update_display
373
+ """
374
+ update_display(obj, display_id=self.display_id, **kwargs)
375
+
376
+
377
+ def clear_output(wait=False):
378
+ """Clear the output of the current cell receiving output.
379
+
380
+ Parameters
381
+ ----------
382
+ wait : bool [default: false]
383
+ Wait to clear the output until new output is available to replace it."""
384
+ from IPython.core.interactiveshell import InteractiveShell
385
+ if InteractiveShell.initialized():
386
+ InteractiveShell.instance().display_pub.clear_output(wait)
387
+ else:
388
+ print('\033[2K\r', end='')
389
+ sys.stdout.flush()
390
+ print('\033[2K\r', end='')
391
+ sys.stderr.flush()
openalex_env_map/lib/python3.10/site-packages/IPython/core/display_trap.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """
3
+ A context manager for handling sys.displayhook.
4
+
5
+ Authors:
6
+
7
+ * Robert Kern
8
+ * Brian Granger
9
+ """
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Copyright (C) 2008-2011 The IPython Development Team
13
+ #
14
+ # Distributed under the terms of the BSD License. The full license is in
15
+ # the file COPYING, distributed as part of this software.
16
+ #-----------------------------------------------------------------------------
17
+
18
+ #-----------------------------------------------------------------------------
19
+ # Imports
20
+ #-----------------------------------------------------------------------------
21
+
22
+ import sys
23
+
24
+ from traitlets.config.configurable import Configurable
25
+ from traitlets import Any
26
+
27
+ #-----------------------------------------------------------------------------
28
+ # Classes and functions
29
+ #-----------------------------------------------------------------------------
30
+
31
+
32
+ class DisplayTrap(Configurable):
33
+ """Object to manage sys.displayhook.
34
+
35
+ This came from IPython.core.kernel.display_hook, but is simplified
36
+ (no callbacks or formatters) until more of the core is refactored.
37
+ """
38
+
39
+ hook = Any()
40
+
41
+ def __init__(self, hook=None):
42
+ super(DisplayTrap, self).__init__(hook=hook, config=None)
43
+ self.old_hook = None
44
+ # We define this to track if a single BuiltinTrap is nested.
45
+ # Only turn off the trap when the outermost call to __exit__ is made.
46
+ self._nested_level = 0
47
+
48
+ def __enter__(self):
49
+ if self._nested_level == 0:
50
+ self.set()
51
+ self._nested_level += 1
52
+ return self
53
+
54
+ def __exit__(self, type, value, traceback):
55
+ if self._nested_level == 1:
56
+ self.unset()
57
+ self._nested_level -= 1
58
+ # Returning False will cause exceptions to propagate
59
+ return False
60
+
61
+ def set(self):
62
+ """Set the hook."""
63
+ if sys.displayhook is not self.hook:
64
+ self.old_hook = sys.displayhook
65
+ sys.displayhook = self.hook
66
+
67
+ def unset(self):
68
+ """Unset the hook."""
69
+ sys.displayhook = self.old_hook
70
+
openalex_env_map/lib/python3.10/site-packages/IPython/core/displayhook.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """Displayhook for IPython.
3
+
4
+ This defines a callable class that IPython uses for `sys.displayhook`.
5
+ """
6
+
7
+ # Copyright (c) IPython Development Team.
8
+ # Distributed under the terms of the Modified BSD License.
9
+
10
+ import builtins as builtin_mod
11
+ import sys
12
+ import io as _io
13
+ import tokenize
14
+
15
+ from traitlets.config.configurable import Configurable
16
+ from traitlets import Instance, Float
17
+ from warnings import warn
18
+
19
+ # TODO: Move the various attributes (cache_size, [others now moved]). Some
20
+ # of these are also attributes of InteractiveShell. They should be on ONE object
21
+ # only and the other objects should ask that one object for their values.
22
+
23
+ class DisplayHook(Configurable):
24
+ """The custom IPython displayhook to replace sys.displayhook.
25
+
26
+ This class does many things, but the basic idea is that it is a callable
27
+ that gets called anytime user code returns a value.
28
+ """
29
+
30
+ shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
31
+ allow_none=True)
32
+ exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
33
+ allow_none=True)
34
+ cull_fraction = Float(0.2)
35
+
36
+ def __init__(self, shell=None, cache_size=1000, **kwargs):
37
+ super(DisplayHook, self).__init__(shell=shell, **kwargs)
38
+ cache_size_min = 3
39
+ if cache_size <= 0:
40
+ self.do_full_cache = 0
41
+ cache_size = 0
42
+ elif cache_size < cache_size_min:
43
+ self.do_full_cache = 0
44
+ cache_size = 0
45
+ warn('caching was disabled (min value for cache size is %s).' %
46
+ cache_size_min,stacklevel=3)
47
+ else:
48
+ self.do_full_cache = 1
49
+
50
+ self.cache_size = cache_size
51
+
52
+ # we need a reference to the user-level namespace
53
+ self.shell = shell
54
+
55
+ self._,self.__,self.___ = '','',''
56
+
57
+ # these are deliberately global:
58
+ to_user_ns = {'_':self._,'__':self.__,'___':self.___}
59
+ self.shell.user_ns.update(to_user_ns)
60
+
61
+ @property
62
+ def prompt_count(self):
63
+ return self.shell.execution_count
64
+
65
+ #-------------------------------------------------------------------------
66
+ # Methods used in __call__. Override these methods to modify the behavior
67
+ # of the displayhook.
68
+ #-------------------------------------------------------------------------
69
+
70
+ def check_for_underscore(self):
71
+ """Check if the user has set the '_' variable by hand."""
72
+ # If something injected a '_' variable in __builtin__, delete
73
+ # ipython's automatic one so we don't clobber that. gettext() in
74
+ # particular uses _, so we need to stay away from it.
75
+ if '_' in builtin_mod.__dict__:
76
+ try:
77
+ user_value = self.shell.user_ns['_']
78
+ if user_value is not self._:
79
+ return
80
+ del self.shell.user_ns['_']
81
+ except KeyError:
82
+ pass
83
+
84
+ def quiet(self):
85
+ """Should we silence the display hook because of ';'?"""
86
+ # do not print output if input ends in ';'
87
+
88
+ try:
89
+ cell = self.shell.history_manager.input_hist_parsed[-1]
90
+ except IndexError:
91
+ # some uses of ipshellembed may fail here
92
+ return False
93
+
94
+ return self.semicolon_at_end_of_expression(cell)
95
+
96
+ @staticmethod
97
+ def semicolon_at_end_of_expression(expression):
98
+ """Parse Python expression and detects whether last token is ';'"""
99
+
100
+ sio = _io.StringIO(expression)
101
+ tokens = list(tokenize.generate_tokens(sio.readline))
102
+
103
+ for token in reversed(tokens):
104
+ if token[0] in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT):
105
+ continue
106
+ if (token[0] == tokenize.OP) and (token[1] == ';'):
107
+ return True
108
+ else:
109
+ return False
110
+
111
+ def start_displayhook(self):
112
+ """Start the displayhook, initializing resources."""
113
+ pass
114
+
115
+ def write_output_prompt(self):
116
+ """Write the output prompt.
117
+
118
+ The default implementation simply writes the prompt to
119
+ ``sys.stdout``.
120
+ """
121
+ # Use write, not print which adds an extra space.
122
+ sys.stdout.write(self.shell.separate_out)
123
+ outprompt = 'Out[{}]: '.format(self.shell.execution_count)
124
+ if self.do_full_cache:
125
+ sys.stdout.write(outprompt)
126
+
127
+ def compute_format_data(self, result):
128
+ """Compute format data of the object to be displayed.
129
+
130
+ The format data is a generalization of the :func:`repr` of an object.
131
+ In the default implementation the format data is a :class:`dict` of
132
+ key value pair where the keys are valid MIME types and the values
133
+ are JSON'able data structure containing the raw data for that MIME
134
+ type. It is up to frontends to determine pick a MIME to to use and
135
+ display that data in an appropriate manner.
136
+
137
+ This method only computes the format data for the object and should
138
+ NOT actually print or write that to a stream.
139
+
140
+ Parameters
141
+ ----------
142
+ result : object
143
+ The Python object passed to the display hook, whose format will be
144
+ computed.
145
+
146
+ Returns
147
+ -------
148
+ (format_dict, md_dict) : dict
149
+ format_dict is a :class:`dict` whose keys are valid MIME types and values are
150
+ JSON'able raw data for that MIME type. It is recommended that
151
+ all return values of this should always include the "text/plain"
152
+ MIME type representation of the object.
153
+ md_dict is a :class:`dict` with the same MIME type keys
154
+ of metadata associated with each output.
155
+
156
+ """
157
+ return self.shell.display_formatter.format(result)
158
+
159
+ # This can be set to True by the write_output_prompt method in a subclass
160
+ prompt_end_newline = False
161
+
162
+ def write_format_data(self, format_dict, md_dict=None) -> None:
163
+ """Write the format data dict to the frontend.
164
+
165
+ This default version of this method simply writes the plain text
166
+ representation of the object to ``sys.stdout``. Subclasses should
167
+ override this method to send the entire `format_dict` to the
168
+ frontends.
169
+
170
+ Parameters
171
+ ----------
172
+ format_dict : dict
173
+ The format dict for the object passed to `sys.displayhook`.
174
+ md_dict : dict (optional)
175
+ The metadata dict to be associated with the display data.
176
+ """
177
+ if 'text/plain' not in format_dict:
178
+ # nothing to do
179
+ return
180
+ # We want to print because we want to always make sure we have a
181
+ # newline, even if all the prompt separators are ''. This is the
182
+ # standard IPython behavior.
183
+ result_repr = format_dict['text/plain']
184
+ if '\n' in result_repr:
185
+ # So that multi-line strings line up with the left column of
186
+ # the screen, instead of having the output prompt mess up
187
+ # their first line.
188
+ # We use the prompt template instead of the expanded prompt
189
+ # because the expansion may add ANSI escapes that will interfere
190
+ # with our ability to determine whether or not we should add
191
+ # a newline.
192
+ if not self.prompt_end_newline:
193
+ # But avoid extraneous empty lines.
194
+ result_repr = '\n' + result_repr
195
+
196
+ try:
197
+ print(result_repr)
198
+ except UnicodeEncodeError:
199
+ # If a character is not supported by the terminal encoding replace
200
+ # it with its \u or \x representation
201
+ print(result_repr.encode(sys.stdout.encoding,'backslashreplace').decode(sys.stdout.encoding))
202
+
203
+ def update_user_ns(self, result):
204
+ """Update user_ns with various things like _, __, _1, etc."""
205
+
206
+ # Avoid recursive reference when displaying _oh/Out
207
+ if self.cache_size and result is not self.shell.user_ns['_oh']:
208
+ if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
209
+ self.cull_cache()
210
+
211
+ # Don't overwrite '_' and friends if '_' is in __builtin__
212
+ # (otherwise we cause buggy behavior for things like gettext). and
213
+ # do not overwrite _, __ or ___ if one of these has been assigned
214
+ # by the user.
215
+ update_unders = True
216
+ for unders in ['_'*i for i in range(1,4)]:
217
+ if not unders in self.shell.user_ns:
218
+ continue
219
+ if getattr(self, unders) is not self.shell.user_ns.get(unders):
220
+ update_unders = False
221
+
222
+ self.___ = self.__
223
+ self.__ = self._
224
+ self._ = result
225
+
226
+ if ('_' not in builtin_mod.__dict__) and (update_unders):
227
+ self.shell.push({'_':self._,
228
+ '__':self.__,
229
+ '___':self.___}, interactive=False)
230
+
231
+ # hackish access to top-level namespace to create _1,_2... dynamically
232
+ to_main = {}
233
+ if self.do_full_cache:
234
+ new_result = '_%s' % self.prompt_count
235
+ to_main[new_result] = result
236
+ self.shell.push(to_main, interactive=False)
237
+ self.shell.user_ns['_oh'][self.prompt_count] = result
238
+
239
+ def fill_exec_result(self, result):
240
+ if self.exec_result is not None:
241
+ self.exec_result.result = result
242
+
243
+ def log_output(self, format_dict):
244
+ """Log the output."""
245
+ if 'text/plain' not in format_dict:
246
+ # nothing to do
247
+ return
248
+ if self.shell.logger.log_output:
249
+ self.shell.logger.log_write(format_dict['text/plain'], 'output')
250
+ self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
251
+ format_dict['text/plain']
252
+
253
+ def finish_displayhook(self):
254
+ """Finish up all displayhook activities."""
255
+ sys.stdout.write(self.shell.separate_out2)
256
+ sys.stdout.flush()
257
+
258
+ def __call__(self, result=None):
259
+ """Printing with history cache management.
260
+
261
+ This is invoked every time the interpreter needs to print, and is
262
+ activated by setting the variable sys.displayhook to it.
263
+ """
264
+ self.check_for_underscore()
265
+ if result is not None and not self.quiet():
266
+ self.start_displayhook()
267
+ self.write_output_prompt()
268
+ format_dict, md_dict = self.compute_format_data(result)
269
+ self.update_user_ns(result)
270
+ self.fill_exec_result(result)
271
+ if format_dict:
272
+ self.write_format_data(format_dict, md_dict)
273
+ self.log_output(format_dict)
274
+ self.finish_displayhook()
275
+
276
+ def cull_cache(self):
277
+ """Output cache is full, cull the oldest entries"""
278
+ oh = self.shell.user_ns.get('_oh', {})
279
+ sz = len(oh)
280
+ cull_count = max(int(sz * self.cull_fraction), 2)
281
+ warn('Output cache limit (currently {sz} entries) hit.\n'
282
+ 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
283
+
284
+ for i, n in enumerate(sorted(oh)):
285
+ if i >= cull_count:
286
+ break
287
+ self.shell.user_ns.pop('_%i' % n, None)
288
+ oh.pop(n, None)
289
+
290
+
291
+ def flush(self):
292
+ if not self.do_full_cache:
293
+ raise ValueError("You shouldn't have reached the cache flush "
294
+ "if full caching is not enabled!")
295
+ # delete auto-generated vars from global namespace
296
+
297
+ for n in range(1,self.prompt_count + 1):
298
+ key = '_'+repr(n)
299
+ try:
300
+ del self.shell.user_ns_hidden[key]
301
+ except KeyError:
302
+ pass
303
+ try:
304
+ del self.shell.user_ns[key]
305
+ except KeyError:
306
+ pass
307
+ # In some embedded circumstances, the user_ns doesn't have the
308
+ # '_oh' key set up.
309
+ oh = self.shell.user_ns.get('_oh', None)
310
+ if oh is not None:
311
+ oh.clear()
312
+
313
+ # Release our own references to objects:
314
+ self._, self.__, self.___ = '', '', ''
315
+
316
+ if '_' not in builtin_mod.__dict__:
317
+ self.shell.user_ns.update({'_':self._,'__':self.__,'___':self.___})
318
+ import gc
319
+ # TODO: Is this really needed?
320
+ # IronPython blocks here forever
321
+ if sys.platform != "cli":
322
+ gc.collect()
323
+
324
+
325
+ class CapturingDisplayHook(object):
326
+ def __init__(self, shell, outputs=None):
327
+ self.shell = shell
328
+ if outputs is None:
329
+ outputs = []
330
+ self.outputs = outputs
331
+
332
+ def __call__(self, result=None):
333
+ if result is None:
334
+ return
335
+ format_dict, md_dict = self.shell.display_formatter.format(result)
336
+ self.outputs.append({ 'data': format_dict, 'metadata': md_dict })
openalex_env_map/lib/python3.10/site-packages/IPython/core/displaypub.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """An interface for publishing rich data to frontends.
2
+
3
+ There are two components of the display system:
4
+
5
+ * Display formatters, which take a Python object and compute the
6
+ representation of the object in various formats (text, HTML, SVG, etc.).
7
+ * The display publisher that is used to send the representation data to the
8
+ various frontends.
9
+
10
+ This module defines the logic display publishing. The display publisher uses
11
+ the ``display_data`` message type that is defined in the IPython messaging
12
+ spec.
13
+ """
14
+
15
+ # Copyright (c) IPython Development Team.
16
+ # Distributed under the terms of the Modified BSD License.
17
+
18
+
19
+ import sys
20
+
21
+ from traitlets.config.configurable import Configurable
22
+ from traitlets import List
23
+
24
+ # This used to be defined here - it is imported for backwards compatibility
25
+ from .display_functions import publish_display_data
26
+
27
+ import typing as t
28
+
29
+ # -----------------------------------------------------------------------------
30
+ # Main payload class
31
+ #-----------------------------------------------------------------------------
32
+
33
+
34
+ class DisplayPublisher(Configurable):
35
+ """A traited class that publishes display data to frontends.
36
+
37
+ Instances of this class are created by the main IPython object and should
38
+ be accessed there.
39
+ """
40
+
41
+ def __init__(self, shell=None, *args, **kwargs):
42
+ self.shell = shell
43
+ super().__init__(*args, **kwargs)
44
+
45
+ def _validate_data(self, data, metadata=None):
46
+ """Validate the display data.
47
+
48
+ Parameters
49
+ ----------
50
+ data : dict
51
+ The formata data dictionary.
52
+ metadata : dict
53
+ Any metadata for the data.
54
+ """
55
+
56
+ if not isinstance(data, dict):
57
+ raise TypeError('data must be a dict, got: %r' % data)
58
+ if metadata is not None:
59
+ if not isinstance(metadata, dict):
60
+ raise TypeError('metadata must be a dict, got: %r' % data)
61
+
62
+ # use * to indicate transient, update are keyword-only
63
+ def publish(self, data, metadata=None, source=None, *, transient=None, update=False, **kwargs) -> None:
64
+ """Publish data and metadata to all frontends.
65
+
66
+ See the ``display_data`` message in the messaging documentation for
67
+ more details about this message type.
68
+
69
+ The following MIME types are currently implemented:
70
+
71
+ * text/plain
72
+ * text/html
73
+ * text/markdown
74
+ * text/latex
75
+ * application/json
76
+ * application/javascript
77
+ * image/png
78
+ * image/jpeg
79
+ * image/svg+xml
80
+
81
+ Parameters
82
+ ----------
83
+ data : dict
84
+ A dictionary having keys that are valid MIME types (like
85
+ 'text/plain' or 'image/svg+xml') and values that are the data for
86
+ that MIME type. The data itself must be a JSON'able data
87
+ structure. Minimally all data should have the 'text/plain' data,
88
+ which can be displayed by all frontends. If more than the plain
89
+ text is given, it is up to the frontend to decide which
90
+ representation to use.
91
+ metadata : dict
92
+ A dictionary for metadata related to the data. This can contain
93
+ arbitrary key, value pairs that frontends can use to interpret
94
+ the data. Metadata specific to each mime-type can be specified
95
+ in the metadata dict with the same mime-type keys as
96
+ the data itself.
97
+ source : str, deprecated
98
+ Unused.
99
+ transient : dict, keyword-only
100
+ A dictionary for transient data.
101
+ Data in this dictionary should not be persisted as part of saving this output.
102
+ Examples include 'display_id'.
103
+ update : bool, keyword-only, default: False
104
+ If True, only update existing outputs with the same display_id,
105
+ rather than creating a new output.
106
+ """
107
+
108
+ handlers: t.Dict = {}
109
+ if self.shell is not None:
110
+ handlers = getattr(self.shell, "mime_renderers", {})
111
+
112
+ for mime, handler in handlers.items():
113
+ if mime in data:
114
+ handler(data[mime], metadata.get(mime, None))
115
+ return
116
+
117
+ if 'text/plain' in data:
118
+ print(data['text/plain'])
119
+
120
+ def clear_output(self, wait=False):
121
+ """Clear the output of the cell receiving output."""
122
+ print('\033[2K\r', end='')
123
+ sys.stdout.flush()
124
+ print('\033[2K\r', end='')
125
+ sys.stderr.flush()
126
+
127
+
128
+ class CapturingDisplayPublisher(DisplayPublisher):
129
+ """A DisplayPublisher that stores"""
130
+
131
+ outputs: List = List()
132
+
133
+ def publish(
134
+ self, data, metadata=None, source=None, *, transient=None, update=False
135
+ ):
136
+ self.outputs.append(
137
+ {
138
+ "data": data,
139
+ "metadata": metadata,
140
+ "transient": transient,
141
+ "update": update,
142
+ }
143
+ )
144
+
145
+ def clear_output(self, wait=False):
146
+ super(CapturingDisplayPublisher, self).clear_output(wait)
147
+
148
+ # empty the list, *do not* reassign a new list
149
+ self.outputs.clear()
openalex_env_map/lib/python3.10/site-packages/IPython/core/error.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """
3
+ Global exception classes for IPython.core.
4
+
5
+ Authors:
6
+
7
+ * Brian Granger
8
+ * Fernando Perez
9
+ * Min Ragan-Kelley
10
+
11
+ Notes
12
+ -----
13
+ """
14
+
15
+ #-----------------------------------------------------------------------------
16
+ # Copyright (C) 2008 The IPython Development Team
17
+ #
18
+ # Distributed under the terms of the BSD License. The full license is in
19
+ # the file COPYING, distributed as part of this software.
20
+ #-----------------------------------------------------------------------------
21
+
22
+ #-----------------------------------------------------------------------------
23
+ # Imports
24
+ #-----------------------------------------------------------------------------
25
+
26
+ #-----------------------------------------------------------------------------
27
+ # Exception classes
28
+ #-----------------------------------------------------------------------------
29
+
30
+ class IPythonCoreError(Exception):
31
+ pass
32
+
33
+
34
+ class TryNext(IPythonCoreError):
35
+ """Try next hook exception.
36
+
37
+ Raise this in your hook function to indicate that the next hook handler
38
+ should be used to handle the operation.
39
+ """
40
+
41
+ class UsageError(IPythonCoreError):
42
+ """Error in magic function arguments, etc.
43
+
44
+ Something that probably won't warrant a full traceback, but should
45
+ nevertheless interrupt a macro / batch file.
46
+ """
47
+
48
+ class StdinNotImplementedError(IPythonCoreError, NotImplementedError):
49
+ """raw_input was requested in a context where it is not supported
50
+
51
+ For use in IPython kernels, where only some frontends may support
52
+ stdin requests.
53
+ """
54
+
55
+ class InputRejected(Exception):
56
+ """Input rejected by ast transformer.
57
+
58
+ Raise this in your NodeTransformer to indicate that InteractiveShell should
59
+ not execute the supplied input.
60
+ """
openalex_env_map/lib/python3.10/site-packages/IPython/core/events.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Infrastructure for registering and firing callbacks on application events.
2
+
3
+ Unlike :mod:`IPython.core.hooks`, which lets end users set single functions to
4
+ be called at specific times, or a collection of alternative methods to try,
5
+ callbacks are designed to be used by extension authors. A number of callbacks
6
+ can be registered for the same event without needing to be aware of one another.
7
+
8
+ The functions defined in this module are no-ops indicating the names of available
9
+ events and the arguments which will be passed to them.
10
+
11
+ .. note::
12
+
13
+ This API is experimental in IPython 2.0, and may be revised in future versions.
14
+ """
15
+
16
+
17
+ class EventManager(object):
18
+ """Manage a collection of events and a sequence of callbacks for each.
19
+
20
+ This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell`
21
+ instances as an ``events`` attribute.
22
+
23
+ .. note::
24
+
25
+ This API is experimental in IPython 2.0, and may be revised in future versions.
26
+ """
27
+
28
+ def __init__(self, shell, available_events, print_on_error=True):
29
+ """Initialise the :class:`CallbackManager`.
30
+
31
+ Parameters
32
+ ----------
33
+ shell
34
+ The :class:`~IPython.core.interactiveshell.InteractiveShell` instance
35
+ available_events
36
+ An iterable of names for callback events.
37
+ print_on_error:
38
+ A boolean flag to set whether the EventManager will print a warning which a event errors.
39
+ """
40
+ self.shell = shell
41
+ self.callbacks = {n:[] for n in available_events}
42
+ self.print_on_error = print_on_error
43
+
44
+ def register(self, event, function):
45
+ """Register a new event callback.
46
+
47
+ Parameters
48
+ ----------
49
+ event : str
50
+ The event for which to register this callback.
51
+ function : callable
52
+ A function to be called on the given event. It should take the same
53
+ parameters as the appropriate callback prototype.
54
+
55
+ Raises
56
+ ------
57
+ TypeError
58
+ If ``function`` is not callable.
59
+ KeyError
60
+ If ``event`` is not one of the known events.
61
+ """
62
+ if not callable(function):
63
+ raise TypeError('Need a callable, got %r' % function)
64
+ if function not in self.callbacks[event]:
65
+ self.callbacks[event].append(function)
66
+
67
+ def unregister(self, event, function):
68
+ """Remove a callback from the given event."""
69
+ if function in self.callbacks[event]:
70
+ return self.callbacks[event].remove(function)
71
+
72
+ raise ValueError('Function {!r} is not registered as a {} callback'.format(function, event))
73
+
74
+ def trigger(self, event, *args, **kwargs):
75
+ """Call callbacks for ``event``.
76
+
77
+ Any additional arguments are passed to all callbacks registered for this
78
+ event. Exceptions raised by callbacks are caught, and a message printed.
79
+ """
80
+ for func in self.callbacks[event][:]:
81
+ try:
82
+ func(*args, **kwargs)
83
+ except (Exception, KeyboardInterrupt):
84
+ if self.print_on_error:
85
+ print(
86
+ "Error in callback {} (for {}), with arguments args {},kwargs {}:".format(
87
+ func, event, args, kwargs
88
+ )
89
+ )
90
+ self.shell.showtraceback()
91
+
92
+ # event_name -> prototype mapping
93
+ available_events = {}
94
+
95
+ def _define_event(callback_function):
96
+ available_events[callback_function.__name__] = callback_function
97
+ return callback_function
98
+
99
+ # ------------------------------------------------------------------------------
100
+ # Callback prototypes
101
+ #
102
+ # No-op functions which describe the names of available events and the
103
+ # signatures of callbacks for those events.
104
+ # ------------------------------------------------------------------------------
105
+
106
+ @_define_event
107
+ def pre_execute():
108
+ """Fires before code is executed in response to user/frontend action.
109
+
110
+ This includes comm and widget messages and silent execution, as well as user
111
+ code cells.
112
+ """
113
+ pass
114
+
115
+ @_define_event
116
+ def pre_run_cell(info):
117
+ """Fires before user-entered code runs.
118
+
119
+ Parameters
120
+ ----------
121
+ info : :class:`~IPython.core.interactiveshell.ExecutionInfo`
122
+ An object containing information used for the code execution.
123
+ """
124
+ pass
125
+
126
+ @_define_event
127
+ def post_execute():
128
+ """Fires after code is executed in response to user/frontend action.
129
+
130
+ This includes comm and widget messages and silent execution, as well as user
131
+ code cells.
132
+ """
133
+ pass
134
+
135
+ @_define_event
136
+ def post_run_cell(result):
137
+ """Fires after user-entered code runs.
138
+
139
+ Parameters
140
+ ----------
141
+ result : :class:`~IPython.core.interactiveshell.ExecutionResult`
142
+ The object which will be returned as the execution result.
143
+ """
144
+ pass
145
+
146
+ @_define_event
147
+ def shell_initialized(ip):
148
+ """Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`.
149
+
150
+ This is before extensions and startup scripts are loaded, so it can only be
151
+ set by subclassing.
152
+
153
+ Parameters
154
+ ----------
155
+ ip : :class:`~IPython.core.interactiveshell.InteractiveShell`
156
+ The newly initialised shell.
157
+ """
158
+ pass
openalex_env_map/lib/python3.10/site-packages/IPython/core/excolors.py ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Color schemes for exception handling code in IPython.
4
+ """
5
+
6
+ import os
7
+
8
+ #*****************************************************************************
9
+ # Copyright (C) 2005-2006 Fernando Perez <[email protected]>
10
+ #
11
+ # Distributed under the terms of the BSD License. The full license is in
12
+ # the file COPYING, distributed as part of this software.
13
+ #*****************************************************************************
14
+
15
+ from IPython.utils.coloransi import ColorSchemeTable, TermColors, ColorScheme
16
+
17
+ def exception_colors():
18
+ """Return a color table with fields for exception reporting.
19
+
20
+ The table is an instance of ColorSchemeTable with schemes added for
21
+ 'Neutral', 'Linux', 'LightBG' and 'NoColor' and fields for exception handling filled
22
+ in.
23
+
24
+ Examples:
25
+
26
+ >>> ec = exception_colors()
27
+ >>> ec.active_scheme_name
28
+ ''
29
+ >>> print(ec.active_colors)
30
+ None
31
+
32
+ Now we activate a color scheme:
33
+ >>> ec.set_active_scheme('NoColor')
34
+ >>> ec.active_scheme_name
35
+ 'NoColor'
36
+ >>> sorted(ec.active_colors.keys())
37
+ ['Normal', 'breakpoint_disabled', 'breakpoint_enabled', 'caret', 'em',
38
+ 'excName', 'filename', 'filenameEm', 'line', 'lineno', 'linenoEm', 'name',
39
+ 'nameEm', 'normalEm', 'prompt', 'topline', 'vName', 'val', 'valEm']
40
+
41
+ """
42
+
43
+ ex_colors = ColorSchemeTable()
44
+
45
+ # Populate it with color schemes
46
+ C = TermColors # shorthand and local lookup
47
+ ex_colors.add_scheme(
48
+ ColorScheme(
49
+ "NoColor",
50
+ {
51
+ # The color to be used for the top line
52
+ "topline": C.NoColor,
53
+
54
+ # The colors to be used in the traceback
55
+ "filename": C.NoColor,
56
+ "lineno": C.NoColor,
57
+ "name": C.NoColor,
58
+ "vName": C.NoColor,
59
+ "val": C.NoColor,
60
+ "em": C.NoColor,
61
+
62
+ # Emphasized colors for the last frame of the traceback
63
+ "normalEm": C.NoColor,
64
+ "filenameEm": C.NoColor,
65
+ "linenoEm": C.NoColor,
66
+ "nameEm": C.NoColor,
67
+ "valEm": C.NoColor,
68
+
69
+ # Colors for printing the exception
70
+ "excName": C.NoColor,
71
+ "line": C.NoColor,
72
+ "caret": C.NoColor,
73
+ "Normal": C.NoColor,
74
+ # debugger
75
+ "prompt": C.NoColor,
76
+ "breakpoint_enabled": C.NoColor,
77
+ "breakpoint_disabled": C.NoColor,
78
+ },
79
+ )
80
+ )
81
+
82
+ # make some schemes as instances so we can copy them for modification easily
83
+ ex_colors.add_scheme(
84
+ ColorScheme(
85
+ "Linux",
86
+ {
87
+ # The color to be used for the top line
88
+ "topline": C.LightRed,
89
+ # The colors to be used in the traceback
90
+ "filename": C.Green,
91
+ "lineno": C.Green,
92
+ "name": C.Purple,
93
+ "vName": C.Cyan,
94
+ "val": C.Green,
95
+ "em": C.LightCyan,
96
+ # Emphasized colors for the last frame of the traceback
97
+ "normalEm": C.LightCyan,
98
+ "filenameEm": C.LightGreen,
99
+ "linenoEm": C.LightGreen,
100
+ "nameEm": C.LightPurple,
101
+ "valEm": C.LightBlue,
102
+ # Colors for printing the exception
103
+ "excName": C.LightRed,
104
+ "line": C.Yellow,
105
+ "caret": C.White,
106
+ "Normal": C.Normal,
107
+ # debugger
108
+ "prompt": C.Green,
109
+ "breakpoint_enabled": C.LightRed,
110
+ "breakpoint_disabled": C.Red,
111
+ },
112
+ )
113
+ )
114
+
115
+ # For light backgrounds, swap dark/light colors
116
+ ex_colors.add_scheme(
117
+ ColorScheme(
118
+ "LightBG",
119
+ {
120
+ # The color to be used for the top line
121
+ "topline": C.Red,
122
+
123
+ # The colors to be used in the traceback
124
+ "filename": C.LightGreen,
125
+ "lineno": C.LightGreen,
126
+ "name": C.LightPurple,
127
+ "vName": C.Cyan,
128
+ "val": C.LightGreen,
129
+ "em": C.Cyan,
130
+
131
+ # Emphasized colors for the last frame of the traceback
132
+ "normalEm": C.Cyan,
133
+ "filenameEm": C.Green,
134
+ "linenoEm": C.Green,
135
+ "nameEm": C.Purple,
136
+ "valEm": C.Blue,
137
+
138
+ # Colors for printing the exception
139
+ "excName": C.Red,
140
+ # "line": C.Brown, # brown often is displayed as yellow
141
+ "line": C.Red,
142
+ "caret": C.Normal,
143
+ "Normal": C.Normal,
144
+ # debugger
145
+ "prompt": C.Blue,
146
+ "breakpoint_enabled": C.LightRed,
147
+ "breakpoint_disabled": C.Red,
148
+ },
149
+ )
150
+ )
151
+
152
+ ex_colors.add_scheme(
153
+ ColorScheme(
154
+ "Neutral",
155
+ {
156
+ # The color to be used for the top line
157
+ "topline": C.Red,
158
+ # The colors to be used in the traceback
159
+ "filename": C.LightGreen,
160
+ "lineno": C.LightGreen,
161
+ "name": C.LightPurple,
162
+ "vName": C.Cyan,
163
+ "val": C.LightGreen,
164
+ "em": C.Cyan,
165
+ # Emphasized colors for the last frame of the traceback
166
+ "normalEm": C.Cyan,
167
+ "filenameEm": C.Green,
168
+ "linenoEm": C.Green,
169
+ "nameEm": C.Purple,
170
+ "valEm": C.Blue,
171
+ # Colors for printing the exception
172
+ "excName": C.Red,
173
+ # line = C.Brown, # brown often is displayed as yellow
174
+ "line": C.Red,
175
+ "caret": C.Normal,
176
+ "Normal": C.Normal,
177
+ # debugger
178
+ "prompt": C.Blue,
179
+ "breakpoint_enabled": C.LightRed,
180
+ "breakpoint_disabled": C.Red,
181
+ },
182
+ )
183
+ )
184
+
185
+ # Hack: the 'neutral' colours are not very visible on a dark background on
186
+ # Windows. Since Windows command prompts have a dark background by default, and
187
+ # relatively few users are likely to alter that, we will use the 'Linux' colours,
188
+ # designed for a dark background, as the default on Windows.
189
+ if os.name == "nt":
190
+ ex_colors.add_scheme(ex_colors['Linux'].copy('Neutral'))
191
+
192
+ return ex_colors
openalex_env_map/lib/python3.10/site-packages/IPython/core/extensions.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """A class for managing IPython extensions."""
3
+
4
+ # Copyright (c) IPython Development Team.
5
+ # Distributed under the terms of the Modified BSD License.
6
+
7
+ import os
8
+ import os.path
9
+ import sys
10
+ from importlib import import_module, reload
11
+
12
+ from traitlets.config.configurable import Configurable
13
+ from IPython.utils.path import ensure_dir_exists
14
+ from traitlets import Instance
15
+
16
+
17
+ #-----------------------------------------------------------------------------
18
+ # Main class
19
+ #-----------------------------------------------------------------------------
20
+
21
+ BUILTINS_EXTS = {"storemagic": False, "autoreload": False}
22
+
23
+
24
+ class ExtensionManager(Configurable):
25
+ """A class to manage IPython extensions.
26
+
27
+ An IPython extension is an importable Python module that has
28
+ a function with the signature::
29
+
30
+ def load_ipython_extension(ipython):
31
+ # Do things with ipython
32
+
33
+ This function is called after your extension is imported and the
34
+ currently active :class:`InteractiveShell` instance is passed as
35
+ the only argument. You can do anything you want with IPython at
36
+ that point, including defining new magic and aliases, adding new
37
+ components, etc.
38
+
39
+ You can also optionally define an :func:`unload_ipython_extension(ipython)`
40
+ function, which will be called if the user unloads or reloads the extension.
41
+ The extension manager will only call :func:`load_ipython_extension` again
42
+ if the extension is reloaded.
43
+
44
+ You can put your extension modules anywhere you want, as long as
45
+ they can be imported by Python's standard import mechanism.
46
+ """
47
+
48
+ shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
49
+
50
+ def __init__(self, shell=None, **kwargs):
51
+ super(ExtensionManager, self).__init__(shell=shell, **kwargs)
52
+ self.loaded = set()
53
+
54
+ def load_extension(self, module_str: str):
55
+ """Load an IPython extension by its module name.
56
+
57
+ Returns the string "already loaded" if the extension is already loaded,
58
+ "no load function" if the module doesn't have a load_ipython_extension
59
+ function, or None if it succeeded.
60
+ """
61
+ try:
62
+ return self._load_extension(module_str)
63
+ except ModuleNotFoundError:
64
+ if module_str in BUILTINS_EXTS:
65
+ BUILTINS_EXTS[module_str] = True
66
+ return self._load_extension("IPython.extensions." + module_str)
67
+ raise
68
+
69
+ def _load_extension(self, module_str: str):
70
+ if module_str in self.loaded:
71
+ return "already loaded"
72
+
73
+ assert self.shell is not None
74
+
75
+ with self.shell.builtin_trap:
76
+ if module_str not in sys.modules:
77
+ mod = import_module(module_str)
78
+ mod = sys.modules[module_str]
79
+ if self._call_load_ipython_extension(mod):
80
+ self.loaded.add(module_str)
81
+ else:
82
+ return "no load function"
83
+
84
+ def unload_extension(self, module_str: str):
85
+ """Unload an IPython extension by its module name.
86
+
87
+ This function looks up the extension's name in ``sys.modules`` and
88
+ simply calls ``mod.unload_ipython_extension(self)``.
89
+
90
+ Returns the string "no unload function" if the extension doesn't define
91
+ a function to unload itself, "not loaded" if the extension isn't loaded,
92
+ otherwise None.
93
+ """
94
+ if BUILTINS_EXTS.get(module_str, False) is True:
95
+ module_str = "IPython.extensions." + module_str
96
+ if module_str not in self.loaded:
97
+ return "not loaded"
98
+
99
+ if module_str in sys.modules:
100
+ mod = sys.modules[module_str]
101
+ if self._call_unload_ipython_extension(mod):
102
+ self.loaded.discard(module_str)
103
+ else:
104
+ return "no unload function"
105
+
106
+ def reload_extension(self, module_str: str):
107
+ """Reload an IPython extension by calling reload.
108
+
109
+ If the module has not been loaded before,
110
+ :meth:`InteractiveShell.load_extension` is called. Otherwise
111
+ :func:`reload` is called and then the :func:`load_ipython_extension`
112
+ function of the module, if it exists is called.
113
+ """
114
+
115
+ if BUILTINS_EXTS.get(module_str, False) is True:
116
+ module_str = "IPython.extensions." + module_str
117
+
118
+ if (module_str in self.loaded) and (module_str in sys.modules):
119
+ self.unload_extension(module_str)
120
+ mod = sys.modules[module_str]
121
+ reload(mod)
122
+ if self._call_load_ipython_extension(mod):
123
+ self.loaded.add(module_str)
124
+ else:
125
+ self.load_extension(module_str)
126
+
127
+ def _call_load_ipython_extension(self, mod):
128
+ if hasattr(mod, 'load_ipython_extension'):
129
+ mod.load_ipython_extension(self.shell)
130
+ return True
131
+
132
+ def _call_unload_ipython_extension(self, mod):
133
+ if hasattr(mod, 'unload_ipython_extension'):
134
+ mod.unload_ipython_extension(self.shell)
135
+ return True
openalex_env_map/lib/python3.10/site-packages/IPython/core/formatters.py ADDED
@@ -0,0 +1,1090 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """Display formatters.
3
+
4
+ This module defines the base instances in order to implement custom
5
+ formatters/mimetypes
6
+ got objects:
7
+
8
+ As we want to see internal IPython working we are going to use the following
9
+ function to diaply objects instead of the normal print or display method:
10
+
11
+ >>> ip = get_ipython()
12
+ >>> ip.display_formatter.format(...)
13
+ ({'text/plain': 'Ellipsis'}, {})
14
+
15
+ This return a tuple with the mimebumdle for the current object, and the
16
+ associated metadata.
17
+
18
+
19
+ We can now define our own formatter and register it:
20
+
21
+
22
+ >>> from IPython.core.formatters import BaseFormatter, FormatterABC
23
+
24
+
25
+ >>> class LLMFormatter(BaseFormatter):
26
+ ...
27
+ ... format_type = 'x-vendor/llm'
28
+ ... print_method = '_repr_llm_'
29
+ ... _return_type = (dict, str)
30
+
31
+ >>> llm_formatter = LLMFormatter(parent=ip.display_formatter)
32
+
33
+ >>> ip.display_formatter.formatters[LLMFormatter.format_type] = llm_formatter
34
+
35
+ Now any class that define `_repr_llm_` will return a x-vendor/llm as part of
36
+ it's display data:
37
+
38
+ >>> class A:
39
+ ...
40
+ ... def _repr_llm_(self, *kwargs):
41
+ ... return 'This a A'
42
+ ...
43
+
44
+ >>> ip.display_formatter.format(A())
45
+ ({'text/plain': '<IPython.core.formatters.A at ...>', 'x-vendor/llm': 'This a A'}, {})
46
+
47
+ As usual, you can register methods for third party types (see
48
+ :ref:`third_party_formatting`)
49
+
50
+ >>> def llm_int(obj):
51
+ ... return 'This is the integer %s, in between %s and %s'%(obj, obj-1, obj+1)
52
+
53
+ >>> llm_formatter.for_type(int, llm_int)
54
+
55
+ >>> ip.display_formatter.format(42)
56
+ ({'text/plain': '42', 'x-vendor/llm': 'This is the integer 42, in between 41 and 43'}, {})
57
+
58
+
59
+ Inheritance diagram:
60
+
61
+ .. inheritance-diagram:: IPython.core.formatters
62
+ :parts: 3
63
+ """
64
+
65
+ # Copyright (c) IPython Development Team.
66
+ # Distributed under the terms of the Modified BSD License.
67
+
68
+ import abc
69
+ import sys
70
+ import traceback
71
+ import warnings
72
+ from io import StringIO
73
+
74
+ from decorator import decorator
75
+
76
+ from traitlets.config.configurable import Configurable
77
+ from .getipython import get_ipython
78
+ from ..utils.sentinel import Sentinel
79
+ from ..utils.dir2 import get_real_method
80
+ from ..lib import pretty
81
+ from traitlets import (
82
+ Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
83
+ ForwardDeclaredInstance,
84
+ default, observe,
85
+ )
86
+
87
+ from typing import Any
88
+
89
+
90
+ class DisplayFormatter(Configurable):
91
+
92
+ active_types = List(Unicode(),
93
+ help="""List of currently active mime-types to display.
94
+ You can use this to set a white-list for formats to display.
95
+
96
+ Most users will not need to change this value.
97
+ """,
98
+ ).tag(config=True)
99
+
100
+ @default('active_types')
101
+ def _active_types_default(self):
102
+ return self.format_types
103
+
104
+ @observe('active_types')
105
+ def _active_types_changed(self, change):
106
+ for key, formatter in self.formatters.items():
107
+ if key in change['new']:
108
+ formatter.enabled = True
109
+ else:
110
+ formatter.enabled = False
111
+
112
+ ipython_display_formatter = ForwardDeclaredInstance("FormatterABC") # type: ignore
113
+
114
+ @default("ipython_display_formatter")
115
+ def _default_formatter(self):
116
+ return IPythonDisplayFormatter(parent=self)
117
+
118
+ mimebundle_formatter = ForwardDeclaredInstance("FormatterABC") # type: ignore
119
+
120
+ @default("mimebundle_formatter")
121
+ def _default_mime_formatter(self):
122
+ return MimeBundleFormatter(parent=self)
123
+
124
+ # A dict of formatter whose keys are format types (MIME types) and whose
125
+ # values are subclasses of BaseFormatter.
126
+ formatters = Dict()
127
+
128
+ @default("formatters")
129
+ def _formatters_default(self):
130
+ """Activate the default formatters."""
131
+ formatter_classes = [
132
+ PlainTextFormatter,
133
+ HTMLFormatter,
134
+ MarkdownFormatter,
135
+ SVGFormatter,
136
+ PNGFormatter,
137
+ PDFFormatter,
138
+ JPEGFormatter,
139
+ LatexFormatter,
140
+ JSONFormatter,
141
+ JavascriptFormatter
142
+ ]
143
+ d = {}
144
+ for cls in formatter_classes:
145
+ f = cls(parent=self)
146
+ d[f.format_type] = f
147
+ return d
148
+
149
+ def format(self, obj, include=None, exclude=None):
150
+ """Return a format data dict for an object.
151
+
152
+ By default all format types will be computed.
153
+
154
+ The following MIME types are usually implemented:
155
+
156
+ * text/plain
157
+ * text/html
158
+ * text/markdown
159
+ * text/latex
160
+ * application/json
161
+ * application/javascript
162
+ * application/pdf
163
+ * image/png
164
+ * image/jpeg
165
+ * image/svg+xml
166
+
167
+ Parameters
168
+ ----------
169
+ obj : object
170
+ The Python object whose format data will be computed.
171
+ include : list, tuple or set; optional
172
+ A list of format type strings (MIME types) to include in the
173
+ format data dict. If this is set *only* the format types included
174
+ in this list will be computed.
175
+ exclude : list, tuple or set; optional
176
+ A list of format type string (MIME types) to exclude in the format
177
+ data dict. If this is set all format types will be computed,
178
+ except for those included in this argument.
179
+ Mimetypes present in exclude will take precedence over the ones in include
180
+
181
+ Returns
182
+ -------
183
+ (format_dict, metadata_dict) : tuple of two dicts
184
+ format_dict is a dictionary of key/value pairs, one of each format that was
185
+ generated for the object. The keys are the format types, which
186
+ will usually be MIME type strings and the values and JSON'able
187
+ data structure containing the raw data for the representation in
188
+ that format.
189
+
190
+ metadata_dict is a dictionary of metadata about each mime-type output.
191
+ Its keys will be a strict subset of the keys in format_dict.
192
+
193
+ Notes
194
+ -----
195
+ If an object implement `_repr_mimebundle_` as well as various
196
+ `_repr_*_`, the data returned by `_repr_mimebundle_` will take
197
+ precedence and the corresponding `_repr_*_` for this mimetype will
198
+ not be called.
199
+
200
+ """
201
+ format_dict = {}
202
+ md_dict = {}
203
+
204
+ if self.ipython_display_formatter(obj):
205
+ # object handled itself, don't proceed
206
+ return {}, {}
207
+
208
+ format_dict, md_dict = self.mimebundle_formatter(obj, include=include, exclude=exclude)
209
+
210
+ if format_dict or md_dict:
211
+ if include:
212
+ format_dict = {k:v for k,v in format_dict.items() if k in include}
213
+ md_dict = {k:v for k,v in md_dict.items() if k in include}
214
+ if exclude:
215
+ format_dict = {k:v for k,v in format_dict.items() if k not in exclude}
216
+ md_dict = {k:v for k,v in md_dict.items() if k not in exclude}
217
+
218
+ for format_type, formatter in self.formatters.items():
219
+ if format_type in format_dict:
220
+ # already got it from mimebundle, maybe don't render again.
221
+ # exception: manually registered per-mime renderer
222
+ # check priority:
223
+ # 1. user-registered per-mime formatter
224
+ # 2. mime-bundle (user-registered or repr method)
225
+ # 3. default per-mime formatter (e.g. repr method)
226
+ try:
227
+ formatter.lookup(obj)
228
+ except KeyError:
229
+ # no special formatter, use mime-bundle-provided value
230
+ continue
231
+ if include and format_type not in include:
232
+ continue
233
+ if exclude and format_type in exclude:
234
+ continue
235
+
236
+ md = None
237
+ try:
238
+ data = formatter(obj)
239
+ except:
240
+ # FIXME: log the exception
241
+ raise
242
+
243
+ # formatters can return raw data or (data, metadata)
244
+ if isinstance(data, tuple) and len(data) == 2:
245
+ data, md = data
246
+
247
+ if data is not None:
248
+ format_dict[format_type] = data
249
+ if md is not None:
250
+ md_dict[format_type] = md
251
+ return format_dict, md_dict
252
+
253
+ @property
254
+ def format_types(self):
255
+ """Return the format types (MIME types) of the active formatters."""
256
+ return list(self.formatters.keys())
257
+
258
+
259
+ #-----------------------------------------------------------------------------
260
+ # Formatters for specific format types (text, html, svg, etc.)
261
+ #-----------------------------------------------------------------------------
262
+
263
+
264
+ def _safe_repr(obj):
265
+ """Try to return a repr of an object
266
+
267
+ always returns a string, at least.
268
+ """
269
+ try:
270
+ return repr(obj)
271
+ except Exception as e:
272
+ return "un-repr-able object (%r)" % e
273
+
274
+
275
+ class FormatterWarning(UserWarning):
276
+ """Warning class for errors in formatters"""
277
+
278
+ @decorator
279
+ def catch_format_error(method, self, *args, **kwargs):
280
+ """show traceback on failed format call"""
281
+ try:
282
+ r = method(self, *args, **kwargs)
283
+ except NotImplementedError:
284
+ # don't warn on NotImplementedErrors
285
+ return self._check_return(None, args[0])
286
+ except Exception:
287
+ exc_info = sys.exc_info()
288
+ ip = get_ipython()
289
+ if ip is not None:
290
+ ip.showtraceback(exc_info)
291
+ else:
292
+ traceback.print_exception(*exc_info)
293
+ return self._check_return(None, args[0])
294
+ return self._check_return(r, args[0])
295
+
296
+
297
+ class FormatterABC(metaclass=abc.ABCMeta):
298
+ """ Abstract base class for Formatters.
299
+
300
+ A formatter is a callable class that is responsible for computing the
301
+ raw format data for a particular format type (MIME type). For example,
302
+ an HTML formatter would have a format type of `text/html` and would return
303
+ the HTML representation of the object when called.
304
+ """
305
+
306
+ # The format type of the data returned, usually a MIME type.
307
+ format_type = 'text/plain'
308
+
309
+ # Is the formatter enabled...
310
+ enabled = True
311
+
312
+ @abc.abstractmethod
313
+ def __call__(self, obj):
314
+ """Return a JSON'able representation of the object.
315
+
316
+ If the object cannot be formatted by this formatter,
317
+ warn and return None.
318
+ """
319
+ return repr(obj)
320
+
321
+
322
+ def _mod_name_key(typ):
323
+ """Return a (__module__, __name__) tuple for a type.
324
+
325
+ Used as key in Formatter.deferred_printers.
326
+ """
327
+ module = getattr(typ, '__module__', None)
328
+ name = getattr(typ, '__name__', None)
329
+ return (module, name)
330
+
331
+
332
+ def _get_type(obj):
333
+ """Return the type of an instance (old and new-style)"""
334
+ return getattr(obj, '__class__', None) or type(obj)
335
+
336
+
337
+ _raise_key_error = Sentinel(
338
+ "_raise_key_error",
339
+ __name__,
340
+ """
341
+ Special value to raise a KeyError
342
+
343
+ Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
344
+ """,
345
+ )
346
+
347
+
348
+ class BaseFormatter(Configurable):
349
+ """A base formatter class that is configurable.
350
+
351
+ This formatter should usually be used as the base class of all formatters.
352
+ It is a traited :class:`Configurable` class and includes an extensible
353
+ API for users to determine how their objects are formatted. The following
354
+ logic is used to find a function to format an given object.
355
+
356
+ 1. The object is introspected to see if it has a method with the name
357
+ :attr:`print_method`. If is does, that object is passed to that method
358
+ for formatting.
359
+ 2. If no print method is found, three internal dictionaries are consulted
360
+ to find print method: :attr:`singleton_printers`, :attr:`type_printers`
361
+ and :attr:`deferred_printers`.
362
+
363
+ Users should use these dictionaries to register functions that will be
364
+ used to compute the format data for their objects (if those objects don't
365
+ have the special print methods). The easiest way of using these
366
+ dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
367
+ methods.
368
+
369
+ If no function/callable is found to compute the format data, ``None`` is
370
+ returned and this format type is not used.
371
+ """
372
+
373
+ format_type = Unicode("text/plain")
374
+ _return_type: Any = str
375
+
376
+ enabled = Bool(True).tag(config=True)
377
+
378
+ print_method = ObjectName('__repr__')
379
+
380
+ # The singleton printers.
381
+ # Maps the IDs of the builtin singleton objects to the format functions.
382
+ singleton_printers = Dict().tag(config=True)
383
+
384
+ # The type-specific printers.
385
+ # Map type objects to the format functions.
386
+ type_printers = Dict().tag(config=True)
387
+
388
+ # The deferred-import type-specific printers.
389
+ # Map (modulename, classname) pairs to the format functions.
390
+ deferred_printers = Dict().tag(config=True)
391
+
392
+ @catch_format_error
393
+ def __call__(self, obj):
394
+ """Compute the format for an object."""
395
+ if self.enabled:
396
+ # lookup registered printer
397
+ try:
398
+ printer = self.lookup(obj)
399
+ except KeyError:
400
+ pass
401
+ else:
402
+ return printer(obj)
403
+ # Finally look for special method names
404
+ method = get_real_method(obj, self.print_method)
405
+ if method is not None:
406
+ return method()
407
+ return None
408
+ else:
409
+ return None
410
+
411
+ def __contains__(self, typ):
412
+ """map in to lookup_by_type"""
413
+ try:
414
+ self.lookup_by_type(typ)
415
+ except KeyError:
416
+ return False
417
+ else:
418
+ return True
419
+
420
+ def _check_return(self, r, obj):
421
+ """Check that a return value is appropriate
422
+
423
+ Return the value if so, None otherwise, warning if invalid.
424
+ """
425
+ if r is None or isinstance(r, self._return_type) or \
426
+ (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
427
+ return r
428
+ else:
429
+ warnings.warn(
430
+ "%s formatter returned invalid type %s (expected %s) for object: %s" % \
431
+ (self.format_type, type(r), self._return_type, _safe_repr(obj)),
432
+ FormatterWarning
433
+ )
434
+
435
+ def lookup(self, obj):
436
+ """Look up the formatter for a given instance.
437
+
438
+ Parameters
439
+ ----------
440
+ obj : object instance
441
+
442
+ Returns
443
+ -------
444
+ f : callable
445
+ The registered formatting callable for the type.
446
+
447
+ Raises
448
+ ------
449
+ KeyError if the type has not been registered.
450
+ """
451
+ # look for singleton first
452
+ obj_id = id(obj)
453
+ if obj_id in self.singleton_printers:
454
+ return self.singleton_printers[obj_id]
455
+ # then lookup by type
456
+ return self.lookup_by_type(_get_type(obj))
457
+
458
+ def lookup_by_type(self, typ):
459
+ """Look up the registered formatter for a type.
460
+
461
+ Parameters
462
+ ----------
463
+ typ : type or '__module__.__name__' string for a type
464
+
465
+ Returns
466
+ -------
467
+ f : callable
468
+ The registered formatting callable for the type.
469
+
470
+ Raises
471
+ ------
472
+ KeyError if the type has not been registered.
473
+ """
474
+ if isinstance(typ, str):
475
+ typ_key = tuple(typ.rsplit('.',1))
476
+ if typ_key not in self.deferred_printers:
477
+ # We may have it cached in the type map. We will have to
478
+ # iterate over all of the types to check.
479
+ for cls in self.type_printers:
480
+ if _mod_name_key(cls) == typ_key:
481
+ return self.type_printers[cls]
482
+ else:
483
+ return self.deferred_printers[typ_key]
484
+ else:
485
+ for cls in pretty._get_mro(typ):
486
+ if cls in self.type_printers or self._in_deferred_types(cls):
487
+ return self.type_printers[cls]
488
+
489
+ # If we have reached here, the lookup failed.
490
+ raise KeyError("No registered printer for {0!r}".format(typ))
491
+
492
+ def for_type(self, typ, func=None):
493
+ """Add a format function for a given type.
494
+
495
+ Parameters
496
+ ----------
497
+ typ : type or '__module__.__name__' string for a type
498
+ The class of the object that will be formatted using `func`.
499
+
500
+ func : callable
501
+ A callable for computing the format data.
502
+ `func` will be called with the object to be formatted,
503
+ and will return the raw data in this formatter's format.
504
+ Subclasses may use a different call signature for the
505
+ `func` argument.
506
+
507
+ If `func` is None or not specified, there will be no change,
508
+ only returning the current value.
509
+
510
+ Returns
511
+ -------
512
+ oldfunc : callable
513
+ The currently registered callable.
514
+ If you are registering a new formatter,
515
+ this will be the previous value (to enable restoring later).
516
+ """
517
+ # if string given, interpret as 'pkg.module.class_name'
518
+ if isinstance(typ, str):
519
+ type_module, type_name = typ.rsplit('.', 1)
520
+ return self.for_type_by_name(type_module, type_name, func)
521
+
522
+ try:
523
+ oldfunc = self.lookup_by_type(typ)
524
+ except KeyError:
525
+ oldfunc = None
526
+
527
+ if func is not None:
528
+ self.type_printers[typ] = func
529
+
530
+ return oldfunc
531
+
532
+ def for_type_by_name(self, type_module, type_name, func=None):
533
+ """Add a format function for a type specified by the full dotted
534
+ module and name of the type, rather than the type of the object.
535
+
536
+ Parameters
537
+ ----------
538
+ type_module : str
539
+ The full dotted name of the module the type is defined in, like
540
+ ``numpy``.
541
+
542
+ type_name : str
543
+ The name of the type (the class name), like ``dtype``
544
+
545
+ func : callable
546
+ A callable for computing the format data.
547
+ `func` will be called with the object to be formatted,
548
+ and will return the raw data in this formatter's format.
549
+ Subclasses may use a different call signature for the
550
+ `func` argument.
551
+
552
+ If `func` is None or unspecified, there will be no change,
553
+ only returning the current value.
554
+
555
+ Returns
556
+ -------
557
+ oldfunc : callable
558
+ The currently registered callable.
559
+ If you are registering a new formatter,
560
+ this will be the previous value (to enable restoring later).
561
+ """
562
+ key = (type_module, type_name)
563
+
564
+ try:
565
+ oldfunc = self.lookup_by_type("%s.%s" % key)
566
+ except KeyError:
567
+ oldfunc = None
568
+
569
+ if func is not None:
570
+ self.deferred_printers[key] = func
571
+ return oldfunc
572
+
573
+ def pop(self, typ, default=_raise_key_error):
574
+ """Pop a formatter for the given type.
575
+
576
+ Parameters
577
+ ----------
578
+ typ : type or '__module__.__name__' string for a type
579
+ default : object
580
+ value to be returned if no formatter is registered for typ.
581
+
582
+ Returns
583
+ -------
584
+ obj : object
585
+ The last registered object for the type.
586
+
587
+ Raises
588
+ ------
589
+ KeyError if the type is not registered and default is not specified.
590
+ """
591
+
592
+ if isinstance(typ, str):
593
+ typ_key = tuple(typ.rsplit('.',1))
594
+ if typ_key not in self.deferred_printers:
595
+ # We may have it cached in the type map. We will have to
596
+ # iterate over all of the types to check.
597
+ for cls in self.type_printers:
598
+ if _mod_name_key(cls) == typ_key:
599
+ old = self.type_printers.pop(cls)
600
+ break
601
+ else:
602
+ old = default
603
+ else:
604
+ old = self.deferred_printers.pop(typ_key)
605
+ else:
606
+ if typ in self.type_printers:
607
+ old = self.type_printers.pop(typ)
608
+ else:
609
+ old = self.deferred_printers.pop(_mod_name_key(typ), default)
610
+ if old is _raise_key_error:
611
+ raise KeyError("No registered value for {0!r}".format(typ))
612
+ return old
613
+
614
+ def _in_deferred_types(self, cls):
615
+ """
616
+ Check if the given class is specified in the deferred type registry.
617
+
618
+ Successful matches will be moved to the regular type registry for future use.
619
+ """
620
+ mod = getattr(cls, '__module__', None)
621
+ name = getattr(cls, '__name__', None)
622
+ key = (mod, name)
623
+ if key in self.deferred_printers:
624
+ # Move the printer over to the regular registry.
625
+ printer = self.deferred_printers.pop(key)
626
+ self.type_printers[cls] = printer
627
+ return True
628
+ return False
629
+
630
+
631
+ class PlainTextFormatter(BaseFormatter):
632
+ """The default pretty-printer.
633
+
634
+ This uses :mod:`IPython.lib.pretty` to compute the format data of
635
+ the object. If the object cannot be pretty printed, :func:`repr` is used.
636
+ See the documentation of :mod:`IPython.lib.pretty` for details on
637
+ how to write pretty printers. Here is a simple example::
638
+
639
+ def dtype_pprinter(obj, p, cycle):
640
+ if cycle:
641
+ return p.text('dtype(...)')
642
+ if hasattr(obj, 'fields'):
643
+ if obj.fields is None:
644
+ p.text(repr(obj))
645
+ else:
646
+ p.begin_group(7, 'dtype([')
647
+ for i, field in enumerate(obj.descr):
648
+ if i > 0:
649
+ p.text(',')
650
+ p.breakable()
651
+ p.pretty(field)
652
+ p.end_group(7, '])')
653
+ """
654
+
655
+ # The format type of data returned.
656
+ format_type = Unicode('text/plain')
657
+
658
+ # This subclass ignores this attribute as it always need to return
659
+ # something.
660
+ enabled = Bool(True).tag(config=False)
661
+
662
+ max_seq_length = Integer(pretty.MAX_SEQ_LENGTH,
663
+ help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
664
+
665
+ Set to 0 to disable truncation.
666
+ """,
667
+ ).tag(config=True)
668
+
669
+ # Look for a _repr_pretty_ methods to use for pretty printing.
670
+ print_method = ObjectName('_repr_pretty_')
671
+
672
+ # Whether to pretty-print or not.
673
+ pprint = Bool(True).tag(config=True)
674
+
675
+ # Whether to be verbose or not.
676
+ verbose = Bool(False).tag(config=True)
677
+
678
+ # The maximum width.
679
+ max_width = Integer(79).tag(config=True)
680
+
681
+ # The newline character.
682
+ newline = Unicode('\n').tag(config=True)
683
+
684
+ # format-string for pprinting floats
685
+ float_format = Unicode('%r')
686
+ # setter for float precision, either int or direct format-string
687
+ float_precision = CUnicode('').tag(config=True)
688
+
689
+ @observe('float_precision')
690
+ def _float_precision_changed(self, change):
691
+ """float_precision changed, set float_format accordingly.
692
+
693
+ float_precision can be set by int or str.
694
+ This will set float_format, after interpreting input.
695
+ If numpy has been imported, numpy print precision will also be set.
696
+
697
+ integer `n` sets format to '%.nf', otherwise, format set directly.
698
+
699
+ An empty string returns to defaults (repr for float, 8 for numpy).
700
+
701
+ This parameter can be set via the '%precision' magic.
702
+ """
703
+ new = change['new']
704
+ if '%' in new:
705
+ # got explicit format string
706
+ fmt = new
707
+ try:
708
+ fmt%3.14159
709
+ except Exception as e:
710
+ raise ValueError("Precision must be int or format string, not %r"%new) from e
711
+ elif new:
712
+ # otherwise, should be an int
713
+ try:
714
+ i = int(new)
715
+ assert i >= 0
716
+ except ValueError as e:
717
+ raise ValueError("Precision must be int or format string, not %r"%new) from e
718
+ except AssertionError as e:
719
+ raise ValueError("int precision must be non-negative, not %r"%i) from e
720
+
721
+ fmt = '%%.%if'%i
722
+ if 'numpy' in sys.modules:
723
+ # set numpy precision if it has been imported
724
+ import numpy
725
+ numpy.set_printoptions(precision=i)
726
+ else:
727
+ # default back to repr
728
+ fmt = '%r'
729
+ if 'numpy' in sys.modules:
730
+ import numpy
731
+ # numpy default is 8
732
+ numpy.set_printoptions(precision=8)
733
+ self.float_format = fmt
734
+
735
+ # Use the default pretty printers from IPython.lib.pretty.
736
+ @default('singleton_printers')
737
+ def _singleton_printers_default(self):
738
+ return pretty._singleton_pprinters.copy()
739
+
740
+ @default('type_printers')
741
+ def _type_printers_default(self):
742
+ d = pretty._type_pprinters.copy()
743
+ d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
744
+ # if NumPy is used, set precision for its float64 type
745
+ if "numpy" in sys.modules:
746
+ import numpy
747
+
748
+ d[numpy.float64] = lambda obj, p, cycle: p.text(self.float_format % obj)
749
+ return d
750
+
751
+ @default('deferred_printers')
752
+ def _deferred_printers_default(self):
753
+ return pretty._deferred_type_pprinters.copy()
754
+
755
+ #### FormatterABC interface ####
756
+
757
+ @catch_format_error
758
+ def __call__(self, obj):
759
+ """Compute the pretty representation of the object."""
760
+ if not self.pprint:
761
+ return repr(obj)
762
+ else:
763
+ stream = StringIO()
764
+ printer = pretty.RepresentationPrinter(stream, self.verbose,
765
+ self.max_width, self.newline,
766
+ max_seq_length=self.max_seq_length,
767
+ singleton_pprinters=self.singleton_printers,
768
+ type_pprinters=self.type_printers,
769
+ deferred_pprinters=self.deferred_printers)
770
+ printer.pretty(obj)
771
+ printer.flush()
772
+ return stream.getvalue()
773
+
774
+
775
+ class HTMLFormatter(BaseFormatter):
776
+ """An HTML formatter.
777
+
778
+ To define the callables that compute the HTML representation of your
779
+ objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
780
+ or :meth:`for_type_by_name` methods to register functions that handle
781
+ this.
782
+
783
+ The return value of this formatter should be a valid HTML snippet that
784
+ could be injected into an existing DOM. It should *not* include the
785
+ ```<html>`` or ```<body>`` tags.
786
+ """
787
+ format_type = Unicode('text/html')
788
+
789
+ print_method = ObjectName('_repr_html_')
790
+
791
+
792
+ class MarkdownFormatter(BaseFormatter):
793
+ """A Markdown formatter.
794
+
795
+ To define the callables that compute the Markdown representation of your
796
+ objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
797
+ or :meth:`for_type_by_name` methods to register functions that handle
798
+ this.
799
+
800
+ The return value of this formatter should be a valid Markdown.
801
+ """
802
+ format_type = Unicode('text/markdown')
803
+
804
+ print_method = ObjectName('_repr_markdown_')
805
+
806
+ class SVGFormatter(BaseFormatter):
807
+ """An SVG formatter.
808
+
809
+ To define the callables that compute the SVG representation of your
810
+ objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
811
+ or :meth:`for_type_by_name` methods to register functions that handle
812
+ this.
813
+
814
+ The return value of this formatter should be valid SVG enclosed in
815
+ ```<svg>``` tags, that could be injected into an existing DOM. It should
816
+ *not* include the ```<html>`` or ```<body>`` tags.
817
+ """
818
+ format_type = Unicode('image/svg+xml')
819
+
820
+ print_method = ObjectName('_repr_svg_')
821
+
822
+
823
+ class PNGFormatter(BaseFormatter):
824
+ """A PNG formatter.
825
+
826
+ To define the callables that compute the PNG representation of your
827
+ objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
828
+ or :meth:`for_type_by_name` methods to register functions that handle
829
+ this.
830
+
831
+ The return value of this formatter should be raw PNG data, *not*
832
+ base64 encoded.
833
+ """
834
+ format_type = Unicode('image/png')
835
+
836
+ print_method = ObjectName('_repr_png_')
837
+
838
+ _return_type = (bytes, str)
839
+
840
+
841
+ class JPEGFormatter(BaseFormatter):
842
+ """A JPEG formatter.
843
+
844
+ To define the callables that compute the JPEG representation of your
845
+ objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
846
+ or :meth:`for_type_by_name` methods to register functions that handle
847
+ this.
848
+
849
+ The return value of this formatter should be raw JPEG data, *not*
850
+ base64 encoded.
851
+ """
852
+ format_type = Unicode('image/jpeg')
853
+
854
+ print_method = ObjectName('_repr_jpeg_')
855
+
856
+ _return_type = (bytes, str)
857
+
858
+
859
+ class LatexFormatter(BaseFormatter):
860
+ """A LaTeX formatter.
861
+
862
+ To define the callables that compute the LaTeX representation of your
863
+ objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
864
+ or :meth:`for_type_by_name` methods to register functions that handle
865
+ this.
866
+
867
+ The return value of this formatter should be a valid LaTeX equation,
868
+ enclosed in either ```$```, ```$$``` or another LaTeX equation
869
+ environment.
870
+ """
871
+ format_type = Unicode('text/latex')
872
+
873
+ print_method = ObjectName('_repr_latex_')
874
+
875
+
876
+ class JSONFormatter(BaseFormatter):
877
+ """A JSON string formatter.
878
+
879
+ To define the callables that compute the JSONable representation of
880
+ your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
881
+ or :meth:`for_type_by_name` methods to register functions that handle
882
+ this.
883
+
884
+ The return value of this formatter should be a JSONable list or dict.
885
+ JSON scalars (None, number, string) are not allowed, only dict or list containers.
886
+ """
887
+ format_type = Unicode('application/json')
888
+ _return_type = (list, dict)
889
+
890
+ print_method = ObjectName('_repr_json_')
891
+
892
+ def _check_return(self, r, obj):
893
+ """Check that a return value is appropriate
894
+
895
+ Return the value if so, None otherwise, warning if invalid.
896
+ """
897
+ if r is None:
898
+ return
899
+ md = None
900
+ if isinstance(r, tuple):
901
+ # unpack data, metadata tuple for type checking on first element
902
+ r, md = r
903
+
904
+ assert not isinstance(
905
+ r, str
906
+ ), "JSON-as-string has been deprecated since IPython < 3"
907
+
908
+ if md is not None:
909
+ # put the tuple back together
910
+ r = (r, md)
911
+ return super(JSONFormatter, self)._check_return(r, obj)
912
+
913
+
914
+ class JavascriptFormatter(BaseFormatter):
915
+ """A Javascript formatter.
916
+
917
+ To define the callables that compute the Javascript representation of
918
+ your objects, define a :meth:`_repr_javascript_` method or use the
919
+ :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
920
+ that handle this.
921
+
922
+ The return value of this formatter should be valid Javascript code and
923
+ should *not* be enclosed in ```<script>``` tags.
924
+ """
925
+ format_type = Unicode('application/javascript')
926
+
927
+ print_method = ObjectName('_repr_javascript_')
928
+
929
+
930
+ class PDFFormatter(BaseFormatter):
931
+ """A PDF formatter.
932
+
933
+ To define the callables that compute the PDF representation of your
934
+ objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
935
+ or :meth:`for_type_by_name` methods to register functions that handle
936
+ this.
937
+
938
+ The return value of this formatter should be raw PDF data, *not*
939
+ base64 encoded.
940
+ """
941
+ format_type = Unicode('application/pdf')
942
+
943
+ print_method = ObjectName('_repr_pdf_')
944
+
945
+ _return_type = (bytes, str)
946
+
947
+ class IPythonDisplayFormatter(BaseFormatter):
948
+ """An escape-hatch Formatter for objects that know how to display themselves.
949
+
950
+ To define the callables that compute the representation of your
951
+ objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
952
+ or :meth:`for_type_by_name` methods to register functions that handle
953
+ this. Unlike mime-type displays, this method should not return anything,
954
+ instead calling any appropriate display methods itself.
955
+
956
+ This display formatter has highest priority.
957
+ If it fires, no other display formatter will be called.
958
+
959
+ Prior to IPython 6.1, `_ipython_display_` was the only way to display custom mime-types
960
+ without registering a new Formatter.
961
+
962
+ IPython 6.1 introduces `_repr_mimebundle_` for displaying custom mime-types,
963
+ so `_ipython_display_` should only be used for objects that require unusual
964
+ display patterns, such as multiple display calls.
965
+ """
966
+ print_method = ObjectName('_ipython_display_')
967
+ _return_type = (type(None), bool)
968
+
969
+ @catch_format_error
970
+ def __call__(self, obj):
971
+ """Compute the format for an object."""
972
+ if self.enabled:
973
+ # lookup registered printer
974
+ try:
975
+ printer = self.lookup(obj)
976
+ except KeyError:
977
+ pass
978
+ else:
979
+ printer(obj)
980
+ return True
981
+ # Finally look for special method names
982
+ method = get_real_method(obj, self.print_method)
983
+ if method is not None:
984
+ method()
985
+ return True
986
+
987
+
988
+ class MimeBundleFormatter(BaseFormatter):
989
+ """A Formatter for arbitrary mime-types.
990
+
991
+ Unlike other `_repr_<mimetype>_` methods,
992
+ `_repr_mimebundle_` should return mime-bundle data,
993
+ either the mime-keyed `data` dictionary or the tuple `(data, metadata)`.
994
+ Any mime-type is valid.
995
+
996
+ To define the callables that compute the mime-bundle representation of your
997
+ objects, define a :meth:`_repr_mimebundle_` method or use the :meth:`for_type`
998
+ or :meth:`for_type_by_name` methods to register functions that handle
999
+ this.
1000
+
1001
+ .. versionadded:: 6.1
1002
+ """
1003
+ print_method = ObjectName('_repr_mimebundle_')
1004
+ _return_type = dict
1005
+
1006
+ def _check_return(self, r, obj):
1007
+ r = super(MimeBundleFormatter, self)._check_return(r, obj)
1008
+ # always return (data, metadata):
1009
+ if r is None:
1010
+ return {}, {}
1011
+ if not isinstance(r, tuple):
1012
+ return r, {}
1013
+ return r
1014
+
1015
+ @catch_format_error
1016
+ def __call__(self, obj, include=None, exclude=None):
1017
+ """Compute the format for an object.
1018
+
1019
+ Identical to parent's method but we pass extra parameters to the method.
1020
+
1021
+ Unlike other _repr_*_ `_repr_mimebundle_` should allow extra kwargs, in
1022
+ particular `include` and `exclude`.
1023
+ """
1024
+ if self.enabled:
1025
+ # lookup registered printer
1026
+ try:
1027
+ printer = self.lookup(obj)
1028
+ except KeyError:
1029
+ pass
1030
+ else:
1031
+ return printer(obj)
1032
+ # Finally look for special method names
1033
+ method = get_real_method(obj, self.print_method)
1034
+
1035
+ if method is not None:
1036
+ return method(include=include, exclude=exclude)
1037
+ return None
1038
+ else:
1039
+ return None
1040
+
1041
+
1042
+ FormatterABC.register(BaseFormatter)
1043
+ FormatterABC.register(PlainTextFormatter)
1044
+ FormatterABC.register(HTMLFormatter)
1045
+ FormatterABC.register(MarkdownFormatter)
1046
+ FormatterABC.register(SVGFormatter)
1047
+ FormatterABC.register(PNGFormatter)
1048
+ FormatterABC.register(PDFFormatter)
1049
+ FormatterABC.register(JPEGFormatter)
1050
+ FormatterABC.register(LatexFormatter)
1051
+ FormatterABC.register(JSONFormatter)
1052
+ FormatterABC.register(JavascriptFormatter)
1053
+ FormatterABC.register(IPythonDisplayFormatter)
1054
+ FormatterABC.register(MimeBundleFormatter)
1055
+
1056
+
1057
+ def format_display_data(obj, include=None, exclude=None):
1058
+ """Return a format data dict for an object.
1059
+
1060
+ By default all format types will be computed.
1061
+
1062
+ Parameters
1063
+ ----------
1064
+ obj : object
1065
+ The Python object whose format data will be computed.
1066
+
1067
+ Returns
1068
+ -------
1069
+ format_dict : dict
1070
+ A dictionary of key/value pairs, one or each format that was
1071
+ generated for the object. The keys are the format types, which
1072
+ will usually be MIME type strings and the values and JSON'able
1073
+ data structure containing the raw data for the representation in
1074
+ that format.
1075
+ include : list or tuple, optional
1076
+ A list of format type strings (MIME types) to include in the
1077
+ format data dict. If this is set *only* the format types included
1078
+ in this list will be computed.
1079
+ exclude : list or tuple, optional
1080
+ A list of format type string (MIME types) to exclude in the format
1081
+ data dict. If this is set all format types will be computed,
1082
+ except for those included in this argument.
1083
+ """
1084
+ from .interactiveshell import InteractiveShell
1085
+
1086
+ return InteractiveShell.instance().display_formatter.format(
1087
+ obj,
1088
+ include,
1089
+ exclude
1090
+ )
openalex_env_map/lib/python3.10/site-packages/IPython/core/getipython.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """Simple function to call to get the current InteractiveShell instance
3
+ """
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Copyright (C) 2013 The IPython Development Team
7
+ #
8
+ # Distributed under the terms of the BSD License. The full license is in
9
+ # the file COPYING, distributed as part of this software.
10
+ #-----------------------------------------------------------------------------
11
+
12
+ #-----------------------------------------------------------------------------
13
+ # Classes and functions
14
+ #-----------------------------------------------------------------------------
15
+
16
+
17
+ def get_ipython():
18
+ """Get the global InteractiveShell instance.
19
+
20
+ Returns None if no InteractiveShell instance is registered.
21
+ """
22
+ from IPython.core.interactiveshell import InteractiveShell
23
+ if InteractiveShell.initialized():
24
+ return InteractiveShell.instance()
openalex_env_map/lib/python3.10/site-packages/IPython/core/guarded_eval.py ADDED
@@ -0,0 +1,895 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from inspect import isclass, signature, Signature
2
+ from typing import (
3
+ Annotated,
4
+ AnyStr,
5
+ Callable,
6
+ Dict,
7
+ Literal,
8
+ NamedTuple,
9
+ NewType,
10
+ Optional,
11
+ Protocol,
12
+ Set,
13
+ Sequence,
14
+ Tuple,
15
+ Type,
16
+ TypeGuard,
17
+ Union,
18
+ get_args,
19
+ get_origin,
20
+ is_typeddict,
21
+ )
22
+ import ast
23
+ import builtins
24
+ import collections
25
+ import operator
26
+ import sys
27
+ from functools import cached_property
28
+ from dataclasses import dataclass, field
29
+ from types import MethodDescriptorType, ModuleType
30
+
31
+ from IPython.utils.decorators import undoc
32
+
33
+
34
+ if sys.version_info < (3, 11):
35
+ from typing_extensions import Self, LiteralString
36
+ else:
37
+ from typing import Self, LiteralString
38
+
39
+ if sys.version_info < (3, 12):
40
+ from typing_extensions import TypeAliasType
41
+ else:
42
+ from typing import TypeAliasType
43
+
44
+
45
+ @undoc
46
+ class HasGetItem(Protocol):
47
+ def __getitem__(self, key) -> None: ...
48
+
49
+
50
+ @undoc
51
+ class InstancesHaveGetItem(Protocol):
52
+ def __call__(self, *args, **kwargs) -> HasGetItem: ...
53
+
54
+
55
+ @undoc
56
+ class HasGetAttr(Protocol):
57
+ def __getattr__(self, key) -> None: ...
58
+
59
+
60
+ @undoc
61
+ class DoesNotHaveGetAttr(Protocol):
62
+ pass
63
+
64
+
65
+ # By default `__getattr__` is not explicitly implemented on most objects
66
+ MayHaveGetattr = Union[HasGetAttr, DoesNotHaveGetAttr]
67
+
68
+
69
+ def _unbind_method(func: Callable) -> Union[Callable, None]:
70
+ """Get unbound method for given bound method.
71
+
72
+ Returns None if cannot get unbound method, or method is already unbound.
73
+ """
74
+ owner = getattr(func, "__self__", None)
75
+ owner_class = type(owner)
76
+ name = getattr(func, "__name__", None)
77
+ instance_dict_overrides = getattr(owner, "__dict__", None)
78
+ if (
79
+ owner is not None
80
+ and name
81
+ and (
82
+ not instance_dict_overrides
83
+ or (instance_dict_overrides and name not in instance_dict_overrides)
84
+ )
85
+ ):
86
+ return getattr(owner_class, name)
87
+ return None
88
+
89
+
90
+ @undoc
91
+ @dataclass
92
+ class EvaluationPolicy:
93
+ """Definition of evaluation policy."""
94
+
95
+ allow_locals_access: bool = False
96
+ allow_globals_access: bool = False
97
+ allow_item_access: bool = False
98
+ allow_attr_access: bool = False
99
+ allow_builtins_access: bool = False
100
+ allow_all_operations: bool = False
101
+ allow_any_calls: bool = False
102
+ allowed_calls: Set[Callable] = field(default_factory=set)
103
+
104
+ def can_get_item(self, value, item):
105
+ return self.allow_item_access
106
+
107
+ def can_get_attr(self, value, attr):
108
+ return self.allow_attr_access
109
+
110
+ def can_operate(self, dunders: Tuple[str, ...], a, b=None):
111
+ if self.allow_all_operations:
112
+ return True
113
+
114
+ def can_call(self, func):
115
+ if self.allow_any_calls:
116
+ return True
117
+
118
+ if func in self.allowed_calls:
119
+ return True
120
+
121
+ owner_method = _unbind_method(func)
122
+
123
+ if owner_method and owner_method in self.allowed_calls:
124
+ return True
125
+
126
+
127
+ def _get_external(module_name: str, access_path: Sequence[str]):
128
+ """Get value from external module given a dotted access path.
129
+
130
+ Raises:
131
+ * `KeyError` if module is removed not found, and
132
+ * `AttributeError` if access path does not match an exported object
133
+ """
134
+ member_type = sys.modules[module_name]
135
+ for attr in access_path:
136
+ member_type = getattr(member_type, attr)
137
+ return member_type
138
+
139
+
140
+ def _has_original_dunder_external(
141
+ value,
142
+ module_name: str,
143
+ access_path: Sequence[str],
144
+ method_name: str,
145
+ ):
146
+ if module_name not in sys.modules:
147
+ # LBYLB as it is faster
148
+ return False
149
+ try:
150
+ member_type = _get_external(module_name, access_path)
151
+ value_type = type(value)
152
+ if type(value) == member_type:
153
+ return True
154
+ if method_name == "__getattribute__":
155
+ # we have to short-circuit here due to an unresolved issue in
156
+ # `isinstance` implementation: https://bugs.python.org/issue32683
157
+ return False
158
+ if isinstance(value, member_type):
159
+ method = getattr(value_type, method_name, None)
160
+ member_method = getattr(member_type, method_name, None)
161
+ if member_method == method:
162
+ return True
163
+ except (AttributeError, KeyError):
164
+ return False
165
+
166
+
167
+ def _has_original_dunder(
168
+ value, allowed_types, allowed_methods, allowed_external, method_name
169
+ ):
170
+ # note: Python ignores `__getattr__`/`__getitem__` on instances,
171
+ # we only need to check at class level
172
+ value_type = type(value)
173
+
174
+ # strict type check passes → no need to check method
175
+ if value_type in allowed_types:
176
+ return True
177
+
178
+ method = getattr(value_type, method_name, None)
179
+
180
+ if method is None:
181
+ return None
182
+
183
+ if method in allowed_methods:
184
+ return True
185
+
186
+ for module_name, *access_path in allowed_external:
187
+ if _has_original_dunder_external(value, module_name, access_path, method_name):
188
+ return True
189
+
190
+ return False
191
+
192
+
193
+ @undoc
194
+ @dataclass
195
+ class SelectivePolicy(EvaluationPolicy):
196
+ allowed_getitem: Set[InstancesHaveGetItem] = field(default_factory=set)
197
+ allowed_getitem_external: Set[Tuple[str, ...]] = field(default_factory=set)
198
+
199
+ allowed_getattr: Set[MayHaveGetattr] = field(default_factory=set)
200
+ allowed_getattr_external: Set[Tuple[str, ...]] = field(default_factory=set)
201
+
202
+ allowed_operations: Set = field(default_factory=set)
203
+ allowed_operations_external: Set[Tuple[str, ...]] = field(default_factory=set)
204
+
205
+ _operation_methods_cache: Dict[str, Set[Callable]] = field(
206
+ default_factory=dict, init=False
207
+ )
208
+
209
+ def can_get_attr(self, value, attr):
210
+ has_original_attribute = _has_original_dunder(
211
+ value,
212
+ allowed_types=self.allowed_getattr,
213
+ allowed_methods=self._getattribute_methods,
214
+ allowed_external=self.allowed_getattr_external,
215
+ method_name="__getattribute__",
216
+ )
217
+ has_original_attr = _has_original_dunder(
218
+ value,
219
+ allowed_types=self.allowed_getattr,
220
+ allowed_methods=self._getattr_methods,
221
+ allowed_external=self.allowed_getattr_external,
222
+ method_name="__getattr__",
223
+ )
224
+
225
+ accept = False
226
+
227
+ # Many objects do not have `__getattr__`, this is fine.
228
+ if has_original_attr is None and has_original_attribute:
229
+ accept = True
230
+ else:
231
+ # Accept objects without modifications to `__getattr__` and `__getattribute__`
232
+ accept = has_original_attr and has_original_attribute
233
+
234
+ if accept:
235
+ # We still need to check for overridden properties.
236
+
237
+ value_class = type(value)
238
+ if not hasattr(value_class, attr):
239
+ return True
240
+
241
+ class_attr_val = getattr(value_class, attr)
242
+ is_property = isinstance(class_attr_val, property)
243
+
244
+ if not is_property:
245
+ return True
246
+
247
+ # Properties in allowed types are ok (although we do not include any
248
+ # properties in our default allow list currently).
249
+ if type(value) in self.allowed_getattr:
250
+ return True # pragma: no cover
251
+
252
+ # Properties in subclasses of allowed types may be ok if not changed
253
+ for module_name, *access_path in self.allowed_getattr_external:
254
+ try:
255
+ external_class = _get_external(module_name, access_path)
256
+ external_class_attr_val = getattr(external_class, attr)
257
+ except (KeyError, AttributeError):
258
+ return False # pragma: no cover
259
+ return class_attr_val == external_class_attr_val
260
+
261
+ return False
262
+
263
+ def can_get_item(self, value, item):
264
+ """Allow accessing `__getiitem__` of allow-listed instances unless it was not modified."""
265
+ return _has_original_dunder(
266
+ value,
267
+ allowed_types=self.allowed_getitem,
268
+ allowed_methods=self._getitem_methods,
269
+ allowed_external=self.allowed_getitem_external,
270
+ method_name="__getitem__",
271
+ )
272
+
273
+ def can_operate(self, dunders: Tuple[str, ...], a, b=None):
274
+ objects = [a]
275
+ if b is not None:
276
+ objects.append(b)
277
+ return all(
278
+ [
279
+ _has_original_dunder(
280
+ obj,
281
+ allowed_types=self.allowed_operations,
282
+ allowed_methods=self._operator_dunder_methods(dunder),
283
+ allowed_external=self.allowed_operations_external,
284
+ method_name=dunder,
285
+ )
286
+ for dunder in dunders
287
+ for obj in objects
288
+ ]
289
+ )
290
+
291
+ def _operator_dunder_methods(self, dunder: str) -> Set[Callable]:
292
+ if dunder not in self._operation_methods_cache:
293
+ self._operation_methods_cache[dunder] = self._safe_get_methods(
294
+ self.allowed_operations, dunder
295
+ )
296
+ return self._operation_methods_cache[dunder]
297
+
298
+ @cached_property
299
+ def _getitem_methods(self) -> Set[Callable]:
300
+ return self._safe_get_methods(self.allowed_getitem, "__getitem__")
301
+
302
+ @cached_property
303
+ def _getattr_methods(self) -> Set[Callable]:
304
+ return self._safe_get_methods(self.allowed_getattr, "__getattr__")
305
+
306
+ @cached_property
307
+ def _getattribute_methods(self) -> Set[Callable]:
308
+ return self._safe_get_methods(self.allowed_getattr, "__getattribute__")
309
+
310
+ def _safe_get_methods(self, classes, name) -> Set[Callable]:
311
+ return {
312
+ method
313
+ for class_ in classes
314
+ for method in [getattr(class_, name, None)]
315
+ if method
316
+ }
317
+
318
+
319
+ class _DummyNamedTuple(NamedTuple):
320
+ """Used internally to retrieve methods of named tuple instance."""
321
+
322
+
323
+ class EvaluationContext(NamedTuple):
324
+ #: Local namespace
325
+ locals: dict
326
+ #: Global namespace
327
+ globals: dict
328
+ #: Evaluation policy identifier
329
+ evaluation: Literal["forbidden", "minimal", "limited", "unsafe", "dangerous"] = (
330
+ "forbidden"
331
+ )
332
+ #: Whether the evaluation of code takes place inside of a subscript.
333
+ #: Useful for evaluating ``:-1, 'col'`` in ``df[:-1, 'col']``.
334
+ in_subscript: bool = False
335
+
336
+
337
+ class _IdentitySubscript:
338
+ """Returns the key itself when item is requested via subscript."""
339
+
340
+ def __getitem__(self, key):
341
+ return key
342
+
343
+
344
+ IDENTITY_SUBSCRIPT = _IdentitySubscript()
345
+ SUBSCRIPT_MARKER = "__SUBSCRIPT_SENTINEL__"
346
+ UNKNOWN_SIGNATURE = Signature()
347
+ NOT_EVALUATED = object()
348
+
349
+
350
+ class GuardRejection(Exception):
351
+ """Exception raised when guard rejects evaluation attempt."""
352
+
353
+ pass
354
+
355
+
356
+ def guarded_eval(code: str, context: EvaluationContext):
357
+ """Evaluate provided code in the evaluation context.
358
+
359
+ If evaluation policy given by context is set to ``forbidden``
360
+ no evaluation will be performed; if it is set to ``dangerous``
361
+ standard :func:`eval` will be used; finally, for any other,
362
+ policy :func:`eval_node` will be called on parsed AST.
363
+ """
364
+ locals_ = context.locals
365
+
366
+ if context.evaluation == "forbidden":
367
+ raise GuardRejection("Forbidden mode")
368
+
369
+ # note: not using `ast.literal_eval` as it does not implement
370
+ # getitem at all, for example it fails on simple `[0][1]`
371
+
372
+ if context.in_subscript:
373
+ # syntactic sugar for ellipsis (:) is only available in subscripts
374
+ # so we need to trick the ast parser into thinking that we have
375
+ # a subscript, but we need to be able to later recognise that we did
376
+ # it so we can ignore the actual __getitem__ operation
377
+ if not code:
378
+ return tuple()
379
+ locals_ = locals_.copy()
380
+ locals_[SUBSCRIPT_MARKER] = IDENTITY_SUBSCRIPT
381
+ code = SUBSCRIPT_MARKER + "[" + code + "]"
382
+ context = EvaluationContext(**{**context._asdict(), **{"locals": locals_}})
383
+
384
+ if context.evaluation == "dangerous":
385
+ return eval(code, context.globals, context.locals)
386
+
387
+ expression = ast.parse(code, mode="eval")
388
+
389
+ return eval_node(expression, context)
390
+
391
+
392
+ BINARY_OP_DUNDERS: Dict[Type[ast.operator], Tuple[str]] = {
393
+ ast.Add: ("__add__",),
394
+ ast.Sub: ("__sub__",),
395
+ ast.Mult: ("__mul__",),
396
+ ast.Div: ("__truediv__",),
397
+ ast.FloorDiv: ("__floordiv__",),
398
+ ast.Mod: ("__mod__",),
399
+ ast.Pow: ("__pow__",),
400
+ ast.LShift: ("__lshift__",),
401
+ ast.RShift: ("__rshift__",),
402
+ ast.BitOr: ("__or__",),
403
+ ast.BitXor: ("__xor__",),
404
+ ast.BitAnd: ("__and__",),
405
+ ast.MatMult: ("__matmul__",),
406
+ }
407
+
408
+ COMP_OP_DUNDERS: Dict[Type[ast.cmpop], Tuple[str, ...]] = {
409
+ ast.Eq: ("__eq__",),
410
+ ast.NotEq: ("__ne__", "__eq__"),
411
+ ast.Lt: ("__lt__", "__gt__"),
412
+ ast.LtE: ("__le__", "__ge__"),
413
+ ast.Gt: ("__gt__", "__lt__"),
414
+ ast.GtE: ("__ge__", "__le__"),
415
+ ast.In: ("__contains__",),
416
+ # Note: ast.Is, ast.IsNot, ast.NotIn are handled specially
417
+ }
418
+
419
+ UNARY_OP_DUNDERS: Dict[Type[ast.unaryop], Tuple[str, ...]] = {
420
+ ast.USub: ("__neg__",),
421
+ ast.UAdd: ("__pos__",),
422
+ # we have to check both __inv__ and __invert__!
423
+ ast.Invert: ("__invert__", "__inv__"),
424
+ ast.Not: ("__not__",),
425
+ }
426
+
427
+
428
+ class ImpersonatingDuck:
429
+ """A dummy class used to create objects of other classes without calling their ``__init__``"""
430
+
431
+ # no-op: override __class__ to impersonate
432
+
433
+
434
+ class _Duck:
435
+ """A dummy class used to create objects pretending to have given attributes"""
436
+
437
+ def __init__(self, attributes: Optional[dict] = None, items: Optional[dict] = None):
438
+ self.attributes = attributes or {}
439
+ self.items = items or {}
440
+
441
+ def __getattr__(self, attr: str):
442
+ return self.attributes[attr]
443
+
444
+ def __hasattr__(self, attr: str):
445
+ return attr in self.attributes
446
+
447
+ def __dir__(self):
448
+ return [*dir(super), *self.attributes]
449
+
450
+ def __getitem__(self, key: str):
451
+ return self.items[key]
452
+
453
+ def __hasitem__(self, key: str):
454
+ return self.items[key]
455
+
456
+ def _ipython_key_completions_(self):
457
+ return self.items.keys()
458
+
459
+
460
+ def _find_dunder(node_op, dunders) -> Union[Tuple[str, ...], None]:
461
+ dunder = None
462
+ for op, candidate_dunder in dunders.items():
463
+ if isinstance(node_op, op):
464
+ dunder = candidate_dunder
465
+ return dunder
466
+
467
+
468
+ def eval_node(node: Union[ast.AST, None], context: EvaluationContext):
469
+ """Evaluate AST node in provided context.
470
+
471
+ Applies evaluation restrictions defined in the context. Currently does not support evaluation of functions with keyword arguments.
472
+
473
+ Does not evaluate actions that always have side effects:
474
+
475
+ - class definitions (``class sth: ...``)
476
+ - function definitions (``def sth: ...``)
477
+ - variable assignments (``x = 1``)
478
+ - augmented assignments (``x += 1``)
479
+ - deletions (``del x``)
480
+
481
+ Does not evaluate operations which do not return values:
482
+
483
+ - assertions (``assert x``)
484
+ - pass (``pass``)
485
+ - imports (``import x``)
486
+ - control flow:
487
+
488
+ - conditionals (``if x:``) except for ternary IfExp (``a if x else b``)
489
+ - loops (``for`` and ``while``)
490
+ - exception handling
491
+
492
+ The purpose of this function is to guard against unwanted side-effects;
493
+ it does not give guarantees on protection from malicious code execution.
494
+ """
495
+ policy = EVALUATION_POLICIES[context.evaluation]
496
+ if node is None:
497
+ return None
498
+ if isinstance(node, ast.Expression):
499
+ return eval_node(node.body, context)
500
+ if isinstance(node, ast.BinOp):
501
+ left = eval_node(node.left, context)
502
+ right = eval_node(node.right, context)
503
+ dunders = _find_dunder(node.op, BINARY_OP_DUNDERS)
504
+ if dunders:
505
+ if policy.can_operate(dunders, left, right):
506
+ return getattr(left, dunders[0])(right)
507
+ else:
508
+ raise GuardRejection(
509
+ f"Operation (`{dunders}`) for",
510
+ type(left),
511
+ f"not allowed in {context.evaluation} mode",
512
+ )
513
+ if isinstance(node, ast.Compare):
514
+ left = eval_node(node.left, context)
515
+ all_true = True
516
+ negate = False
517
+ for op, right in zip(node.ops, node.comparators):
518
+ right = eval_node(right, context)
519
+ dunder = None
520
+ dunders = _find_dunder(op, COMP_OP_DUNDERS)
521
+ if not dunders:
522
+ if isinstance(op, ast.NotIn):
523
+ dunders = COMP_OP_DUNDERS[ast.In]
524
+ negate = True
525
+ if isinstance(op, ast.Is):
526
+ dunder = "is_"
527
+ if isinstance(op, ast.IsNot):
528
+ dunder = "is_"
529
+ negate = True
530
+ if not dunder and dunders:
531
+ dunder = dunders[0]
532
+ if dunder:
533
+ a, b = (right, left) if dunder == "__contains__" else (left, right)
534
+ if dunder == "is_" or dunders and policy.can_operate(dunders, a, b):
535
+ result = getattr(operator, dunder)(a, b)
536
+ if negate:
537
+ result = not result
538
+ if not result:
539
+ all_true = False
540
+ left = right
541
+ else:
542
+ raise GuardRejection(
543
+ f"Comparison (`{dunder}`) for",
544
+ type(left),
545
+ f"not allowed in {context.evaluation} mode",
546
+ )
547
+ else:
548
+ raise ValueError(
549
+ f"Comparison `{dunder}` not supported"
550
+ ) # pragma: no cover
551
+ return all_true
552
+ if isinstance(node, ast.Constant):
553
+ return node.value
554
+ if isinstance(node, ast.Tuple):
555
+ return tuple(eval_node(e, context) for e in node.elts)
556
+ if isinstance(node, ast.List):
557
+ return [eval_node(e, context) for e in node.elts]
558
+ if isinstance(node, ast.Set):
559
+ return {eval_node(e, context) for e in node.elts}
560
+ if isinstance(node, ast.Dict):
561
+ return dict(
562
+ zip(
563
+ [eval_node(k, context) for k in node.keys],
564
+ [eval_node(v, context) for v in node.values],
565
+ )
566
+ )
567
+ if isinstance(node, ast.Slice):
568
+ return slice(
569
+ eval_node(node.lower, context),
570
+ eval_node(node.upper, context),
571
+ eval_node(node.step, context),
572
+ )
573
+ if isinstance(node, ast.UnaryOp):
574
+ value = eval_node(node.operand, context)
575
+ dunders = _find_dunder(node.op, UNARY_OP_DUNDERS)
576
+ if dunders:
577
+ if policy.can_operate(dunders, value):
578
+ return getattr(value, dunders[0])()
579
+ else:
580
+ raise GuardRejection(
581
+ f"Operation (`{dunders}`) for",
582
+ type(value),
583
+ f"not allowed in {context.evaluation} mode",
584
+ )
585
+ if isinstance(node, ast.Subscript):
586
+ value = eval_node(node.value, context)
587
+ slice_ = eval_node(node.slice, context)
588
+ if policy.can_get_item(value, slice_):
589
+ return value[slice_]
590
+ raise GuardRejection(
591
+ "Subscript access (`__getitem__`) for",
592
+ type(value), # not joined to avoid calling `repr`
593
+ f" not allowed in {context.evaluation} mode",
594
+ )
595
+ if isinstance(node, ast.Name):
596
+ return _eval_node_name(node.id, context)
597
+ if isinstance(node, ast.Attribute):
598
+ value = eval_node(node.value, context)
599
+ if policy.can_get_attr(value, node.attr):
600
+ return getattr(value, node.attr)
601
+ raise GuardRejection(
602
+ "Attribute access (`__getattr__`) for",
603
+ type(value), # not joined to avoid calling `repr`
604
+ f"not allowed in {context.evaluation} mode",
605
+ )
606
+ if isinstance(node, ast.IfExp):
607
+ test = eval_node(node.test, context)
608
+ if test:
609
+ return eval_node(node.body, context)
610
+ else:
611
+ return eval_node(node.orelse, context)
612
+ if isinstance(node, ast.Call):
613
+ func = eval_node(node.func, context)
614
+ if policy.can_call(func) and not node.keywords:
615
+ args = [eval_node(arg, context) for arg in node.args]
616
+ return func(*args)
617
+ if isclass(func):
618
+ # this code path gets entered when calling class e.g. `MyClass()`
619
+ # or `my_instance.__class__()` - in both cases `func` is `MyClass`.
620
+ # Should return `MyClass` if `__new__` is not overridden,
621
+ # otherwise whatever `__new__` return type is.
622
+ overridden_return_type = _eval_return_type(func.__new__, node, context)
623
+ if overridden_return_type is not NOT_EVALUATED:
624
+ return overridden_return_type
625
+ return _create_duck_for_heap_type(func)
626
+ else:
627
+ return_type = _eval_return_type(func, node, context)
628
+ if return_type is not NOT_EVALUATED:
629
+ return return_type
630
+ raise GuardRejection(
631
+ "Call for",
632
+ func, # not joined to avoid calling `repr`
633
+ f"not allowed in {context.evaluation} mode",
634
+ )
635
+ raise ValueError("Unhandled node", ast.dump(node))
636
+
637
+
638
+ def _eval_return_type(func: Callable, node: ast.Call, context: EvaluationContext):
639
+ """Evaluate return type of a given callable function.
640
+
641
+ Returns the built-in type, a duck or NOT_EVALUATED sentinel.
642
+ """
643
+ try:
644
+ sig = signature(func)
645
+ except ValueError:
646
+ sig = UNKNOWN_SIGNATURE
647
+ # if annotation was not stringized, or it was stringized
648
+ # but resolved by signature call we know the return type
649
+ not_empty = sig.return_annotation is not Signature.empty
650
+ if not_empty:
651
+ return _resolve_annotation(sig.return_annotation, sig, func, node, context)
652
+ return NOT_EVALUATED
653
+
654
+
655
+ def _resolve_annotation(
656
+ annotation,
657
+ sig: Signature,
658
+ func: Callable,
659
+ node: ast.Call,
660
+ context: EvaluationContext,
661
+ ):
662
+ """Resolve annotation created by user with `typing` module and custom objects."""
663
+ annotation = (
664
+ _eval_node_name(annotation, context)
665
+ if isinstance(annotation, str)
666
+ else annotation
667
+ )
668
+ origin = get_origin(annotation)
669
+ if annotation is Self and hasattr(func, "__self__"):
670
+ return func.__self__
671
+ elif origin is Literal:
672
+ type_args = get_args(annotation)
673
+ if len(type_args) == 1:
674
+ return type_args[0]
675
+ elif annotation is LiteralString:
676
+ return ""
677
+ elif annotation is AnyStr:
678
+ index = None
679
+ for i, (key, value) in enumerate(sig.parameters.items()):
680
+ if value.annotation is AnyStr:
681
+ index = i
682
+ break
683
+ if index is not None and index < len(node.args):
684
+ return eval_node(node.args[index], context)
685
+ elif origin is TypeGuard:
686
+ return bool()
687
+ elif origin is Union:
688
+ attributes = [
689
+ attr
690
+ for type_arg in get_args(annotation)
691
+ for attr in dir(_resolve_annotation(type_arg, sig, func, node, context))
692
+ ]
693
+ return _Duck(attributes=dict.fromkeys(attributes))
694
+ elif is_typeddict(annotation):
695
+ return _Duck(
696
+ attributes=dict.fromkeys(dir(dict())),
697
+ items={
698
+ k: _resolve_annotation(v, sig, func, node, context)
699
+ for k, v in annotation.__annotations__.items()
700
+ },
701
+ )
702
+ elif hasattr(annotation, "_is_protocol"):
703
+ return _Duck(attributes=dict.fromkeys(dir(annotation)))
704
+ elif origin is Annotated:
705
+ type_arg = get_args(annotation)[0]
706
+ return _resolve_annotation(type_arg, sig, func, node, context)
707
+ elif isinstance(annotation, NewType):
708
+ return _eval_or_create_duck(annotation.__supertype__, node, context)
709
+ elif isinstance(annotation, TypeAliasType):
710
+ return _eval_or_create_duck(annotation.__value__, node, context)
711
+ else:
712
+ return _eval_or_create_duck(annotation, node, context)
713
+
714
+
715
+ def _eval_node_name(node_id: str, context: EvaluationContext):
716
+ policy = EVALUATION_POLICIES[context.evaluation]
717
+ if policy.allow_locals_access and node_id in context.locals:
718
+ return context.locals[node_id]
719
+ if policy.allow_globals_access and node_id in context.globals:
720
+ return context.globals[node_id]
721
+ if policy.allow_builtins_access and hasattr(builtins, node_id):
722
+ # note: do not use __builtins__, it is implementation detail of cPython
723
+ return getattr(builtins, node_id)
724
+ if not policy.allow_globals_access and not policy.allow_locals_access:
725
+ raise GuardRejection(
726
+ f"Namespace access not allowed in {context.evaluation} mode"
727
+ )
728
+ else:
729
+ raise NameError(f"{node_id} not found in locals, globals, nor builtins")
730
+
731
+
732
+ def _eval_or_create_duck(duck_type, node: ast.Call, context: EvaluationContext):
733
+ policy = EVALUATION_POLICIES[context.evaluation]
734
+ # if allow-listed builtin is on type annotation, instantiate it
735
+ if policy.can_call(duck_type) and not node.keywords:
736
+ args = [eval_node(arg, context) for arg in node.args]
737
+ return duck_type(*args)
738
+ # if custom class is in type annotation, mock it
739
+ return _create_duck_for_heap_type(duck_type)
740
+
741
+
742
+ def _create_duck_for_heap_type(duck_type):
743
+ """Create an imitation of an object of a given type (a duck).
744
+
745
+ Returns the duck or NOT_EVALUATED sentinel if duck could not be created.
746
+ """
747
+ duck = ImpersonatingDuck()
748
+ try:
749
+ # this only works for heap types, not builtins
750
+ duck.__class__ = duck_type
751
+ return duck
752
+ except TypeError:
753
+ pass
754
+ return NOT_EVALUATED
755
+
756
+
757
+ SUPPORTED_EXTERNAL_GETITEM = {
758
+ ("pandas", "core", "indexing", "_iLocIndexer"),
759
+ ("pandas", "core", "indexing", "_LocIndexer"),
760
+ ("pandas", "DataFrame"),
761
+ ("pandas", "Series"),
762
+ ("numpy", "ndarray"),
763
+ ("numpy", "void"),
764
+ }
765
+
766
+
767
+ BUILTIN_GETITEM: Set[InstancesHaveGetItem] = {
768
+ dict,
769
+ str, # type: ignore[arg-type]
770
+ bytes, # type: ignore[arg-type]
771
+ list,
772
+ tuple,
773
+ collections.defaultdict,
774
+ collections.deque,
775
+ collections.OrderedDict,
776
+ collections.ChainMap,
777
+ collections.UserDict,
778
+ collections.UserList,
779
+ collections.UserString, # type: ignore[arg-type]
780
+ _DummyNamedTuple,
781
+ _IdentitySubscript,
782
+ }
783
+
784
+
785
+ def _list_methods(cls, source=None):
786
+ """For use on immutable objects or with methods returning a copy"""
787
+ return [getattr(cls, k) for k in (source if source else dir(cls))]
788
+
789
+
790
+ dict_non_mutating_methods = ("copy", "keys", "values", "items")
791
+ list_non_mutating_methods = ("copy", "index", "count")
792
+ set_non_mutating_methods = set(dir(set)) & set(dir(frozenset))
793
+
794
+
795
+ dict_keys: Type[collections.abc.KeysView] = type({}.keys())
796
+
797
+ NUMERICS = {int, float, complex}
798
+
799
+ ALLOWED_CALLS = {
800
+ bytes,
801
+ *_list_methods(bytes),
802
+ dict,
803
+ *_list_methods(dict, dict_non_mutating_methods),
804
+ dict_keys.isdisjoint,
805
+ list,
806
+ *_list_methods(list, list_non_mutating_methods),
807
+ set,
808
+ *_list_methods(set, set_non_mutating_methods),
809
+ frozenset,
810
+ *_list_methods(frozenset),
811
+ range,
812
+ str,
813
+ *_list_methods(str),
814
+ tuple,
815
+ *_list_methods(tuple),
816
+ *NUMERICS,
817
+ *[method for numeric_cls in NUMERICS for method in _list_methods(numeric_cls)],
818
+ collections.deque,
819
+ *_list_methods(collections.deque, list_non_mutating_methods),
820
+ collections.defaultdict,
821
+ *_list_methods(collections.defaultdict, dict_non_mutating_methods),
822
+ collections.OrderedDict,
823
+ *_list_methods(collections.OrderedDict, dict_non_mutating_methods),
824
+ collections.UserDict,
825
+ *_list_methods(collections.UserDict, dict_non_mutating_methods),
826
+ collections.UserList,
827
+ *_list_methods(collections.UserList, list_non_mutating_methods),
828
+ collections.UserString,
829
+ *_list_methods(collections.UserString, dir(str)),
830
+ collections.Counter,
831
+ *_list_methods(collections.Counter, dict_non_mutating_methods),
832
+ collections.Counter.elements,
833
+ collections.Counter.most_common,
834
+ }
835
+
836
+ BUILTIN_GETATTR: Set[MayHaveGetattr] = {
837
+ *BUILTIN_GETITEM,
838
+ set,
839
+ frozenset,
840
+ object,
841
+ type, # `type` handles a lot of generic cases, e.g. numbers as in `int.real`.
842
+ *NUMERICS,
843
+ dict_keys,
844
+ MethodDescriptorType,
845
+ ModuleType,
846
+ }
847
+
848
+
849
+ BUILTIN_OPERATIONS = {*BUILTIN_GETATTR}
850
+
851
+ EVALUATION_POLICIES = {
852
+ "minimal": EvaluationPolicy(
853
+ allow_builtins_access=True,
854
+ allow_locals_access=False,
855
+ allow_globals_access=False,
856
+ allow_item_access=False,
857
+ allow_attr_access=False,
858
+ allowed_calls=set(),
859
+ allow_any_calls=False,
860
+ allow_all_operations=False,
861
+ ),
862
+ "limited": SelectivePolicy(
863
+ allowed_getitem=BUILTIN_GETITEM,
864
+ allowed_getitem_external=SUPPORTED_EXTERNAL_GETITEM,
865
+ allowed_getattr=BUILTIN_GETATTR,
866
+ allowed_getattr_external={
867
+ # pandas Series/Frame implements custom `__getattr__`
868
+ ("pandas", "DataFrame"),
869
+ ("pandas", "Series"),
870
+ },
871
+ allowed_operations=BUILTIN_OPERATIONS,
872
+ allow_builtins_access=True,
873
+ allow_locals_access=True,
874
+ allow_globals_access=True,
875
+ allowed_calls=ALLOWED_CALLS,
876
+ ),
877
+ "unsafe": EvaluationPolicy(
878
+ allow_builtins_access=True,
879
+ allow_locals_access=True,
880
+ allow_globals_access=True,
881
+ allow_attr_access=True,
882
+ allow_item_access=True,
883
+ allow_any_calls=True,
884
+ allow_all_operations=True,
885
+ ),
886
+ }
887
+
888
+
889
+ __all__ = [
890
+ "guarded_eval",
891
+ "eval_node",
892
+ "GuardRejection",
893
+ "EvaluationContext",
894
+ "_unbind_method",
895
+ ]
openalex_env_map/lib/python3.10/site-packages/IPython/core/history.py ADDED
@@ -0,0 +1,989 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ History related magics and functionality """
2
+
3
+ # Copyright (c) IPython Development Team.
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+
7
+ import atexit
8
+ import datetime
9
+ import re
10
+ import sqlite3
11
+ import threading
12
+ from pathlib import Path
13
+
14
+ from decorator import decorator
15
+ from traitlets import (
16
+ Any,
17
+ Bool,
18
+ Dict,
19
+ Instance,
20
+ Integer,
21
+ List,
22
+ TraitError,
23
+ Unicode,
24
+ Union,
25
+ default,
26
+ observe,
27
+ )
28
+ from traitlets.config.configurable import LoggingConfigurable
29
+
30
+ from IPython.paths import locate_profile
31
+ from IPython.utils.decorators import undoc
32
+
33
+ #-----------------------------------------------------------------------------
34
+ # Classes and functions
35
+ #-----------------------------------------------------------------------------
36
+
37
+ @undoc
38
+ class DummyDB(object):
39
+ """Dummy DB that will act as a black hole for history.
40
+
41
+ Only used in the absence of sqlite"""
42
+ def execute(*args, **kwargs):
43
+ return []
44
+
45
+ def commit(self, *args, **kwargs):
46
+ pass
47
+
48
+ def __enter__(self, *args, **kwargs):
49
+ pass
50
+
51
+ def __exit__(self, *args, **kwargs):
52
+ pass
53
+
54
+
55
+ @decorator
56
+ def only_when_enabled(f, self, *a, **kw):
57
+ """Decorator: return an empty list in the absence of sqlite."""
58
+ if not self.enabled:
59
+ return []
60
+ else:
61
+ return f(self, *a, **kw)
62
+
63
+
64
+ # use 16kB as threshold for whether a corrupt history db should be saved
65
+ # that should be at least 100 entries or so
66
+ _SAVE_DB_SIZE = 16384
67
+
68
+ @decorator
69
+ def catch_corrupt_db(f, self, *a, **kw):
70
+ """A decorator which wraps HistoryAccessor method calls to catch errors from
71
+ a corrupt SQLite database, move the old database out of the way, and create
72
+ a new one.
73
+
74
+ We avoid clobbering larger databases because this may be triggered due to filesystem issues,
75
+ not just a corrupt file.
76
+ """
77
+ try:
78
+ return f(self, *a, **kw)
79
+ except (sqlite3.DatabaseError, sqlite3.OperationalError) as e:
80
+ self._corrupt_db_counter += 1
81
+ self.log.error("Failed to open SQLite history %s (%s).", self.hist_file, e)
82
+ if self.hist_file != ':memory:':
83
+ if self._corrupt_db_counter > self._corrupt_db_limit:
84
+ self.hist_file = ':memory:'
85
+ self.log.error("Failed to load history too many times, history will not be saved.")
86
+ elif self.hist_file.is_file():
87
+ # move the file out of the way
88
+ base = str(self.hist_file.parent / self.hist_file.stem)
89
+ ext = self.hist_file.suffix
90
+ size = self.hist_file.stat().st_size
91
+ if size >= _SAVE_DB_SIZE:
92
+ # if there's significant content, avoid clobbering
93
+ now = datetime.datetime.now().isoformat().replace(':', '.')
94
+ newpath = base + '-corrupt-' + now + ext
95
+ # don't clobber previous corrupt backups
96
+ for i in range(100):
97
+ if not Path(newpath).exists():
98
+ break
99
+ else:
100
+ newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext
101
+ else:
102
+ # not much content, possibly empty; don't worry about clobbering
103
+ # maybe we should just delete it?
104
+ newpath = base + '-corrupt' + ext
105
+ self.hist_file.rename(newpath)
106
+ self.log.error("History file was moved to %s and a new file created.", newpath)
107
+ self.init_db()
108
+ return []
109
+ else:
110
+ # Failed with :memory:, something serious is wrong
111
+ raise
112
+
113
+
114
+ class HistoryAccessorBase(LoggingConfigurable):
115
+ """An abstract class for History Accessors """
116
+
117
+ def get_tail(self, n=10, raw=True, output=False, include_latest=False):
118
+ raise NotImplementedError
119
+
120
+ def search(self, pattern="*", raw=True, search_raw=True,
121
+ output=False, n=None, unique=False):
122
+ raise NotImplementedError
123
+
124
+ def get_range(self, session, start=1, stop=None, raw=True,output=False):
125
+ raise NotImplementedError
126
+
127
+ def get_range_by_str(self, rangestr, raw=True, output=False):
128
+ raise NotImplementedError
129
+
130
+
131
+ class HistoryAccessor(HistoryAccessorBase):
132
+ """Access the history database without adding to it.
133
+
134
+ This is intended for use by standalone history tools. IPython shells use
135
+ HistoryManager, below, which is a subclass of this."""
136
+
137
+ # counter for init_db retries, so we don't keep trying over and over
138
+ _corrupt_db_counter = 0
139
+ # after two failures, fallback on :memory:
140
+ _corrupt_db_limit = 2
141
+
142
+ # String holding the path to the history file
143
+ hist_file = Union(
144
+ [Instance(Path), Unicode()],
145
+ help="""Path to file to use for SQLite history database.
146
+
147
+ By default, IPython will put the history database in the IPython
148
+ profile directory. If you would rather share one history among
149
+ profiles, you can set this value in each, so that they are consistent.
150
+
151
+ Due to an issue with fcntl, SQLite is known to misbehave on some NFS
152
+ mounts. If you see IPython hanging, try setting this to something on a
153
+ local disk, e.g::
154
+
155
+ ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
156
+
157
+ you can also use the specific value `:memory:` (including the colon
158
+ at both end but not the back ticks), to avoid creating an history file.
159
+
160
+ """,
161
+ ).tag(config=True)
162
+
163
+ enabled = Bool(True,
164
+ help="""enable the SQLite history
165
+
166
+ set enabled=False to disable the SQLite history,
167
+ in which case there will be no stored history, no SQLite connection,
168
+ and no background saving thread. This may be necessary in some
169
+ threaded environments where IPython is embedded.
170
+ """,
171
+ ).tag(config=True)
172
+
173
+ connection_options = Dict(
174
+ help="""Options for configuring the SQLite connection
175
+
176
+ These options are passed as keyword args to sqlite3.connect
177
+ when establishing database connections.
178
+ """
179
+ ).tag(config=True)
180
+
181
+ @default("connection_options")
182
+ def _default_connection_options(self):
183
+ return dict(check_same_thread=False)
184
+
185
+ # The SQLite database
186
+ db = Any()
187
+ @observe('db')
188
+ def _db_changed(self, change):
189
+ """validate the db, since it can be an Instance of two different types"""
190
+ new = change['new']
191
+ connection_types = (DummyDB, sqlite3.Connection)
192
+ if not isinstance(new, connection_types):
193
+ msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
194
+ (self.__class__.__name__, new)
195
+ raise TraitError(msg)
196
+
197
+ def __init__(self, profile="default", hist_file="", **traits):
198
+ """Create a new history accessor.
199
+
200
+ Parameters
201
+ ----------
202
+ profile : str
203
+ The name of the profile from which to open history.
204
+ hist_file : str
205
+ Path to an SQLite history database stored by IPython. If specified,
206
+ hist_file overrides profile.
207
+ config : :class:`~traitlets.config.loader.Config`
208
+ Config object. hist_file can also be set through this.
209
+ """
210
+ super(HistoryAccessor, self).__init__(**traits)
211
+ # defer setting hist_file from kwarg until after init,
212
+ # otherwise the default kwarg value would clobber any value
213
+ # set by config
214
+ if hist_file:
215
+ self.hist_file = hist_file
216
+
217
+ try:
218
+ self.hist_file
219
+ except TraitError:
220
+ # No one has set the hist_file, yet.
221
+ self.hist_file = self._get_hist_file_name(profile)
222
+
223
+ self.init_db()
224
+
225
+ def _get_hist_file_name(self, profile='default'):
226
+ """Find the history file for the given profile name.
227
+
228
+ This is overridden by the HistoryManager subclass, to use the shell's
229
+ active profile.
230
+
231
+ Parameters
232
+ ----------
233
+ profile : str
234
+ The name of a profile which has a history file.
235
+ """
236
+ return Path(locate_profile(profile)) / "history.sqlite"
237
+
238
+ @catch_corrupt_db
239
+ def init_db(self):
240
+ """Connect to the database, and create tables if necessary."""
241
+ if not self.enabled:
242
+ self.db = DummyDB()
243
+ return
244
+
245
+ # use detect_types so that timestamps return datetime objects
246
+ kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
247
+ kwargs.update(self.connection_options)
248
+ self.db = sqlite3.connect(str(self.hist_file), **kwargs)
249
+ with self.db:
250
+ self.db.execute(
251
+ """CREATE TABLE IF NOT EXISTS sessions (session integer
252
+ primary key autoincrement, start timestamp,
253
+ end timestamp, num_cmds integer, remark text)"""
254
+ )
255
+ self.db.execute(
256
+ """CREATE TABLE IF NOT EXISTS history
257
+ (session integer, line integer, source text, source_raw text,
258
+ PRIMARY KEY (session, line))"""
259
+ )
260
+ # Output history is optional, but ensure the table's there so it can be
261
+ # enabled later.
262
+ self.db.execute(
263
+ """CREATE TABLE IF NOT EXISTS output_history
264
+ (session integer, line integer, output text,
265
+ PRIMARY KEY (session, line))"""
266
+ )
267
+ # success! reset corrupt db count
268
+ self._corrupt_db_counter = 0
269
+
270
+ def writeout_cache(self):
271
+ """Overridden by HistoryManager to dump the cache before certain
272
+ database lookups."""
273
+ pass
274
+
275
+ ## -------------------------------
276
+ ## Methods for retrieving history:
277
+ ## -------------------------------
278
+ def _run_sql(self, sql, params, raw=True, output=False, latest=False):
279
+ """Prepares and runs an SQL query for the history database.
280
+
281
+ Parameters
282
+ ----------
283
+ sql : str
284
+ Any filtering expressions to go after SELECT ... FROM ...
285
+ params : tuple
286
+ Parameters passed to the SQL query (to replace "?")
287
+ raw, output : bool
288
+ See :meth:`get_range`
289
+ latest : bool
290
+ Select rows with max (session, line)
291
+
292
+ Returns
293
+ -------
294
+ Tuples as :meth:`get_range`
295
+ """
296
+ toget = 'source_raw' if raw else 'source'
297
+ sqlfrom = "history"
298
+ if output:
299
+ sqlfrom = "history LEFT JOIN output_history USING (session, line)"
300
+ toget = "history.%s, output_history.output" % toget
301
+ if latest:
302
+ toget += ", MAX(session * 128 * 1024 + line)"
303
+ this_querry = "SELECT session, line, %s FROM %s " % (toget, sqlfrom) + sql
304
+ cur = self.db.execute(this_querry, params)
305
+ if latest:
306
+ cur = (row[:-1] for row in cur)
307
+ if output: # Regroup into 3-tuples, and parse JSON
308
+ return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
309
+ return cur
310
+
311
+ @only_when_enabled
312
+ @catch_corrupt_db
313
+ def get_session_info(self, session):
314
+ """Get info about a session.
315
+
316
+ Parameters
317
+ ----------
318
+ session : int
319
+ Session number to retrieve.
320
+
321
+ Returns
322
+ -------
323
+ session_id : int
324
+ Session ID number
325
+ start : datetime
326
+ Timestamp for the start of the session.
327
+ end : datetime
328
+ Timestamp for the end of the session, or None if IPython crashed.
329
+ num_cmds : int
330
+ Number of commands run, or None if IPython crashed.
331
+ remark : unicode
332
+ A manually set description.
333
+ """
334
+ query = "SELECT * from sessions where session == ?"
335
+ return self.db.execute(query, (session,)).fetchone()
336
+
337
+ @catch_corrupt_db
338
+ def get_last_session_id(self):
339
+ """Get the last session ID currently in the database.
340
+
341
+ Within IPython, this should be the same as the value stored in
342
+ :attr:`HistoryManager.session_number`.
343
+ """
344
+ for record in self.get_tail(n=1, include_latest=True):
345
+ return record[0]
346
+
347
+ @catch_corrupt_db
348
+ def get_tail(self, n=10, raw=True, output=False, include_latest=False):
349
+ """Get the last n lines from the history database.
350
+
351
+ Parameters
352
+ ----------
353
+ n : int
354
+ The number of lines to get
355
+ raw, output : bool
356
+ See :meth:`get_range`
357
+ include_latest : bool
358
+ If False (default), n+1 lines are fetched, and the latest one
359
+ is discarded. This is intended to be used where the function
360
+ is called by a user command, which it should not return.
361
+
362
+ Returns
363
+ -------
364
+ Tuples as :meth:`get_range`
365
+ """
366
+ self.writeout_cache()
367
+ if not include_latest:
368
+ n += 1
369
+ cur = self._run_sql(
370
+ "ORDER BY session DESC, line DESC LIMIT ?", (n,), raw=raw, output=output
371
+ )
372
+ if not include_latest:
373
+ return reversed(list(cur)[1:])
374
+ return reversed(list(cur))
375
+
376
+ @catch_corrupt_db
377
+ def search(self, pattern="*", raw=True, search_raw=True,
378
+ output=False, n=None, unique=False):
379
+ """Search the database using unix glob-style matching (wildcards
380
+ * and ?).
381
+
382
+ Parameters
383
+ ----------
384
+ pattern : str
385
+ The wildcarded pattern to match when searching
386
+ search_raw : bool
387
+ If True, search the raw input, otherwise, the parsed input
388
+ raw, output : bool
389
+ See :meth:`get_range`
390
+ n : None or int
391
+ If an integer is given, it defines the limit of
392
+ returned entries.
393
+ unique : bool
394
+ When it is true, return only unique entries.
395
+
396
+ Returns
397
+ -------
398
+ Tuples as :meth:`get_range`
399
+ """
400
+ tosearch = "source_raw" if search_raw else "source"
401
+ if output:
402
+ tosearch = "history." + tosearch
403
+ self.writeout_cache()
404
+ sqlform = "WHERE %s GLOB ?" % tosearch
405
+ params = (pattern,)
406
+ if unique:
407
+ sqlform += ' GROUP BY {0}'.format(tosearch)
408
+ if n is not None:
409
+ sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
410
+ params += (n,)
411
+ elif unique:
412
+ sqlform += " ORDER BY session, line"
413
+ cur = self._run_sql(sqlform, params, raw=raw, output=output, latest=unique)
414
+ if n is not None:
415
+ return reversed(list(cur))
416
+ return cur
417
+
418
+ @catch_corrupt_db
419
+ def get_range(self, session, start=1, stop=None, raw=True,output=False):
420
+ """Retrieve input by session.
421
+
422
+ Parameters
423
+ ----------
424
+ session : int
425
+ Session number to retrieve.
426
+ start : int
427
+ First line to retrieve.
428
+ stop : int
429
+ End of line range (excluded from output itself). If None, retrieve
430
+ to the end of the session.
431
+ raw : bool
432
+ If True, return untranslated input
433
+ output : bool
434
+ If True, attempt to include output. This will be 'real' Python
435
+ objects for the current session, or text reprs from previous
436
+ sessions if db_log_output was enabled at the time. Where no output
437
+ is found, None is used.
438
+
439
+ Returns
440
+ -------
441
+ entries
442
+ An iterator over the desired lines. Each line is a 3-tuple, either
443
+ (session, line, input) if output is False, or
444
+ (session, line, (input, output)) if output is True.
445
+ """
446
+ if stop:
447
+ lineclause = "line >= ? AND line < ?"
448
+ params = (session, start, stop)
449
+ else:
450
+ lineclause = "line>=?"
451
+ params = (session, start)
452
+
453
+ return self._run_sql("WHERE session==? AND %s" % lineclause,
454
+ params, raw=raw, output=output)
455
+
456
+ def get_range_by_str(self, rangestr, raw=True, output=False):
457
+ """Get lines of history from a string of ranges, as used by magic
458
+ commands %hist, %save, %macro, etc.
459
+
460
+ Parameters
461
+ ----------
462
+ rangestr : str
463
+ A string specifying ranges, e.g. "5 ~2/1-4". If empty string is used,
464
+ this will return everything from current session's history.
465
+
466
+ See the documentation of :func:`%history` for the full details.
467
+
468
+ raw, output : bool
469
+ As :meth:`get_range`
470
+
471
+ Returns
472
+ -------
473
+ Tuples as :meth:`get_range`
474
+ """
475
+ for sess, s, e in extract_hist_ranges(rangestr):
476
+ for line in self.get_range(sess, s, e, raw=raw, output=output):
477
+ yield line
478
+
479
+
480
+ class HistoryManager(HistoryAccessor):
481
+ """A class to organize all history-related functionality in one place.
482
+ """
483
+ # Public interface
484
+
485
+ # An instance of the IPython shell we are attached to
486
+ shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
487
+ allow_none=True)
488
+ # Lists to hold processed and raw history. These start with a blank entry
489
+ # so that we can index them starting from 1
490
+ input_hist_parsed = List([""])
491
+ input_hist_raw = List([""])
492
+ # A list of directories visited during session
493
+ dir_hist: List = List()
494
+
495
+ @default("dir_hist")
496
+ def _dir_hist_default(self):
497
+ try:
498
+ return [Path.cwd()]
499
+ except OSError:
500
+ return []
501
+
502
+ # A dict of output history, keyed with ints from the shell's
503
+ # execution count.
504
+ output_hist = Dict()
505
+ # The text/plain repr of outputs.
506
+ output_hist_reprs = Dict()
507
+
508
+ # The number of the current session in the history database
509
+ session_number = Integer()
510
+
511
+ db_log_output = Bool(False,
512
+ help="Should the history database include output? (default: no)"
513
+ ).tag(config=True)
514
+ db_cache_size = Integer(0,
515
+ help="Write to database every x commands (higher values save disk access & power).\n"
516
+ "Values of 1 or less effectively disable caching."
517
+ ).tag(config=True)
518
+ # The input and output caches
519
+ db_input_cache: List = List()
520
+ db_output_cache: List = List()
521
+
522
+ # History saving in separate thread
523
+ save_thread = Instance('IPython.core.history.HistorySavingThread',
524
+ allow_none=True)
525
+ save_flag = Instance(threading.Event, allow_none=True)
526
+
527
+ # Private interface
528
+ # Variables used to store the three last inputs from the user. On each new
529
+ # history update, we populate the user's namespace with these, shifted as
530
+ # necessary.
531
+ _i00 = Unicode("")
532
+ _i = Unicode("")
533
+ _ii = Unicode("")
534
+ _iii = Unicode("")
535
+
536
+ # A regex matching all forms of the exit command, so that we don't store
537
+ # them in the history (it's annoying to rewind the first entry and land on
538
+ # an exit call).
539
+ _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
540
+
541
+ def __init__(self, shell=None, config=None, **traits):
542
+ """Create a new history manager associated with a shell instance.
543
+ """
544
+ super(HistoryManager, self).__init__(shell=shell, config=config,
545
+ **traits)
546
+ self.save_flag = threading.Event()
547
+ self.db_input_cache_lock = threading.Lock()
548
+ self.db_output_cache_lock = threading.Lock()
549
+
550
+ try:
551
+ self.new_session()
552
+ except sqlite3.OperationalError:
553
+ self.log.error("Failed to create history session in %s. History will not be saved.",
554
+ self.hist_file, exc_info=True)
555
+ self.hist_file = ':memory:'
556
+
557
+ if self.enabled and self.hist_file != ':memory:':
558
+ self.save_thread = HistorySavingThread(self)
559
+ try:
560
+ self.save_thread.start()
561
+ except RuntimeError:
562
+ self.log.error(
563
+ "Failed to start history saving thread. History will not be saved.",
564
+ exc_info=True,
565
+ )
566
+ self.hist_file = ":memory:"
567
+
568
+ def _get_hist_file_name(self, profile=None):
569
+ """Get default history file name based on the Shell's profile.
570
+
571
+ The profile parameter is ignored, but must exist for compatibility with
572
+ the parent class."""
573
+ profile_dir = self.shell.profile_dir.location
574
+ return Path(profile_dir) / "history.sqlite"
575
+
576
+ @only_when_enabled
577
+ def new_session(self, conn=None):
578
+ """Get a new session number."""
579
+ if conn is None:
580
+ conn = self.db
581
+
582
+ with conn:
583
+ cur = conn.execute(
584
+ """INSERT INTO sessions VALUES (NULL, ?, NULL,
585
+ NULL, '') """,
586
+ (datetime.datetime.now().isoformat(" "),),
587
+ )
588
+ self.session_number = cur.lastrowid
589
+
590
+ def end_session(self):
591
+ """Close the database session, filling in the end time and line count."""
592
+ self.writeout_cache()
593
+ with self.db:
594
+ self.db.execute(
595
+ """UPDATE sessions SET end=?, num_cmds=? WHERE
596
+ session==?""",
597
+ (
598
+ datetime.datetime.now().isoformat(" "),
599
+ len(self.input_hist_parsed) - 1,
600
+ self.session_number,
601
+ ),
602
+ )
603
+ self.session_number = 0
604
+
605
+ def name_session(self, name):
606
+ """Give the current session a name in the history database."""
607
+ with self.db:
608
+ self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
609
+ (name, self.session_number))
610
+
611
+ def reset(self, new_session=True):
612
+ """Clear the session history, releasing all object references, and
613
+ optionally open a new session."""
614
+ self.output_hist.clear()
615
+ # The directory history can't be completely empty
616
+ self.dir_hist[:] = [Path.cwd()]
617
+
618
+ if new_session:
619
+ if self.session_number:
620
+ self.end_session()
621
+ self.input_hist_parsed[:] = [""]
622
+ self.input_hist_raw[:] = [""]
623
+ self.new_session()
624
+
625
+ # ------------------------------
626
+ # Methods for retrieving history
627
+ # ------------------------------
628
+ def get_session_info(self, session=0):
629
+ """Get info about a session.
630
+
631
+ Parameters
632
+ ----------
633
+ session : int
634
+ Session number to retrieve. The current session is 0, and negative
635
+ numbers count back from current session, so -1 is the previous session.
636
+
637
+ Returns
638
+ -------
639
+ session_id : int
640
+ Session ID number
641
+ start : datetime
642
+ Timestamp for the start of the session.
643
+ end : datetime
644
+ Timestamp for the end of the session, or None if IPython crashed.
645
+ num_cmds : int
646
+ Number of commands run, or None if IPython crashed.
647
+ remark : unicode
648
+ A manually set description.
649
+ """
650
+ if session <= 0:
651
+ session += self.session_number
652
+
653
+ return super(HistoryManager, self).get_session_info(session=session)
654
+
655
+ @catch_corrupt_db
656
+ def get_tail(self, n=10, raw=True, output=False, include_latest=False):
657
+ """Get the last n lines from the history database.
658
+
659
+ Most recent entry last.
660
+
661
+ Completion will be reordered so that that the last ones are when
662
+ possible from current session.
663
+
664
+ Parameters
665
+ ----------
666
+ n : int
667
+ The number of lines to get
668
+ raw, output : bool
669
+ See :meth:`get_range`
670
+ include_latest : bool
671
+ If False (default), n+1 lines are fetched, and the latest one
672
+ is discarded. This is intended to be used where the function
673
+ is called by a user command, which it should not return.
674
+
675
+ Returns
676
+ -------
677
+ Tuples as :meth:`get_range`
678
+ """
679
+ self.writeout_cache()
680
+ if not include_latest:
681
+ n += 1
682
+ # cursor/line/entry
683
+ this_cur = list(
684
+ self._run_sql(
685
+ "WHERE session == ? ORDER BY line DESC LIMIT ? ",
686
+ (self.session_number, n),
687
+ raw=raw,
688
+ output=output,
689
+ )
690
+ )
691
+ other_cur = list(
692
+ self._run_sql(
693
+ "WHERE session != ? ORDER BY session DESC, line DESC LIMIT ?",
694
+ (self.session_number, n),
695
+ raw=raw,
696
+ output=output,
697
+ )
698
+ )
699
+
700
+ everything = this_cur + other_cur
701
+
702
+ everything = everything[:n]
703
+
704
+ if not include_latest:
705
+ return list(everything)[:0:-1]
706
+ return list(everything)[::-1]
707
+
708
+ def _get_range_session(self, start=1, stop=None, raw=True, output=False):
709
+ """Get input and output history from the current session. Called by
710
+ get_range, and takes similar parameters."""
711
+ input_hist = self.input_hist_raw if raw else self.input_hist_parsed
712
+
713
+ n = len(input_hist)
714
+ if start < 0:
715
+ start += n
716
+ if not stop or (stop > n):
717
+ stop = n
718
+ elif stop < 0:
719
+ stop += n
720
+
721
+ for i in range(start, stop):
722
+ if output:
723
+ line = (input_hist[i], self.output_hist_reprs.get(i))
724
+ else:
725
+ line = input_hist[i]
726
+ yield (0, i, line)
727
+
728
+ def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
729
+ """Retrieve input by session.
730
+
731
+ Parameters
732
+ ----------
733
+ session : int
734
+ Session number to retrieve. The current session is 0, and negative
735
+ numbers count back from current session, so -1 is previous session.
736
+ start : int
737
+ First line to retrieve.
738
+ stop : int
739
+ End of line range (excluded from output itself). If None, retrieve
740
+ to the end of the session.
741
+ raw : bool
742
+ If True, return untranslated input
743
+ output : bool
744
+ If True, attempt to include output. This will be 'real' Python
745
+ objects for the current session, or text reprs from previous
746
+ sessions if db_log_output was enabled at the time. Where no output
747
+ is found, None is used.
748
+
749
+ Returns
750
+ -------
751
+ entries
752
+ An iterator over the desired lines. Each line is a 3-tuple, either
753
+ (session, line, input) if output is False, or
754
+ (session, line, (input, output)) if output is True.
755
+ """
756
+ if session <= 0:
757
+ session += self.session_number
758
+ if session==self.session_number: # Current session
759
+ return self._get_range_session(start, stop, raw, output)
760
+ return super(HistoryManager, self).get_range(session, start, stop, raw,
761
+ output)
762
+
763
+ ## ----------------------------
764
+ ## Methods for storing history:
765
+ ## ----------------------------
766
+ def store_inputs(self, line_num, source, source_raw=None):
767
+ """Store source and raw input in history and create input cache
768
+ variables ``_i*``.
769
+
770
+ Parameters
771
+ ----------
772
+ line_num : int
773
+ The prompt number of this input.
774
+ source : str
775
+ Python input.
776
+ source_raw : str, optional
777
+ If given, this is the raw input without any IPython transformations
778
+ applied to it. If not given, ``source`` is used.
779
+ """
780
+ if source_raw is None:
781
+ source_raw = source
782
+ source = source.rstrip('\n')
783
+ source_raw = source_raw.rstrip('\n')
784
+
785
+ # do not store exit/quit commands
786
+ if self._exit_re.match(source_raw.strip()):
787
+ return
788
+
789
+ self.input_hist_parsed.append(source)
790
+ self.input_hist_raw.append(source_raw)
791
+
792
+ with self.db_input_cache_lock:
793
+ self.db_input_cache.append((line_num, source, source_raw))
794
+ # Trigger to flush cache and write to DB.
795
+ if len(self.db_input_cache) >= self.db_cache_size:
796
+ self.save_flag.set()
797
+
798
+ # update the auto _i variables
799
+ self._iii = self._ii
800
+ self._ii = self._i
801
+ self._i = self._i00
802
+ self._i00 = source_raw
803
+
804
+ # hackish access to user namespace to create _i1,_i2... dynamically
805
+ new_i = '_i%s' % line_num
806
+ to_main = {'_i': self._i,
807
+ '_ii': self._ii,
808
+ '_iii': self._iii,
809
+ new_i : self._i00 }
810
+
811
+ if self.shell is not None:
812
+ self.shell.push(to_main, interactive=False)
813
+
814
+ def store_output(self, line_num):
815
+ """If database output logging is enabled, this saves all the
816
+ outputs from the indicated prompt number to the database. It's
817
+ called by run_cell after code has been executed.
818
+
819
+ Parameters
820
+ ----------
821
+ line_num : int
822
+ The line number from which to save outputs
823
+ """
824
+ if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
825
+ return
826
+ output = self.output_hist_reprs[line_num]
827
+
828
+ with self.db_output_cache_lock:
829
+ self.db_output_cache.append((line_num, output))
830
+ if self.db_cache_size <= 1:
831
+ self.save_flag.set()
832
+
833
+ def _writeout_input_cache(self, conn):
834
+ with conn:
835
+ for line in self.db_input_cache:
836
+ conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
837
+ (self.session_number,)+line)
838
+
839
+ def _writeout_output_cache(self, conn):
840
+ with conn:
841
+ for line in self.db_output_cache:
842
+ conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
843
+ (self.session_number,)+line)
844
+
845
+ @only_when_enabled
846
+ def writeout_cache(self, conn=None):
847
+ """Write any entries in the cache to the database."""
848
+ if conn is None:
849
+ conn = self.db
850
+
851
+ with self.db_input_cache_lock:
852
+ try:
853
+ self._writeout_input_cache(conn)
854
+ except sqlite3.IntegrityError:
855
+ self.new_session(conn)
856
+ print("ERROR! Session/line number was not unique in",
857
+ "database. History logging moved to new session",
858
+ self.session_number)
859
+ try:
860
+ # Try writing to the new session. If this fails, don't
861
+ # recurse
862
+ self._writeout_input_cache(conn)
863
+ except sqlite3.IntegrityError:
864
+ pass
865
+ finally:
866
+ self.db_input_cache = []
867
+
868
+ with self.db_output_cache_lock:
869
+ try:
870
+ self._writeout_output_cache(conn)
871
+ except sqlite3.IntegrityError:
872
+ print("!! Session/line number for output was not unique",
873
+ "in database. Output will not be stored.")
874
+ finally:
875
+ self.db_output_cache = []
876
+
877
+
878
+ class HistorySavingThread(threading.Thread):
879
+ """This thread takes care of writing history to the database, so that
880
+ the UI isn't held up while that happens.
881
+
882
+ It waits for the HistoryManager's save_flag to be set, then writes out
883
+ the history cache. The main thread is responsible for setting the flag when
884
+ the cache size reaches a defined threshold."""
885
+ daemon = True
886
+ stop_now = False
887
+ enabled = True
888
+ def __init__(self, history_manager):
889
+ super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
890
+ self.history_manager = history_manager
891
+ self.enabled = history_manager.enabled
892
+
893
+ @only_when_enabled
894
+ def run(self):
895
+ atexit.register(self.stop)
896
+ # We need a separate db connection per thread:
897
+ try:
898
+ self.db = sqlite3.connect(
899
+ str(self.history_manager.hist_file),
900
+ **self.history_manager.connection_options,
901
+ )
902
+ while True:
903
+ self.history_manager.save_flag.wait()
904
+ if self.stop_now:
905
+ self.db.close()
906
+ return
907
+ self.history_manager.save_flag.clear()
908
+ self.history_manager.writeout_cache(self.db)
909
+ except Exception as e:
910
+ print(("The history saving thread hit an unexpected error (%s)."
911
+ "History will not be written to the database.") % repr(e))
912
+ finally:
913
+ atexit.unregister(self.stop)
914
+
915
+ def stop(self):
916
+ """This can be called from the main thread to safely stop this thread.
917
+
918
+ Note that it does not attempt to write out remaining history before
919
+ exiting. That should be done by calling the HistoryManager's
920
+ end_session method."""
921
+ self.stop_now = True
922
+ self.history_manager.save_flag.set()
923
+ self.join()
924
+
925
+
926
+ # To match, e.g. ~5/8-~2/3
927
+ range_re = re.compile(r"""
928
+ ((?P<startsess>~?\d+)/)?
929
+ (?P<start>\d+)?
930
+ ((?P<sep>[\-:])
931
+ ((?P<endsess>~?\d+)/)?
932
+ (?P<end>\d+))?
933
+ $""", re.VERBOSE)
934
+
935
+
936
+ def extract_hist_ranges(ranges_str):
937
+ """Turn a string of history ranges into 3-tuples of (session, start, stop).
938
+
939
+ Empty string results in a `[(0, 1, None)]`, i.e. "everything from current
940
+ session".
941
+
942
+ Examples
943
+ --------
944
+ >>> list(extract_hist_ranges("~8/5-~7/4 2"))
945
+ [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
946
+ """
947
+ if ranges_str == "":
948
+ yield (0, 1, None) # Everything from current session
949
+ return
950
+
951
+ for range_str in ranges_str.split():
952
+ rmatch = range_re.match(range_str)
953
+ if not rmatch:
954
+ continue
955
+ start = rmatch.group("start")
956
+ if start:
957
+ start = int(start)
958
+ end = rmatch.group("end")
959
+ # If no end specified, get (a, a + 1)
960
+ end = int(end) if end else start + 1
961
+ else: # start not specified
962
+ if not rmatch.group('startsess'): # no startsess
963
+ continue
964
+ start = 1
965
+ end = None # provide the entire session hist
966
+
967
+ if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
968
+ end += 1
969
+ startsess = rmatch.group("startsess") or "0"
970
+ endsess = rmatch.group("endsess") or startsess
971
+ startsess = int(startsess.replace("~","-"))
972
+ endsess = int(endsess.replace("~","-"))
973
+ assert endsess >= startsess, "start session must be earlier than end session"
974
+
975
+ if endsess == startsess:
976
+ yield (startsess, start, end)
977
+ continue
978
+ # Multiple sessions in one range:
979
+ yield (startsess, start, None)
980
+ for sess in range(startsess+1, endsess):
981
+ yield (sess, 1, None)
982
+ yield (endsess, 1, end)
983
+
984
+
985
+ def _format_lineno(session, line):
986
+ """Helper function to format line numbers properly."""
987
+ if session == 0:
988
+ return str(line)
989
+ return "%s#%s" % (session, line)
openalex_env_map/lib/python3.10/site-packages/IPython/core/historyapp.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """
3
+ An application for managing IPython history.
4
+
5
+ To be invoked as the `ipython history` subcommand.
6
+ """
7
+
8
+ import sqlite3
9
+ from pathlib import Path
10
+
11
+ from traitlets.config.application import Application
12
+ from .application import BaseIPythonApplication
13
+ from traitlets import Bool, Int, Dict
14
+ from ..utils.io import ask_yes_no
15
+
16
+ trim_hist_help = """Trim the IPython history database to the last 1000 entries.
17
+
18
+ This actually copies the last 1000 entries to a new database, and then replaces
19
+ the old file with the new. Use the `--keep=` argument to specify a number
20
+ other than 1000.
21
+ """
22
+
23
+ clear_hist_help = """Clear the IPython history database, deleting all entries.
24
+
25
+ Because this is a destructive operation, IPython will prompt the user if they
26
+ really want to do this. Passing a `-f` flag will force clearing without a
27
+ prompt.
28
+
29
+ This is an handy alias to `ipython history trim --keep=0`
30
+ """
31
+
32
+
33
+ class HistoryTrim(BaseIPythonApplication):
34
+ description = trim_hist_help
35
+
36
+ backup = Bool(False, help="Keep the old history file as history.sqlite.<N>").tag(
37
+ config=True
38
+ )
39
+
40
+ keep = Int(1000, help="Number of recent lines to keep in the database.").tag(
41
+ config=True
42
+ )
43
+
44
+ flags = Dict( # type: ignore
45
+ dict(backup=({"HistoryTrim": {"backup": True}}, backup.help))
46
+ )
47
+
48
+ aliases = Dict(dict(keep="HistoryTrim.keep")) # type: ignore
49
+
50
+ def start(self):
51
+ profile_dir = Path(self.profile_dir.location)
52
+ hist_file = profile_dir / "history.sqlite"
53
+ con = sqlite3.connect(hist_file)
54
+
55
+ # Grab the recent history from the current database.
56
+ inputs = list(con.execute('SELECT session, line, source, source_raw FROM '
57
+ 'history ORDER BY session DESC, line DESC LIMIT ?', (self.keep+1,)))
58
+ if len(inputs) <= self.keep:
59
+ print("There are already at most %d entries in the history database." % self.keep)
60
+ print("Not doing anything. Use --keep= argument to keep fewer entries")
61
+ return
62
+
63
+ print("Trimming history to the most recent %d entries." % self.keep)
64
+
65
+ inputs.pop() # Remove the extra element we got to check the length.
66
+ inputs.reverse()
67
+ if inputs:
68
+ first_session = inputs[0][0]
69
+ outputs = list(con.execute('SELECT session, line, output FROM '
70
+ 'output_history WHERE session >= ?', (first_session,)))
71
+ sessions = list(con.execute('SELECT session, start, end, num_cmds, remark FROM '
72
+ 'sessions WHERE session >= ?', (first_session,)))
73
+ con.close()
74
+
75
+ # Create the new history database.
76
+ new_hist_file = profile_dir / "history.sqlite.new"
77
+ i = 0
78
+ while new_hist_file.exists():
79
+ # Make sure we don't interfere with an existing file.
80
+ i += 1
81
+ new_hist_file = profile_dir / ("history.sqlite.new" + str(i))
82
+ new_db = sqlite3.connect(new_hist_file)
83
+ new_db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
84
+ primary key autoincrement, start timestamp,
85
+ end timestamp, num_cmds integer, remark text)""")
86
+ new_db.execute("""CREATE TABLE IF NOT EXISTS history
87
+ (session integer, line integer, source text, source_raw text,
88
+ PRIMARY KEY (session, line))""")
89
+ new_db.execute("""CREATE TABLE IF NOT EXISTS output_history
90
+ (session integer, line integer, output text,
91
+ PRIMARY KEY (session, line))""")
92
+ new_db.commit()
93
+
94
+
95
+ if inputs:
96
+ with new_db:
97
+ # Add the recent history into the new database.
98
+ new_db.executemany('insert into sessions values (?,?,?,?,?)', sessions)
99
+ new_db.executemany('insert into history values (?,?,?,?)', inputs)
100
+ new_db.executemany('insert into output_history values (?,?,?)', outputs)
101
+ new_db.close()
102
+
103
+ if self.backup:
104
+ i = 1
105
+ backup_hist_file = profile_dir / ("history.sqlite.old.%d" % i)
106
+ while backup_hist_file.exists():
107
+ i += 1
108
+ backup_hist_file = profile_dir / ("history.sqlite.old.%d" % i)
109
+ hist_file.rename(backup_hist_file)
110
+ print("Backed up longer history file to", backup_hist_file)
111
+ else:
112
+ hist_file.unlink()
113
+
114
+ new_hist_file.rename(hist_file)
115
+
116
+
117
+ class HistoryClear(HistoryTrim):
118
+ description = clear_hist_help
119
+ keep = Int(0, help="Number of recent lines to keep in the database.")
120
+
121
+ force = Bool(False, help="Don't prompt user for confirmation").tag(config=True)
122
+
123
+ flags = Dict( # type: ignore
124
+ dict(
125
+ force=({"HistoryClear": {"force": True}}, force.help),
126
+ f=({"HistoryTrim": {"force": True}}, force.help),
127
+ )
128
+ )
129
+ aliases = Dict() # type: ignore
130
+
131
+ def start(self):
132
+ if self.force or ask_yes_no(
133
+ "Really delete all ipython history? ", default="no", interrupt="no"
134
+ ):
135
+ HistoryTrim.start(self)
136
+
137
+
138
+ class HistoryApp(Application):
139
+ name = "ipython-history"
140
+ description = "Manage the IPython history database."
141
+
142
+ subcommands = Dict(dict(
143
+ trim = (HistoryTrim, HistoryTrim.description.splitlines()[0]),
144
+ clear = (HistoryClear, HistoryClear.description.splitlines()[0]),
145
+ ))
146
+
147
+ def start(self):
148
+ if self.subapp is None:
149
+ print(
150
+ "No subcommand specified. Must specify one of: "
151
+ + ", ".join(map(repr, self.subcommands))
152
+ + ".\n"
153
+ )
154
+ self.print_description()
155
+ self.print_subcommands()
156
+ self.exit(1)
157
+ else:
158
+ return self.subapp.start()
openalex_env_map/lib/python3.10/site-packages/IPython/core/hooks.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Hooks for IPython.
2
+
3
+ In Python, it is possible to overwrite any method of any object if you really
4
+ want to. But IPython exposes a few 'hooks', methods which are *designed* to
5
+ be overwritten by users for customization purposes. This module defines the
6
+ default versions of all such hooks, which get used by IPython if not
7
+ overridden by the user.
8
+
9
+ Hooks are simple functions, but they should be declared with ``self`` as their
10
+ first argument, because when activated they are registered into IPython as
11
+ instance methods. The self argument will be the IPython running instance
12
+ itself, so hooks have full access to the entire IPython object.
13
+
14
+ If you wish to define a new hook and activate it, you can make an :doc:`extension
15
+ </config/extensions/index>` or a :ref:`startup script <startup_files>`. For
16
+ example, you could use a startup file like this::
17
+
18
+ import os
19
+
20
+ def calljed(self,filename, linenum):
21
+ "My editor hook calls the jed editor directly."
22
+ print("Calling my own editor, jed ...")
23
+ if os.system('jed +%d %s' % (linenum,filename)) != 0:
24
+ raise TryNext()
25
+
26
+ def load_ipython_extension(ip):
27
+ ip.set_hook('editor', calljed)
28
+
29
+ """
30
+
31
+ #*****************************************************************************
32
+ # Copyright (C) 2005 Fernando Perez. <[email protected]>
33
+ #
34
+ # Distributed under the terms of the BSD License. The full license is in
35
+ # the file COPYING, distributed as part of this software.
36
+ #*****************************************************************************
37
+
38
+ import os
39
+ import subprocess
40
+ import sys
41
+
42
+ from .error import TryNext
43
+
44
+ # List here all the default hooks. For now it's just the editor functions
45
+ # but over time we'll move here all the public API for user-accessible things.
46
+
47
+ __all__ = [
48
+ "editor",
49
+ "synchronize_with_editor",
50
+ "show_in_pager",
51
+ "pre_prompt_hook",
52
+ "clipboard_get",
53
+ ]
54
+
55
+ deprecated = {'pre_run_code_hook': "a callback for the 'pre_execute' or 'pre_run_cell' event",
56
+ 'late_startup_hook': "a callback for the 'shell_initialized' event",
57
+ 'shutdown_hook': "the atexit module",
58
+ }
59
+
60
+ def editor(self, filename, linenum=None, wait=True):
61
+ """Open the default editor at the given filename and linenumber.
62
+
63
+ This is IPython's default editor hook, you can use it as an example to
64
+ write your own modified one. To set your own editor function as the
65
+ new editor hook, call ip.set_hook('editor',yourfunc)."""
66
+
67
+ # IPython configures a default editor at startup by reading $EDITOR from
68
+ # the environment, and falling back on vi (unix) or notepad (win32).
69
+ editor = self.editor
70
+
71
+ # marker for at which line to open the file (for existing objects)
72
+ if linenum is None or editor=='notepad':
73
+ linemark = ''
74
+ else:
75
+ linemark = '+%d' % int(linenum)
76
+
77
+ # Enclose in quotes if necessary and legal
78
+ if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
79
+ editor = '"%s"' % editor
80
+
81
+ # Call the actual editor
82
+ proc = subprocess.Popen('%s %s %s' % (editor, linemark, filename),
83
+ shell=True)
84
+ if wait and proc.wait() != 0:
85
+ raise TryNext()
86
+
87
+
88
+ def synchronize_with_editor(self, filename, linenum, column):
89
+ pass
90
+
91
+
92
+ class CommandChainDispatcher:
93
+ """ Dispatch calls to a chain of commands until some func can handle it
94
+
95
+ Usage: instantiate, execute "add" to add commands (with optional
96
+ priority), execute normally via f() calling mechanism.
97
+
98
+ """
99
+ def __init__(self,commands=None):
100
+ if commands is None:
101
+ self.chain = []
102
+ else:
103
+ self.chain = commands
104
+
105
+
106
+ def __call__(self,*args, **kw):
107
+ """ Command chain is called just like normal func.
108
+
109
+ This will call all funcs in chain with the same args as were given to
110
+ this function, and return the result of first func that didn't raise
111
+ TryNext"""
112
+ last_exc = TryNext()
113
+ for prio,cmd in self.chain:
114
+ # print("prio",prio,"cmd",cmd) # dbg
115
+ try:
116
+ return cmd(*args, **kw)
117
+ except TryNext as exc:
118
+ last_exc = exc
119
+ # if no function will accept it, raise TryNext up to the caller
120
+ raise last_exc
121
+
122
+ def __str__(self):
123
+ return str(self.chain)
124
+
125
+ def add(self, func, priority=0):
126
+ """ Add a func to the cmd chain with given priority """
127
+ self.chain.append((priority, func))
128
+ self.chain.sort(key=lambda x: x[0])
129
+
130
+ def __iter__(self):
131
+ """ Return all objects in chain.
132
+
133
+ Handy if the objects are not callable.
134
+ """
135
+ return iter(self.chain)
136
+
137
+
138
+ def show_in_pager(self, data, start, screen_lines):
139
+ """ Run a string through pager """
140
+ # raising TryNext here will use the default paging functionality
141
+ raise TryNext
142
+
143
+
144
+ def pre_prompt_hook(self):
145
+ """ Run before displaying the next prompt
146
+
147
+ Use this e.g. to display output from asynchronous operations (in order
148
+ to not mess up text entry)
149
+ """
150
+
151
+ return None
152
+
153
+
154
+ def clipboard_get(self):
155
+ """ Get text from the clipboard.
156
+ """
157
+ from ..lib.clipboard import (
158
+ osx_clipboard_get,
159
+ tkinter_clipboard_get,
160
+ win32_clipboard_get,
161
+ wayland_clipboard_get,
162
+ )
163
+ if sys.platform == 'win32':
164
+ chain = [win32_clipboard_get, tkinter_clipboard_get]
165
+ elif sys.platform == 'darwin':
166
+ chain = [osx_clipboard_get, tkinter_clipboard_get]
167
+ else:
168
+ chain = [wayland_clipboard_get, tkinter_clipboard_get]
169
+ dispatcher = CommandChainDispatcher()
170
+ for func in chain:
171
+ dispatcher.add(func)
172
+ text = dispatcher()
173
+ return text
openalex_env_map/lib/python3.10/site-packages/IPython/core/inputsplitter.py ADDED
@@ -0,0 +1,799 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DEPRECATED: Input handling and transformation machinery.
2
+
3
+ This module was deprecated in IPython 7.0, in favour of inputtransformer2.
4
+
5
+ The first class in this module, :class:`InputSplitter`, is designed to tell when
6
+ input from a line-oriented frontend is complete and should be executed, and when
7
+ the user should be prompted for another line of code instead. The name 'input
8
+ splitter' is largely for historical reasons.
9
+
10
+ A companion, :class:`IPythonInputSplitter`, provides the same functionality but
11
+ with full support for the extended IPython syntax (magics, system calls, etc).
12
+ The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
13
+ :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
14
+ and stores the results.
15
+
16
+ For more details, see the class docstrings below.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from warnings import warn
22
+
23
+ warn('IPython.core.inputsplitter is deprecated since IPython 7 in favor of `IPython.core.inputtransformer2`',
24
+ DeprecationWarning)
25
+
26
+ # Copyright (c) IPython Development Team.
27
+ # Distributed under the terms of the Modified BSD License.
28
+ import ast
29
+ import codeop
30
+ import io
31
+ import re
32
+ import sys
33
+ import tokenize
34
+ import warnings
35
+
36
+ from typing import List, Tuple, Union, Optional, TYPE_CHECKING
37
+ from types import CodeType
38
+
39
+ from IPython.core.inputtransformer import (leading_indent,
40
+ classic_prompt,
41
+ ipy_prompt,
42
+ cellmagic,
43
+ assemble_logical_lines,
44
+ help_end,
45
+ escaped_commands,
46
+ assign_from_magic,
47
+ assign_from_system,
48
+ assemble_python_lines,
49
+ )
50
+ from IPython.utils import tokenutil
51
+
52
+ # These are available in this module for backwards compatibility.
53
+ from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
54
+ ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
55
+ ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
56
+
57
+ if TYPE_CHECKING:
58
+ from typing_extensions import Self
59
+ #-----------------------------------------------------------------------------
60
+ # Utilities
61
+ #-----------------------------------------------------------------------------
62
+
63
+ # FIXME: These are general-purpose utilities that later can be moved to the
64
+ # general ward. Kept here for now because we're being very strict about test
65
+ # coverage with this code, and this lets us ensure that we keep 100% coverage
66
+ # while developing.
67
+
68
+ # compiled regexps for autoindent management
69
+ dedent_re = re.compile('|'.join([
70
+ r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
71
+ r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
72
+ r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
73
+ r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
74
+ r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
75
+ r'^\s+break\s*$', # break (optionally followed by trailing spaces)
76
+ r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
77
+ ]))
78
+ ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
79
+
80
+ # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
81
+ # before pure comments
82
+ comment_line_re = re.compile(r'^\s*\#')
83
+
84
+
85
+ def num_ini_spaces(s):
86
+ """Return the number of initial spaces in a string.
87
+
88
+ Note that tabs are counted as a single space. For now, we do *not* support
89
+ mixing of tabs and spaces in the user's input.
90
+
91
+ Parameters
92
+ ----------
93
+ s : string
94
+
95
+ Returns
96
+ -------
97
+ n : int
98
+ """
99
+ warnings.warn(
100
+ "`num_ini_spaces` is Pending Deprecation since IPython 8.17."
101
+ "It is considered for removal in in future version. "
102
+ "Please open an issue if you believe it should be kept.",
103
+ stacklevel=2,
104
+ category=PendingDeprecationWarning,
105
+ )
106
+ ini_spaces = ini_spaces_re.match(s)
107
+ if ini_spaces:
108
+ return ini_spaces.end()
109
+ else:
110
+ return 0
111
+
112
+ # Fake token types for partial_tokenize:
113
+ INCOMPLETE_STRING = tokenize.N_TOKENS
114
+ IN_MULTILINE_STATEMENT = tokenize.N_TOKENS + 1
115
+
116
+ # The 2 classes below have the same API as TokenInfo, but don't try to look up
117
+ # a token type name that they won't find.
118
+ class IncompleteString:
119
+ type = exact_type = INCOMPLETE_STRING
120
+ def __init__(self, s, start, end, line):
121
+ self.s = s
122
+ self.start = start
123
+ self.end = end
124
+ self.line = line
125
+
126
+ class InMultilineStatement:
127
+ type = exact_type = IN_MULTILINE_STATEMENT
128
+ def __init__(self, pos, line):
129
+ self.s = ''
130
+ self.start = self.end = pos
131
+ self.line = line
132
+
133
+ def partial_tokens(s):
134
+ """Iterate over tokens from a possibly-incomplete string of code.
135
+
136
+ This adds two special token types: INCOMPLETE_STRING and
137
+ IN_MULTILINE_STATEMENT. These can only occur as the last token yielded, and
138
+ represent the two main ways for code to be incomplete.
139
+ """
140
+ readline = io.StringIO(s).readline
141
+ token = tokenize.TokenInfo(tokenize.NEWLINE, '', (1, 0), (1, 0), '')
142
+ try:
143
+ for token in tokenutil.generate_tokens_catch_errors(readline):
144
+ yield token
145
+ except tokenize.TokenError as e:
146
+ # catch EOF error
147
+ lines = s.splitlines(keepends=True)
148
+ end = len(lines), len(lines[-1])
149
+ if 'multi-line string' in e.args[0]:
150
+ l, c = start = token.end
151
+ s = lines[l-1][c:] + ''.join(lines[l:])
152
+ yield IncompleteString(s, start, end, lines[-1])
153
+ elif 'multi-line statement' in e.args[0]:
154
+ yield InMultilineStatement(end, lines[-1])
155
+ else:
156
+ raise
157
+
158
+ def find_next_indent(code) -> int:
159
+ """Find the number of spaces for the next line of indentation"""
160
+ tokens = list(partial_tokens(code))
161
+ if tokens[-1].type == tokenize.ENDMARKER:
162
+ tokens.pop()
163
+ if not tokens:
164
+ return 0
165
+
166
+ while tokens[-1].type in {
167
+ tokenize.DEDENT,
168
+ tokenize.NEWLINE,
169
+ tokenize.COMMENT,
170
+ tokenize.ERRORTOKEN,
171
+ }:
172
+ tokens.pop()
173
+
174
+ # Starting in Python 3.12, the tokenize module adds implicit newlines at the end
175
+ # of input. We need to remove those if we're in a multiline statement
176
+ if tokens[-1].type == IN_MULTILINE_STATEMENT:
177
+ while tokens[-2].type in {tokenize.NL}:
178
+ tokens.pop(-2)
179
+
180
+
181
+ if tokens[-1].type == INCOMPLETE_STRING:
182
+ # Inside a multiline string
183
+ return 0
184
+
185
+ # Find the indents used before
186
+ prev_indents = [0]
187
+ def _add_indent(n):
188
+ if n != prev_indents[-1]:
189
+ prev_indents.append(n)
190
+
191
+ tokiter = iter(tokens)
192
+ for tok in tokiter:
193
+ if tok.type in {tokenize.INDENT, tokenize.DEDENT}:
194
+ _add_indent(tok.end[1])
195
+ elif (tok.type == tokenize.NL):
196
+ try:
197
+ _add_indent(next(tokiter).start[1])
198
+ except StopIteration:
199
+ break
200
+
201
+ last_indent = prev_indents.pop()
202
+
203
+ # If we've just opened a multiline statement (e.g. 'a = ['), indent more
204
+ if tokens[-1].type == IN_MULTILINE_STATEMENT:
205
+ if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
206
+ return last_indent + 4
207
+ return last_indent
208
+
209
+ if tokens[-1].exact_type == tokenize.COLON:
210
+ # Line ends with colon - indent
211
+ return last_indent + 4
212
+
213
+ if last_indent:
214
+ # Examine the last line for dedent cues - statements like return or
215
+ # raise which normally end a block of code.
216
+ last_line_starts = 0
217
+ for i, tok in enumerate(tokens):
218
+ if tok.type == tokenize.NEWLINE:
219
+ last_line_starts = i + 1
220
+
221
+ last_line_tokens = tokens[last_line_starts:]
222
+ names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
223
+ if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
224
+ # Find the most recent indentation less than the current level
225
+ for indent in reversed(prev_indents):
226
+ if indent < last_indent:
227
+ return indent
228
+
229
+ return last_indent
230
+
231
+
232
+ def last_blank(src):
233
+ """Determine if the input source ends in a blank.
234
+
235
+ A blank is either a newline or a line consisting of whitespace.
236
+
237
+ Parameters
238
+ ----------
239
+ src : string
240
+ A single or multiline string.
241
+ """
242
+ if not src: return False
243
+ ll = src.splitlines()[-1]
244
+ return (ll == '') or ll.isspace()
245
+
246
+
247
+ last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
248
+ last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
249
+
250
+ def last_two_blanks(src):
251
+ """Determine if the input source ends in two blanks.
252
+
253
+ A blank is either a newline or a line consisting of whitespace.
254
+
255
+ Parameters
256
+ ----------
257
+ src : string
258
+ A single or multiline string.
259
+ """
260
+ if not src: return False
261
+ # The logic here is tricky: I couldn't get a regexp to work and pass all
262
+ # the tests, so I took a different approach: split the source by lines,
263
+ # grab the last two and prepend '###\n' as a stand-in for whatever was in
264
+ # the body before the last two lines. Then, with that structure, it's
265
+ # possible to analyze with two regexps. Not the most elegant solution, but
266
+ # it works. If anyone tries to change this logic, make sure to validate
267
+ # the whole test suite first!
268
+ new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
269
+ return (bool(last_two_blanks_re.match(new_src)) or
270
+ bool(last_two_blanks_re2.match(new_src)) )
271
+
272
+
273
+ def remove_comments(src):
274
+ """Remove all comments from input source.
275
+
276
+ Note: comments are NOT recognized inside of strings!
277
+
278
+ Parameters
279
+ ----------
280
+ src : string
281
+ A single or multiline input string.
282
+
283
+ Returns
284
+ -------
285
+ String with all Python comments removed.
286
+ """
287
+
288
+ return re.sub('#.*', '', src)
289
+
290
+
291
+ def get_input_encoding():
292
+ """Return the default standard input encoding.
293
+
294
+ If sys.stdin has no encoding, 'ascii' is returned."""
295
+ # There are strange environments for which sys.stdin.encoding is None. We
296
+ # ensure that a valid encoding is returned.
297
+ encoding = getattr(sys.stdin, 'encoding', None)
298
+ if encoding is None:
299
+ encoding = 'ascii'
300
+ return encoding
301
+
302
+ #-----------------------------------------------------------------------------
303
+ # Classes and functions for normal Python syntax handling
304
+ #-----------------------------------------------------------------------------
305
+
306
+ class InputSplitter(object):
307
+ r"""An object that can accumulate lines of Python source before execution.
308
+
309
+ This object is designed to be fed python source line-by-line, using
310
+ :meth:`push`. It will return on each push whether the currently pushed
311
+ code could be executed already. In addition, it provides a method called
312
+ :meth:`push_accepts_more` that can be used to query whether more input
313
+ can be pushed into a single interactive block.
314
+
315
+ This is a simple example of how an interactive terminal-based client can use
316
+ this tool::
317
+
318
+ isp = InputSplitter()
319
+ while isp.push_accepts_more():
320
+ indent = ' '*isp.indent_spaces
321
+ prompt = '>>> ' + indent
322
+ line = indent + raw_input(prompt)
323
+ isp.push(line)
324
+ print('Input source was:\n', isp.source_reset())
325
+ """
326
+ # A cache for storing the current indentation
327
+ # The first value stores the most recently processed source input
328
+ # The second value is the number of spaces for the current indentation
329
+ # If self.source matches the first value, the second value is a valid
330
+ # current indentation. Otherwise, the cache is invalid and the indentation
331
+ # must be recalculated.
332
+ _indent_spaces_cache: Union[Tuple[None, None], Tuple[str, int]] = None, None
333
+ # String, indicating the default input encoding. It is computed by default
334
+ # at initialization time via get_input_encoding(), but it can be reset by a
335
+ # client with specific knowledge of the encoding.
336
+ encoding = ''
337
+ # String where the current full source input is stored, properly encoded.
338
+ # Reading this attribute is the normal way of querying the currently pushed
339
+ # source code, that has been properly encoded.
340
+ source: str = ""
341
+ # Code object corresponding to the current source. It is automatically
342
+ # synced to the source, so it can be queried at any time to obtain the code
343
+ # object; it will be None if the source doesn't compile to valid Python.
344
+ code: Optional[CodeType] = None
345
+
346
+ # Private attributes
347
+
348
+ # List with lines of input accumulated so far
349
+ _buffer: List[str]
350
+ # Command compiler
351
+ _compile: codeop.CommandCompiler
352
+ # Boolean indicating whether the current block is complete
353
+ _is_complete: Optional[bool] = None
354
+ # Boolean indicating whether the current block has an unrecoverable syntax error
355
+ _is_invalid: bool = False
356
+
357
+ def __init__(self) -> None:
358
+ """Create a new InputSplitter instance."""
359
+ self._buffer = []
360
+ self._compile = codeop.CommandCompiler()
361
+ self.encoding = get_input_encoding()
362
+
363
+ def reset(self):
364
+ """Reset the input buffer and associated state."""
365
+ self._buffer[:] = []
366
+ self.source = ''
367
+ self.code = None
368
+ self._is_complete = False
369
+ self._is_invalid = False
370
+
371
+ def source_reset(self):
372
+ """Return the input source and perform a full reset.
373
+ """
374
+ out = self.source
375
+ self.reset()
376
+ return out
377
+
378
+ def check_complete(self, source):
379
+ """Return whether a block of code is ready to execute, or should be continued
380
+
381
+ This is a non-stateful API, and will reset the state of this InputSplitter.
382
+
383
+ Parameters
384
+ ----------
385
+ source : string
386
+ Python input code, which can be multiline.
387
+
388
+ Returns
389
+ -------
390
+ status : str
391
+ One of 'complete', 'incomplete', or 'invalid' if source is not a
392
+ prefix of valid code.
393
+ indent_spaces : int or None
394
+ The number of spaces by which to indent the next line of code. If
395
+ status is not 'incomplete', this is None.
396
+ """
397
+ self.reset()
398
+ try:
399
+ self.push(source)
400
+ except SyntaxError:
401
+ # Transformers in IPythonInputSplitter can raise SyntaxError,
402
+ # which push() will not catch.
403
+ return 'invalid', None
404
+ else:
405
+ if self._is_invalid:
406
+ return 'invalid', None
407
+ elif self.push_accepts_more():
408
+ return 'incomplete', self.get_indent_spaces()
409
+ else:
410
+ return 'complete', None
411
+ finally:
412
+ self.reset()
413
+
414
+ def push(self, lines:str) -> bool:
415
+ """Push one or more lines of input.
416
+
417
+ This stores the given lines and returns a status code indicating
418
+ whether the code forms a complete Python block or not.
419
+
420
+ Any exceptions generated in compilation are swallowed, but if an
421
+ exception was produced, the method returns True.
422
+
423
+ Parameters
424
+ ----------
425
+ lines : string
426
+ One or more lines of Python input.
427
+
428
+ Returns
429
+ -------
430
+ is_complete : boolean
431
+ True if the current input source (the result of the current input
432
+ plus prior inputs) forms a complete Python execution block. Note that
433
+ this value is also stored as a private attribute (``_is_complete``), so it
434
+ can be queried at any time.
435
+ """
436
+ assert isinstance(lines, str)
437
+ self._store(lines)
438
+ source = self.source
439
+
440
+ # Before calling _compile(), reset the code object to None so that if an
441
+ # exception is raised in compilation, we don't mislead by having
442
+ # inconsistent code/source attributes.
443
+ self.code, self._is_complete = None, None
444
+ self._is_invalid = False
445
+
446
+ # Honor termination lines properly
447
+ if source.endswith('\\\n'):
448
+ return False
449
+
450
+ try:
451
+ with warnings.catch_warnings():
452
+ warnings.simplefilter('error', SyntaxWarning)
453
+ self.code = self._compile(source, symbol="exec")
454
+ # Invalid syntax can produce any of a number of different errors from
455
+ # inside the compiler, so we have to catch them all. Syntax errors
456
+ # immediately produce a 'ready' block, so the invalid Python can be
457
+ # sent to the kernel for evaluation with possible ipython
458
+ # special-syntax conversion.
459
+ except (SyntaxError, OverflowError, ValueError, TypeError,
460
+ MemoryError, SyntaxWarning):
461
+ self._is_complete = True
462
+ self._is_invalid = True
463
+ else:
464
+ # Compilation didn't produce any exceptions (though it may not have
465
+ # given a complete code object)
466
+ self._is_complete = self.code is not None
467
+
468
+ return self._is_complete
469
+
470
+ def push_accepts_more(self):
471
+ """Return whether a block of interactive input can accept more input.
472
+
473
+ This method is meant to be used by line-oriented frontends, who need to
474
+ guess whether a block is complete or not based solely on prior and
475
+ current input lines. The InputSplitter considers it has a complete
476
+ interactive block and will not accept more input when either:
477
+
478
+ * A SyntaxError is raised
479
+
480
+ * The code is complete and consists of a single line or a single
481
+ non-compound statement
482
+
483
+ * The code is complete and has a blank line at the end
484
+
485
+ If the current input produces a syntax error, this method immediately
486
+ returns False but does *not* raise the syntax error exception, as
487
+ typically clients will want to send invalid syntax to an execution
488
+ backend which might convert the invalid syntax into valid Python via
489
+ one of the dynamic IPython mechanisms.
490
+ """
491
+
492
+ # With incomplete input, unconditionally accept more
493
+ # A syntax error also sets _is_complete to True - see push()
494
+ if not self._is_complete:
495
+ #print("Not complete") # debug
496
+ return True
497
+
498
+ # The user can make any (complete) input execute by leaving a blank line
499
+ last_line = self.source.splitlines()[-1]
500
+ if (not last_line) or last_line.isspace():
501
+ #print("Blank line") # debug
502
+ return False
503
+
504
+ # If there's just a single line or AST node, and we're flush left, as is
505
+ # the case after a simple statement such as 'a=1', we want to execute it
506
+ # straight away.
507
+ if self.get_indent_spaces() == 0:
508
+ if len(self.source.splitlines()) <= 1:
509
+ return False
510
+
511
+ try:
512
+ code_ast = ast.parse("".join(self._buffer))
513
+ except Exception:
514
+ #print("Can't parse AST") # debug
515
+ return False
516
+ else:
517
+ if len(code_ast.body) == 1 and \
518
+ not hasattr(code_ast.body[0], 'body'):
519
+ #print("Simple statement") # debug
520
+ return False
521
+
522
+ # General fallback - accept more code
523
+ return True
524
+
525
+ def get_indent_spaces(self) -> int:
526
+ sourcefor, n = self._indent_spaces_cache
527
+ if sourcefor == self.source:
528
+ assert n is not None
529
+ return n
530
+
531
+ # self.source always has a trailing newline
532
+ n = find_next_indent(self.source[:-1])
533
+ self._indent_spaces_cache = (self.source, n)
534
+ return n
535
+
536
+ # Backwards compatibility. I think all code that used .indent_spaces was
537
+ # inside IPython, but we can leave this here until IPython 7 in case any
538
+ # other modules are using it. -TK, November 2017
539
+ indent_spaces = property(get_indent_spaces)
540
+
541
+ def _store(self, lines, buffer=None, store='source'):
542
+ """Store one or more lines of input.
543
+
544
+ If input lines are not newline-terminated, a newline is automatically
545
+ appended."""
546
+
547
+ if buffer is None:
548
+ buffer = self._buffer
549
+
550
+ if lines.endswith('\n'):
551
+ buffer.append(lines)
552
+ else:
553
+ buffer.append(lines+'\n')
554
+ setattr(self, store, self._set_source(buffer))
555
+
556
+ def _set_source(self, buffer):
557
+ return u''.join(buffer)
558
+
559
+
560
+ class IPythonInputSplitter(InputSplitter):
561
+ """An input splitter that recognizes all of IPython's special syntax."""
562
+
563
+ # String with raw, untransformed input.
564
+ source_raw = ''
565
+
566
+ # Flag to track when a transformer has stored input that it hasn't given
567
+ # back yet.
568
+ transformer_accumulating = False
569
+
570
+ # Flag to track when assemble_python_lines has stored input that it hasn't
571
+ # given back yet.
572
+ within_python_line = False
573
+
574
+ # Private attributes
575
+
576
+ # List with lines of raw input accumulated so far.
577
+ _buffer_raw: List[str]
578
+
579
+ def __init__(self, line_input_checker=True, physical_line_transforms=None,
580
+ logical_line_transforms=None, python_line_transforms=None):
581
+ super(IPythonInputSplitter, self).__init__()
582
+ self._buffer_raw = []
583
+ self._validate = True
584
+
585
+ if physical_line_transforms is not None:
586
+ self.physical_line_transforms = physical_line_transforms
587
+ else:
588
+ self.physical_line_transforms = [
589
+ leading_indent(),
590
+ classic_prompt(),
591
+ ipy_prompt(),
592
+ cellmagic(end_on_blank_line=line_input_checker),
593
+ ]
594
+
595
+ self.assemble_logical_lines = assemble_logical_lines()
596
+ if logical_line_transforms is not None:
597
+ self.logical_line_transforms = logical_line_transforms
598
+ else:
599
+ self.logical_line_transforms = [
600
+ help_end(),
601
+ escaped_commands(),
602
+ assign_from_magic(),
603
+ assign_from_system(),
604
+ ]
605
+
606
+ self.assemble_python_lines = assemble_python_lines()
607
+ if python_line_transforms is not None:
608
+ self.python_line_transforms = python_line_transforms
609
+ else:
610
+ # We don't use any of these at present
611
+ self.python_line_transforms = []
612
+
613
+ @property
614
+ def transforms(self):
615
+ "Quick access to all transformers."
616
+ return self.physical_line_transforms + \
617
+ [self.assemble_logical_lines] + self.logical_line_transforms + \
618
+ [self.assemble_python_lines] + self.python_line_transforms
619
+
620
+ @property
621
+ def transforms_in_use(self):
622
+ """Transformers, excluding logical line transformers if we're in a
623
+ Python line."""
624
+ t = self.physical_line_transforms[:]
625
+ if not self.within_python_line:
626
+ t += [self.assemble_logical_lines] + self.logical_line_transforms
627
+ return t + [self.assemble_python_lines] + self.python_line_transforms
628
+
629
+ def reset(self):
630
+ """Reset the input buffer and associated state."""
631
+ super(IPythonInputSplitter, self).reset()
632
+ self._buffer_raw[:] = []
633
+ self.source_raw = ''
634
+ self.transformer_accumulating = False
635
+ self.within_python_line = False
636
+
637
+ for t in self.transforms:
638
+ try:
639
+ t.reset()
640
+ except SyntaxError:
641
+ # Nothing that calls reset() expects to handle transformer
642
+ # errors
643
+ pass
644
+
645
+ def flush_transformers(self: Self):
646
+ def _flush(transform, outs: List[str]):
647
+ """yield transformed lines
648
+
649
+ always strings, never None
650
+
651
+ transform: the current transform
652
+ outs: an iterable of previously transformed inputs.
653
+ Each may be multiline, which will be passed
654
+ one line at a time to transform.
655
+ """
656
+ for out in outs:
657
+ for line in out.splitlines():
658
+ # push one line at a time
659
+ tmp = transform.push(line)
660
+ if tmp is not None:
661
+ yield tmp
662
+
663
+ # reset the transform
664
+ tmp = transform.reset()
665
+ if tmp is not None:
666
+ yield tmp
667
+
668
+ out: List[str] = []
669
+ for t in self.transforms_in_use:
670
+ out = _flush(t, out)
671
+
672
+ out = list(out)
673
+ if out:
674
+ self._store('\n'.join(out))
675
+
676
+ def raw_reset(self):
677
+ """Return raw input only and perform a full reset.
678
+ """
679
+ out = self.source_raw
680
+ self.reset()
681
+ return out
682
+
683
+ def source_reset(self):
684
+ try:
685
+ self.flush_transformers()
686
+ return self.source
687
+ finally:
688
+ self.reset()
689
+
690
+ def push_accepts_more(self):
691
+ if self.transformer_accumulating:
692
+ return True
693
+ else:
694
+ return super(IPythonInputSplitter, self).push_accepts_more()
695
+
696
+ def transform_cell(self, cell):
697
+ """Process and translate a cell of input.
698
+ """
699
+ self.reset()
700
+ try:
701
+ self.push(cell)
702
+ self.flush_transformers()
703
+ return self.source
704
+ finally:
705
+ self.reset()
706
+
707
+ def push(self, lines:str) -> bool:
708
+ """Push one or more lines of IPython input.
709
+
710
+ This stores the given lines and returns a status code indicating
711
+ whether the code forms a complete Python block or not, after processing
712
+ all input lines for special IPython syntax.
713
+
714
+ Any exceptions generated in compilation are swallowed, but if an
715
+ exception was produced, the method returns True.
716
+
717
+ Parameters
718
+ ----------
719
+ lines : string
720
+ One or more lines of Python input.
721
+
722
+ Returns
723
+ -------
724
+ is_complete : boolean
725
+ True if the current input source (the result of the current input
726
+ plus prior inputs) forms a complete Python execution block. Note that
727
+ this value is also stored as a private attribute (_is_complete), so it
728
+ can be queried at any time.
729
+ """
730
+ assert isinstance(lines, str)
731
+ # We must ensure all input is pure unicode
732
+ # ''.splitlines() --> [], but we need to push the empty line to transformers
733
+ lines_list = lines.splitlines()
734
+ if not lines_list:
735
+ lines_list = ['']
736
+
737
+ # Store raw source before applying any transformations to it. Note
738
+ # that this must be done *after* the reset() call that would otherwise
739
+ # flush the buffer.
740
+ self._store(lines, self._buffer_raw, 'source_raw')
741
+
742
+ transformed_lines_list = []
743
+ for line in lines_list:
744
+ transformed = self._transform_line(line)
745
+ if transformed is not None:
746
+ transformed_lines_list.append(transformed)
747
+
748
+ if transformed_lines_list:
749
+ transformed_lines = '\n'.join(transformed_lines_list)
750
+ return super(IPythonInputSplitter, self).push(transformed_lines)
751
+ else:
752
+ # Got nothing back from transformers - they must be waiting for
753
+ # more input.
754
+ return False
755
+
756
+ def _transform_line(self, line):
757
+ """Push a line of input code through the various transformers.
758
+
759
+ Returns any output from the transformers, or None if a transformer
760
+ is accumulating lines.
761
+
762
+ Sets self.transformer_accumulating as a side effect.
763
+ """
764
+ def _accumulating(dbg):
765
+ #print(dbg)
766
+ self.transformer_accumulating = True
767
+ return None
768
+
769
+ for transformer in self.physical_line_transforms:
770
+ line = transformer.push(line)
771
+ if line is None:
772
+ return _accumulating(transformer)
773
+
774
+ if not self.within_python_line:
775
+ line = self.assemble_logical_lines.push(line)
776
+ if line is None:
777
+ return _accumulating('acc logical line')
778
+
779
+ for transformer in self.logical_line_transforms:
780
+ line = transformer.push(line)
781
+ if line is None:
782
+ return _accumulating(transformer)
783
+
784
+ line = self.assemble_python_lines.push(line)
785
+ if line is None:
786
+ self.within_python_line = True
787
+ return _accumulating('acc python line')
788
+ else:
789
+ self.within_python_line = False
790
+
791
+ for transformer in self.python_line_transforms:
792
+ line = transformer.push(line)
793
+ if line is None:
794
+ return _accumulating(transformer)
795
+
796
+ #print("transformers clear") #debug
797
+ self.transformer_accumulating = False
798
+ return line
799
+
openalex_env_map/lib/python3.10/site-packages/IPython/core/inputtransformer.py ADDED
@@ -0,0 +1,577 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DEPRECATED: Input transformer classes to support IPython special syntax.
2
+
3
+ This module was deprecated in IPython 7.0, in favour of inputtransformer2.
4
+
5
+ This includes the machinery to recognise and transform ``%magic`` commands,
6
+ ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
7
+ """
8
+ import abc
9
+ import functools
10
+ import re
11
+ import tokenize
12
+ import warnings
13
+ from tokenize import untokenize, TokenError
14
+ from io import StringIO
15
+
16
+ from IPython.core.splitinput import LineInfo
17
+ from IPython.utils import tokenutil
18
+
19
+ #-----------------------------------------------------------------------------
20
+ # Globals
21
+ #-----------------------------------------------------------------------------
22
+
23
+ # The escape sequences that define the syntax transformations IPython will
24
+ # apply to user input. These can NOT be just changed here: many regular
25
+ # expressions and other parts of the code may use their hardcoded values, and
26
+ # for all intents and purposes they constitute the 'IPython syntax', so they
27
+ # should be considered fixed.
28
+
29
+ ESC_SHELL = '!' # Send line to underlying system shell
30
+ ESC_SH_CAP = '!!' # Send line to system shell and capture output
31
+ ESC_HELP = '?' # Find information about object
32
+ ESC_HELP2 = '??' # Find extra-detailed information about object
33
+ ESC_MAGIC = '%' # Call magic function
34
+ ESC_MAGIC2 = '%%' # Call cell-magic function
35
+ ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
36
+ ESC_QUOTE2 = ';' # Quote all args as a single string, call
37
+ ESC_PAREN = '/' # Call first argument with rest of line as arguments
38
+
39
+ ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
40
+ ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
41
+ ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
42
+
43
+
44
+ class InputTransformer(metaclass=abc.ABCMeta):
45
+ """Abstract base class for line-based input transformers."""
46
+
47
+ def __init__(self):
48
+ warnings.warn(
49
+ "`InputTransformer` has been deprecated since IPython 7.0"
50
+ " and emit a warnig since IPython 8.31, it"
51
+ " will be removed in the future",
52
+ DeprecationWarning,
53
+ stacklevel=2,
54
+ )
55
+
56
+ @abc.abstractmethod
57
+ def push(self, line):
58
+ """Send a line of input to the transformer, returning the transformed
59
+ input or None if the transformer is waiting for more input.
60
+
61
+ Must be overridden by subclasses.
62
+
63
+ Implementations may raise ``SyntaxError`` if the input is invalid. No
64
+ other exceptions may be raised.
65
+ """
66
+ pass
67
+
68
+ @abc.abstractmethod
69
+ def reset(self):
70
+ """Return, transformed any lines that the transformer has accumulated,
71
+ and reset its internal state.
72
+
73
+ Must be overridden by subclasses.
74
+ """
75
+ pass
76
+
77
+ @classmethod
78
+ def wrap(cls, func):
79
+ """Can be used by subclasses as a decorator, to return a factory that
80
+ will allow instantiation with the decorated object.
81
+ """
82
+ @functools.wraps(func)
83
+ def transformer_factory(**kwargs):
84
+ return cls(func, **kwargs) # type: ignore [call-arg]
85
+
86
+ return transformer_factory
87
+
88
+ class StatelessInputTransformer(InputTransformer):
89
+ """Wrapper for a stateless input transformer implemented as a function."""
90
+ def __init__(self, func):
91
+ super().__init__()
92
+ warnings.warn(
93
+ "`StatelessInputTransformer` has been deprecated since IPython 7.0"
94
+ " and emit a warnig since IPython 8.31, it"
95
+ " will be removed in the future",
96
+ DeprecationWarning,
97
+ stacklevel=2,
98
+ )
99
+ self.func = func
100
+
101
+ def __repr__(self):
102
+ return "StatelessInputTransformer(func={0!r})".format(self.func)
103
+
104
+ def push(self, line):
105
+ """Send a line of input to the transformer, returning the
106
+ transformed input."""
107
+ return self.func(line)
108
+
109
+ def reset(self):
110
+ """No-op - exists for compatibility."""
111
+ pass
112
+
113
+ class CoroutineInputTransformer(InputTransformer):
114
+ """Wrapper for an input transformer implemented as a coroutine."""
115
+ def __init__(self, coro, **kwargs):
116
+ # Prime it
117
+ super().__init__()
118
+ warnings.warn(
119
+ "`CoroutineInputTransformer` has been deprecated since IPython 7.0"
120
+ " and emit a warnig since IPython 8.31, it"
121
+ " will be removed in the future",
122
+ DeprecationWarning,
123
+ stacklevel=2,
124
+ )
125
+ self.coro = coro(**kwargs)
126
+ next(self.coro)
127
+
128
+ def __repr__(self):
129
+ return "CoroutineInputTransformer(coro={0!r})".format(self.coro)
130
+
131
+ def push(self, line):
132
+ """Send a line of input to the transformer, returning the
133
+ transformed input or None if the transformer is waiting for more
134
+ input.
135
+ """
136
+ return self.coro.send(line)
137
+
138
+ def reset(self):
139
+ """Return, transformed any lines that the transformer has
140
+ accumulated, and reset its internal state.
141
+ """
142
+ return self.coro.send(None)
143
+
144
+ class TokenInputTransformer(InputTransformer):
145
+ """Wrapper for a token-based input transformer.
146
+
147
+ func should accept a list of tokens (5-tuples, see tokenize docs), and
148
+ return an iterable which can be passed to tokenize.untokenize().
149
+ """
150
+ def __init__(self, func):
151
+ warnings.warn(
152
+ "`CoroutineInputTransformer` has been deprecated since IPython 7.0"
153
+ " and emit a warnig since IPython 8.31, it"
154
+ " will be removed in the future",
155
+ DeprecationWarning,
156
+ stacklevel=2,
157
+ )
158
+ self.func = func
159
+ self.buf = []
160
+ self.reset_tokenizer()
161
+
162
+ def reset_tokenizer(self):
163
+ it = iter(self.buf)
164
+ self.tokenizer = tokenutil.generate_tokens_catch_errors(it.__next__)
165
+
166
+ def push(self, line):
167
+ self.buf.append(line + '\n')
168
+ if all(l.isspace() for l in self.buf):
169
+ return self.reset()
170
+
171
+ tokens = []
172
+ stop_at_NL = False
173
+ try:
174
+ for intok in self.tokenizer:
175
+ tokens.append(intok)
176
+ t = intok[0]
177
+ if t == tokenize.NEWLINE or (stop_at_NL and t == tokenize.NL):
178
+ # Stop before we try to pull a line we don't have yet
179
+ break
180
+ elif t == tokenize.ERRORTOKEN:
181
+ stop_at_NL = True
182
+ except TokenError:
183
+ # Multi-line statement - stop and try again with the next line
184
+ self.reset_tokenizer()
185
+ return None
186
+
187
+ return self.output(tokens)
188
+
189
+ def output(self, tokens):
190
+ self.buf.clear()
191
+ self.reset_tokenizer()
192
+ return untokenize(self.func(tokens)).rstrip('\n')
193
+
194
+ def reset(self):
195
+ l = ''.join(self.buf)
196
+ self.buf.clear()
197
+ self.reset_tokenizer()
198
+ if l:
199
+ return l.rstrip('\n')
200
+
201
+ class assemble_python_lines(TokenInputTransformer):
202
+ def __init__(self):
203
+ super().__init__(None)
204
+
205
+ def output(self, tokens):
206
+ return self.reset()
207
+
208
+ @CoroutineInputTransformer.wrap
209
+ def assemble_logical_lines():
210
+ r"""Join lines following explicit line continuations (\)"""
211
+ line = ''
212
+ while True:
213
+ line = (yield line)
214
+ if not line or line.isspace():
215
+ continue
216
+
217
+ parts = []
218
+ while line is not None:
219
+ if line.endswith('\\') and (not has_comment(line)):
220
+ parts.append(line[:-1])
221
+ line = (yield None) # Get another line
222
+ else:
223
+ parts.append(line)
224
+ break
225
+
226
+ # Output
227
+ line = ''.join(parts)
228
+
229
+ # Utilities
230
+ def _make_help_call(target: str, esc: str, lspace: str) -> str:
231
+ """Prepares a pinfo(2)/psearch call from a target name and the escape
232
+ (i.e. ? or ??)"""
233
+ method = 'pinfo2' if esc == '??' \
234
+ else 'psearch' if '*' in target \
235
+ else 'pinfo'
236
+ arg = " ".join([method, target])
237
+ #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
238
+ t_magic_name, _, t_magic_arg_s = arg.partition(' ')
239
+ t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
240
+ return "%sget_ipython().run_line_magic(%r, %r)" % (
241
+ lspace,
242
+ t_magic_name,
243
+ t_magic_arg_s,
244
+ )
245
+
246
+
247
+ # These define the transformations for the different escape characters.
248
+ def _tr_system(line_info: LineInfo):
249
+ "Translate lines escaped with: !"
250
+ cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
251
+ return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
252
+
253
+
254
+ def _tr_system2(line_info: LineInfo):
255
+ "Translate lines escaped with: !!"
256
+ cmd = line_info.line.lstrip()[2:]
257
+ return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
258
+
259
+
260
+ def _tr_help(line_info: LineInfo):
261
+ "Translate lines escaped with: ?/??"
262
+ # A naked help line should just fire the intro help screen
263
+ if not line_info.line[1:]:
264
+ return 'get_ipython().show_usage()'
265
+
266
+ return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
267
+
268
+
269
+ def _tr_magic(line_info: LineInfo):
270
+ "Translate lines escaped with: %"
271
+ tpl = '%sget_ipython().run_line_magic(%r, %r)'
272
+ if line_info.line.startswith(ESC_MAGIC2):
273
+ return line_info.line
274
+ cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
275
+ #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
276
+ t_magic_name, _, t_magic_arg_s = cmd.partition(' ')
277
+ t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
278
+ return tpl % (line_info.pre, t_magic_name, t_magic_arg_s)
279
+
280
+
281
+ def _tr_quote(line_info: LineInfo):
282
+ "Translate lines escaped with: ,"
283
+ return '%s%s("%s")' % (line_info.pre, line_info.ifun,
284
+ '", "'.join(line_info.the_rest.split()) )
285
+
286
+
287
+ def _tr_quote2(line_info: LineInfo):
288
+ "Translate lines escaped with: ;"
289
+ return '%s%s("%s")' % (line_info.pre, line_info.ifun,
290
+ line_info.the_rest)
291
+
292
+
293
+ def _tr_paren(line_info: LineInfo):
294
+ "Translate lines escaped with: /"
295
+ return '%s%s(%s)' % (line_info.pre, line_info.ifun,
296
+ ", ".join(line_info.the_rest.split()))
297
+
298
+ tr = { ESC_SHELL : _tr_system,
299
+ ESC_SH_CAP : _tr_system2,
300
+ ESC_HELP : _tr_help,
301
+ ESC_HELP2 : _tr_help,
302
+ ESC_MAGIC : _tr_magic,
303
+ ESC_QUOTE : _tr_quote,
304
+ ESC_QUOTE2 : _tr_quote2,
305
+ ESC_PAREN : _tr_paren }
306
+
307
+ @StatelessInputTransformer.wrap
308
+ def escaped_commands(line: str):
309
+ """Transform escaped commands - %magic, !system, ?help + various autocalls."""
310
+ if not line or line.isspace():
311
+ return line
312
+ lineinf = LineInfo(line)
313
+ if lineinf.esc not in tr:
314
+ return line
315
+
316
+ return tr[lineinf.esc](lineinf)
317
+
318
+ _initial_space_re = re.compile(r'\s*')
319
+
320
+ _help_end_re = re.compile(r"""(%{0,2}
321
+ (?!\d)[\w*]+ # Variable name
322
+ (\.(?!\d)[\w*]+)* # .etc.etc
323
+ )
324
+ (\?\??)$ # ? or ??
325
+ """,
326
+ re.VERBOSE)
327
+
328
+ # Extra pseudotokens for multiline strings and data structures
329
+ _MULTILINE_STRING = object()
330
+ _MULTILINE_STRUCTURE = object()
331
+
332
+ def _line_tokens(line):
333
+ """Helper for has_comment and ends_in_comment_or_string."""
334
+ readline = StringIO(line).readline
335
+ toktypes = set()
336
+ try:
337
+ for t in tokenutil.generate_tokens_catch_errors(readline):
338
+ toktypes.add(t[0])
339
+ except TokenError as e:
340
+ # There are only two cases where a TokenError is raised.
341
+ if 'multi-line string' in e.args[0]:
342
+ toktypes.add(_MULTILINE_STRING)
343
+ else:
344
+ toktypes.add(_MULTILINE_STRUCTURE)
345
+ return toktypes
346
+
347
+ def has_comment(src):
348
+ """Indicate whether an input line has (i.e. ends in, or is) a comment.
349
+
350
+ This uses tokenize, so it can distinguish comments from # inside strings.
351
+
352
+ Parameters
353
+ ----------
354
+ src : string
355
+ A single line input string.
356
+
357
+ Returns
358
+ -------
359
+ comment : bool
360
+ True if source has a comment.
361
+ """
362
+ return (tokenize.COMMENT in _line_tokens(src))
363
+
364
+ def ends_in_comment_or_string(src):
365
+ """Indicates whether or not an input line ends in a comment or within
366
+ a multiline string.
367
+
368
+ Parameters
369
+ ----------
370
+ src : string
371
+ A single line input string.
372
+
373
+ Returns
374
+ -------
375
+ comment : bool
376
+ True if source ends in a comment or multiline string.
377
+ """
378
+ toktypes = _line_tokens(src)
379
+ return (tokenize.COMMENT in toktypes) or (_MULTILINE_STRING in toktypes)
380
+
381
+
382
+ @StatelessInputTransformer.wrap
383
+ def help_end(line: str):
384
+ """Translate lines with ?/?? at the end"""
385
+ m = _help_end_re.search(line)
386
+ if m is None or ends_in_comment_or_string(line):
387
+ return line
388
+ target = m.group(1)
389
+ esc = m.group(3)
390
+ match = _initial_space_re.match(line)
391
+ assert match is not None
392
+ lspace = match.group(0)
393
+
394
+ return _make_help_call(target, esc, lspace)
395
+
396
+
397
+ @CoroutineInputTransformer.wrap
398
+ def cellmagic(end_on_blank_line: bool = False):
399
+ """Captures & transforms cell magics.
400
+
401
+ After a cell magic is started, this stores up any lines it gets until it is
402
+ reset (sent None).
403
+ """
404
+ tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
405
+ cellmagic_help_re = re.compile(r'%%\w+\?')
406
+ line = ''
407
+ while True:
408
+ line = (yield line)
409
+ # consume leading empty lines
410
+ while not line:
411
+ line = (yield line)
412
+
413
+ if not line.startswith(ESC_MAGIC2):
414
+ # This isn't a cell magic, idle waiting for reset then start over
415
+ while line is not None:
416
+ line = (yield line)
417
+ continue
418
+
419
+ if cellmagic_help_re.match(line):
420
+ # This case will be handled by help_end
421
+ continue
422
+
423
+ first = line
424
+ body = []
425
+ line = (yield None)
426
+ while (line is not None) and \
427
+ ((line.strip() != '') or not end_on_blank_line):
428
+ body.append(line)
429
+ line = (yield None)
430
+
431
+ # Output
432
+ magic_name, _, first = first.partition(' ')
433
+ magic_name = magic_name.lstrip(ESC_MAGIC2)
434
+ line = tpl % (magic_name, first, u'\n'.join(body))
435
+
436
+
437
+ def _strip_prompts(prompt_re, initial_re=None, turnoff_re=None):
438
+ """Remove matching input prompts from a block of input.
439
+
440
+ Parameters
441
+ ----------
442
+ prompt_re : regular expression
443
+ A regular expression matching any input prompt (including continuation)
444
+ initial_re : regular expression, optional
445
+ A regular expression matching only the initial prompt, but not continuation.
446
+ If no initial expression is given, prompt_re will be used everywhere.
447
+ Used mainly for plain Python prompts, where the continuation prompt
448
+ ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
449
+
450
+ Notes
451
+ -----
452
+ If `initial_re` and `prompt_re differ`,
453
+ only `initial_re` will be tested against the first line.
454
+ If any prompt is found on the first two lines,
455
+ prompts will be stripped from the rest of the block.
456
+ """
457
+ if initial_re is None:
458
+ initial_re = prompt_re
459
+ line = ''
460
+ while True:
461
+ line = (yield line)
462
+
463
+ # First line of cell
464
+ if line is None:
465
+ continue
466
+ out, n1 = initial_re.subn('', line, count=1)
467
+ if turnoff_re and not n1:
468
+ if turnoff_re.match(line):
469
+ # We're in e.g. a cell magic; disable this transformer for
470
+ # the rest of the cell.
471
+ while line is not None:
472
+ line = (yield line)
473
+ continue
474
+
475
+ line = (yield out)
476
+
477
+ if line is None:
478
+ continue
479
+ # check for any prompt on the second line of the cell,
480
+ # because people often copy from just after the first prompt,
481
+ # so we might not see it in the first line.
482
+ out, n2 = prompt_re.subn('', line, count=1)
483
+ line = (yield out)
484
+
485
+ if n1 or n2:
486
+ # Found a prompt in the first two lines - check for it in
487
+ # the rest of the cell as well.
488
+ while line is not None:
489
+ line = (yield prompt_re.sub('', line, count=1))
490
+
491
+ else:
492
+ # Prompts not in input - wait for reset
493
+ while line is not None:
494
+ line = (yield line)
495
+
496
+ @CoroutineInputTransformer.wrap
497
+ def classic_prompt():
498
+ """Strip the >>>/... prompts of the Python interactive shell."""
499
+ # FIXME: non-capturing version (?:...) usable?
500
+ prompt_re = re.compile(r'^(>>>|\.\.\.)( |$)')
501
+ initial_re = re.compile(r'^>>>( |$)')
502
+ # Any %magic/!system is IPython syntax, so we needn't look for >>> prompts
503
+ turnoff_re = re.compile(r'^[%!]')
504
+ return _strip_prompts(prompt_re, initial_re, turnoff_re)
505
+
506
+ @CoroutineInputTransformer.wrap
507
+ def ipy_prompt():
508
+ """Strip IPython's In [1]:/...: prompts."""
509
+ # FIXME: non-capturing version (?:...) usable?
510
+ prompt_re = re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)')
511
+ # Disable prompt stripping inside cell magics
512
+ turnoff_re = re.compile(r'^%%')
513
+ return _strip_prompts(prompt_re, turnoff_re=turnoff_re)
514
+
515
+
516
+ @CoroutineInputTransformer.wrap
517
+ def leading_indent():
518
+ """Remove leading indentation.
519
+
520
+ If the first line starts with a spaces or tabs, the same whitespace will be
521
+ removed from each following line until it is reset.
522
+ """
523
+ space_re = re.compile(r'^[ \t]+')
524
+ line = ''
525
+ while True:
526
+ line = (yield line)
527
+
528
+ if line is None:
529
+ continue
530
+
531
+ m = space_re.match(line)
532
+ if m:
533
+ space = m.group(0)
534
+ while line is not None:
535
+ if line.startswith(space):
536
+ line = line[len(space):]
537
+ line = (yield line)
538
+ else:
539
+ # No leading spaces - wait for reset
540
+ while line is not None:
541
+ line = (yield line)
542
+
543
+
544
+ _assign_pat = \
545
+ r'''(?P<lhs>(\s*)
546
+ ([\w\.]+) # Initial identifier
547
+ (\s*,\s*
548
+ \*?[\w\.]+)* # Further identifiers for unpacking
549
+ \s*?,? # Trailing comma
550
+ )
551
+ \s*=\s*
552
+ '''
553
+
554
+ assign_system_re = re.compile(r'{}!\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
555
+ assign_system_template = '%s = get_ipython().getoutput(%r)'
556
+ @StatelessInputTransformer.wrap
557
+ def assign_from_system(line):
558
+ """Transform assignment from system commands (e.g. files = !ls)"""
559
+ m = assign_system_re.match(line)
560
+ if m is None:
561
+ return line
562
+
563
+ return assign_system_template % m.group('lhs', 'cmd')
564
+
565
+ assign_magic_re = re.compile(r'{}%\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
566
+ assign_magic_template = '%s = get_ipython().run_line_magic(%r, %r)'
567
+ @StatelessInputTransformer.wrap
568
+ def assign_from_magic(line):
569
+ """Transform assignment from magic commands (e.g. a = %who_ls)"""
570
+ m = assign_magic_re.match(line)
571
+ if m is None:
572
+ return line
573
+ #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
574
+ m_lhs, m_cmd = m.group('lhs', 'cmd')
575
+ t_magic_name, _, t_magic_arg_s = m_cmd.partition(' ')
576
+ t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
577
+ return assign_magic_template % (m_lhs, t_magic_name, t_magic_arg_s)
openalex_env_map/lib/python3.10/site-packages/IPython/core/inputtransformer2.py ADDED
@@ -0,0 +1,830 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Input transformer machinery to support IPython special syntax.
2
+
3
+ This includes the machinery to recognise and transform ``%magic`` commands,
4
+ ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
5
+
6
+ Added: IPython 7.0. Replaces inputsplitter and inputtransformer which were
7
+ deprecated in 7.0.
8
+ """
9
+
10
+ # Copyright (c) IPython Development Team.
11
+ # Distributed under the terms of the Modified BSD License.
12
+
13
+ import ast
14
+ from codeop import CommandCompiler, Compile
15
+ import re
16
+ import sys
17
+ import tokenize
18
+ from typing import List, Tuple, Optional, Any
19
+ import warnings
20
+
21
+ from IPython.utils import tokenutil
22
+
23
+ _indent_re = re.compile(r'^[ \t]+')
24
+
25
+ def leading_empty_lines(lines):
26
+ """Remove leading empty lines
27
+
28
+ If the leading lines are empty or contain only whitespace, they will be
29
+ removed.
30
+ """
31
+ if not lines:
32
+ return lines
33
+ for i, line in enumerate(lines):
34
+ if line and not line.isspace():
35
+ return lines[i:]
36
+ return lines
37
+
38
+ def leading_indent(lines):
39
+ """Remove leading indentation.
40
+
41
+ If the first line starts with a spaces or tabs, the same whitespace will be
42
+ removed from each following line in the cell.
43
+ """
44
+ if not lines:
45
+ return lines
46
+ m = _indent_re.match(lines[0])
47
+ if not m:
48
+ return lines
49
+ space = m.group(0)
50
+ n = len(space)
51
+ return [l[n:] if l.startswith(space) else l
52
+ for l in lines]
53
+
54
+ class PromptStripper:
55
+ """Remove matching input prompts from a block of input.
56
+
57
+ Parameters
58
+ ----------
59
+ prompt_re : regular expression
60
+ A regular expression matching any input prompt (including continuation,
61
+ e.g. ``...``)
62
+ initial_re : regular expression, optional
63
+ A regular expression matching only the initial prompt, but not continuation.
64
+ If no initial expression is given, prompt_re will be used everywhere.
65
+ Used mainly for plain Python prompts (``>>>``), where the continuation prompt
66
+ ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
67
+
68
+ Notes
69
+ -----
70
+
71
+ If initial_re and prompt_re differ,
72
+ only initial_re will be tested against the first line.
73
+ If any prompt is found on the first two lines,
74
+ prompts will be stripped from the rest of the block.
75
+ """
76
+ def __init__(self, prompt_re, initial_re=None):
77
+ self.prompt_re = prompt_re
78
+ self.initial_re = initial_re or prompt_re
79
+
80
+ def _strip(self, lines):
81
+ return [self.prompt_re.sub('', l, count=1) for l in lines]
82
+
83
+ def __call__(self, lines):
84
+ if not lines:
85
+ return lines
86
+ if self.initial_re.match(lines[0]) or \
87
+ (len(lines) > 1 and self.prompt_re.match(lines[1])):
88
+ return self._strip(lines)
89
+ return lines
90
+
91
+ classic_prompt = PromptStripper(
92
+ prompt_re=re.compile(r'^(>>>|\.\.\.)( |$)'),
93
+ initial_re=re.compile(r'^>>>( |$)')
94
+ )
95
+
96
+ ipython_prompt = PromptStripper(
97
+ re.compile(
98
+ r"""
99
+ ^( # Match from the beginning of a line, either:
100
+
101
+ # 1. First-line prompt:
102
+ ((\[nav\]|\[ins\])?\ )? # Vi editing mode prompt, if it's there
103
+ In\ # The 'In' of the prompt, with a space
104
+ \[\d+\]: # Command index, as displayed in the prompt
105
+ \ # With a mandatory trailing space
106
+
107
+ | # ... or ...
108
+
109
+ # 2. The three dots of the multiline prompt
110
+ \s* # All leading whitespace characters
111
+ \.{3,}: # The three (or more) dots
112
+ \ ? # With an optional trailing space
113
+
114
+ )
115
+ """,
116
+ re.VERBOSE,
117
+ )
118
+ )
119
+
120
+
121
+ def cell_magic(lines):
122
+ if not lines or not lines[0].startswith('%%'):
123
+ return lines
124
+ if re.match(r'%%\w+\?', lines[0]):
125
+ # This case will be handled by help_end
126
+ return lines
127
+ magic_name, _, first_line = lines[0][2:].rstrip().partition(' ')
128
+ body = ''.join(lines[1:])
129
+ return ['get_ipython().run_cell_magic(%r, %r, %r)\n'
130
+ % (magic_name, first_line, body)]
131
+
132
+
133
+ def _find_assign_op(token_line) -> Optional[int]:
134
+ """Get the index of the first assignment in the line ('=' not inside brackets)
135
+
136
+ Note: We don't try to support multiple special assignment (a = b = %foo)
137
+ """
138
+ paren_level = 0
139
+ for i, ti in enumerate(token_line):
140
+ s = ti.string
141
+ if s == '=' and paren_level == 0:
142
+ return i
143
+ if s in {'(','[','{'}:
144
+ paren_level += 1
145
+ elif s in {')', ']', '}'}:
146
+ if paren_level > 0:
147
+ paren_level -= 1
148
+ return None
149
+
150
+ def find_end_of_continued_line(lines, start_line: int):
151
+ """Find the last line of a line explicitly extended using backslashes.
152
+
153
+ Uses 0-indexed line numbers.
154
+ """
155
+ end_line = start_line
156
+ while lines[end_line].endswith('\\\n'):
157
+ end_line += 1
158
+ if end_line >= len(lines):
159
+ break
160
+ return end_line
161
+
162
+ def assemble_continued_line(lines, start: Tuple[int, int], end_line: int):
163
+ r"""Assemble a single line from multiple continued line pieces
164
+
165
+ Continued lines are lines ending in ``\``, and the line following the last
166
+ ``\`` in the block.
167
+
168
+ For example, this code continues over multiple lines::
169
+
170
+ if (assign_ix is not None) \
171
+ and (len(line) >= assign_ix + 2) \
172
+ and (line[assign_ix+1].string == '%') \
173
+ and (line[assign_ix+2].type == tokenize.NAME):
174
+
175
+ This statement contains four continued line pieces.
176
+ Assembling these pieces into a single line would give::
177
+
178
+ if (assign_ix is not None) and (len(line) >= assign_ix + 2) and (line[...
179
+
180
+ This uses 0-indexed line numbers. *start* is (lineno, colno).
181
+
182
+ Used to allow ``%magic`` and ``!system`` commands to be continued over
183
+ multiple lines.
184
+ """
185
+ parts = [lines[start[0]][start[1]:]] + lines[start[0]+1:end_line+1]
186
+ return ' '.join([p.rstrip()[:-1] for p in parts[:-1]] # Strip backslash+newline
187
+ + [parts[-1].rstrip()]) # Strip newline from last line
188
+
189
+ class TokenTransformBase:
190
+ """Base class for transformations which examine tokens.
191
+
192
+ Special syntax should not be transformed when it occurs inside strings or
193
+ comments. This is hard to reliably avoid with regexes. The solution is to
194
+ tokenise the code as Python, and recognise the special syntax in the tokens.
195
+
196
+ IPython's special syntax is not valid Python syntax, so tokenising may go
197
+ wrong after the special syntax starts. These classes therefore find and
198
+ transform *one* instance of special syntax at a time into regular Python
199
+ syntax. After each transformation, tokens are regenerated to find the next
200
+ piece of special syntax.
201
+
202
+ Subclasses need to implement one class method (find)
203
+ and one regular method (transform).
204
+
205
+ The priority attribute can select which transformation to apply if multiple
206
+ transformers match in the same place. Lower numbers have higher priority.
207
+ This allows "%magic?" to be turned into a help call rather than a magic call.
208
+ """
209
+ # Lower numbers -> higher priority (for matches in the same location)
210
+ priority = 10
211
+
212
+ def sortby(self):
213
+ return self.start_line, self.start_col, self.priority
214
+
215
+ def __init__(self, start):
216
+ self.start_line = start[0] - 1 # Shift from 1-index to 0-index
217
+ self.start_col = start[1]
218
+
219
+ @classmethod
220
+ def find(cls, tokens_by_line):
221
+ """Find one instance of special syntax in the provided tokens.
222
+
223
+ Tokens are grouped into logical lines for convenience,
224
+ so it is easy to e.g. look at the first token of each line.
225
+ *tokens_by_line* is a list of lists of tokenize.TokenInfo objects.
226
+
227
+ This should return an instance of its class, pointing to the start
228
+ position it has found, or None if it found no match.
229
+ """
230
+ raise NotImplementedError
231
+
232
+ def transform(self, lines: List[str]):
233
+ """Transform one instance of special syntax found by ``find()``
234
+
235
+ Takes a list of strings representing physical lines,
236
+ returns a similar list of transformed lines.
237
+ """
238
+ raise NotImplementedError
239
+
240
+ class MagicAssign(TokenTransformBase):
241
+ """Transformer for assignments from magics (a = %foo)"""
242
+ @classmethod
243
+ def find(cls, tokens_by_line):
244
+ """Find the first magic assignment (a = %foo) in the cell.
245
+ """
246
+ for line in tokens_by_line:
247
+ assign_ix = _find_assign_op(line)
248
+ if (assign_ix is not None) \
249
+ and (len(line) >= assign_ix + 2) \
250
+ and (line[assign_ix+1].string == '%') \
251
+ and (line[assign_ix+2].type == tokenize.NAME):
252
+ return cls(line[assign_ix+1].start)
253
+
254
+ def transform(self, lines: List[str]):
255
+ """Transform a magic assignment found by the ``find()`` classmethod.
256
+ """
257
+ start_line, start_col = self.start_line, self.start_col
258
+ lhs = lines[start_line][:start_col]
259
+ end_line = find_end_of_continued_line(lines, start_line)
260
+ rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
261
+ assert rhs.startswith('%'), rhs
262
+ magic_name, _, args = rhs[1:].partition(' ')
263
+
264
+ lines_before = lines[:start_line]
265
+ call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args)
266
+ new_line = lhs + call + '\n'
267
+ lines_after = lines[end_line+1:]
268
+
269
+ return lines_before + [new_line] + lines_after
270
+
271
+
272
+ class SystemAssign(TokenTransformBase):
273
+ """Transformer for assignments from system commands (a = !foo)"""
274
+ @classmethod
275
+ def find_pre_312(cls, tokens_by_line):
276
+ for line in tokens_by_line:
277
+ assign_ix = _find_assign_op(line)
278
+ if (assign_ix is not None) \
279
+ and not line[assign_ix].line.strip().startswith('=') \
280
+ and (len(line) >= assign_ix + 2) \
281
+ and (line[assign_ix + 1].type == tokenize.ERRORTOKEN):
282
+ ix = assign_ix + 1
283
+
284
+ while ix < len(line) and line[ix].type == tokenize.ERRORTOKEN:
285
+ if line[ix].string == '!':
286
+ return cls(line[ix].start)
287
+ elif not line[ix].string.isspace():
288
+ break
289
+ ix += 1
290
+
291
+ @classmethod
292
+ def find_post_312(cls, tokens_by_line):
293
+ for line in tokens_by_line:
294
+ assign_ix = _find_assign_op(line)
295
+ if (
296
+ (assign_ix is not None)
297
+ and not line[assign_ix].line.strip().startswith("=")
298
+ and (len(line) >= assign_ix + 2)
299
+ and (line[assign_ix + 1].type == tokenize.OP)
300
+ and (line[assign_ix + 1].string == "!")
301
+ ):
302
+ return cls(line[assign_ix + 1].start)
303
+
304
+ @classmethod
305
+ def find(cls, tokens_by_line):
306
+ """Find the first system assignment (a = !foo) in the cell."""
307
+ if sys.version_info < (3, 12):
308
+ return cls.find_pre_312(tokens_by_line)
309
+ return cls.find_post_312(tokens_by_line)
310
+
311
+ def transform(self, lines: List[str]):
312
+ """Transform a system assignment found by the ``find()`` classmethod.
313
+ """
314
+ start_line, start_col = self.start_line, self.start_col
315
+
316
+ lhs = lines[start_line][:start_col]
317
+ end_line = find_end_of_continued_line(lines, start_line)
318
+ rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
319
+ assert rhs.startswith('!'), rhs
320
+ cmd = rhs[1:]
321
+
322
+ lines_before = lines[:start_line]
323
+ call = "get_ipython().getoutput({!r})".format(cmd)
324
+ new_line = lhs + call + '\n'
325
+ lines_after = lines[end_line + 1:]
326
+
327
+ return lines_before + [new_line] + lines_after
328
+
329
+ # The escape sequences that define the syntax transformations IPython will
330
+ # apply to user input. These can NOT be just changed here: many regular
331
+ # expressions and other parts of the code may use their hardcoded values, and
332
+ # for all intents and purposes they constitute the 'IPython syntax', so they
333
+ # should be considered fixed.
334
+
335
+ ESC_SHELL = '!' # Send line to underlying system shell
336
+ ESC_SH_CAP = '!!' # Send line to system shell and capture output
337
+ ESC_HELP = '?' # Find information about object
338
+ ESC_HELP2 = '??' # Find extra-detailed information about object
339
+ ESC_MAGIC = '%' # Call magic function
340
+ ESC_MAGIC2 = '%%' # Call cell-magic function
341
+ ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
342
+ ESC_QUOTE2 = ';' # Quote all args as a single string, call
343
+ ESC_PAREN = '/' # Call first argument with rest of line as arguments
344
+
345
+ ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
346
+ ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
347
+
348
+ def _make_help_call(target, esc):
349
+ """Prepares a pinfo(2)/psearch call from a target name and the escape
350
+ (i.e. ? or ??)"""
351
+ method = 'pinfo2' if esc == '??' \
352
+ else 'psearch' if '*' in target \
353
+ else 'pinfo'
354
+ arg = " ".join([method, target])
355
+ #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
356
+ t_magic_name, _, t_magic_arg_s = arg.partition(' ')
357
+ t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
358
+ return "get_ipython().run_line_magic(%r, %r)" % (t_magic_name, t_magic_arg_s)
359
+
360
+
361
+ def _tr_help(content):
362
+ """Translate lines escaped with: ?
363
+
364
+ A naked help line should fire the intro help screen (shell.show_usage())
365
+ """
366
+ if not content:
367
+ return 'get_ipython().show_usage()'
368
+
369
+ return _make_help_call(content, '?')
370
+
371
+ def _tr_help2(content):
372
+ """Translate lines escaped with: ??
373
+
374
+ A naked help line should fire the intro help screen (shell.show_usage())
375
+ """
376
+ if not content:
377
+ return 'get_ipython().show_usage()'
378
+
379
+ return _make_help_call(content, '??')
380
+
381
+ def _tr_magic(content):
382
+ "Translate lines escaped with a percent sign: %"
383
+ name, _, args = content.partition(' ')
384
+ return 'get_ipython().run_line_magic(%r, %r)' % (name, args)
385
+
386
+ def _tr_quote(content):
387
+ "Translate lines escaped with a comma: ,"
388
+ name, _, args = content.partition(' ')
389
+ return '%s("%s")' % (name, '", "'.join(args.split()) )
390
+
391
+ def _tr_quote2(content):
392
+ "Translate lines escaped with a semicolon: ;"
393
+ name, _, args = content.partition(' ')
394
+ return '%s("%s")' % (name, args)
395
+
396
+ def _tr_paren(content):
397
+ "Translate lines escaped with a slash: /"
398
+ name, _, args = content.partition(" ")
399
+ if name == "":
400
+ raise SyntaxError(f'"{ESC_SHELL}" must be followed by a callable name')
401
+
402
+ return '%s(%s)' % (name, ", ".join(args.split()))
403
+
404
+ tr = { ESC_SHELL : 'get_ipython().system({!r})'.format,
405
+ ESC_SH_CAP : 'get_ipython().getoutput({!r})'.format,
406
+ ESC_HELP : _tr_help,
407
+ ESC_HELP2 : _tr_help2,
408
+ ESC_MAGIC : _tr_magic,
409
+ ESC_QUOTE : _tr_quote,
410
+ ESC_QUOTE2 : _tr_quote2,
411
+ ESC_PAREN : _tr_paren }
412
+
413
+ class EscapedCommand(TokenTransformBase):
414
+ """Transformer for escaped commands like %foo, !foo, or /foo"""
415
+ @classmethod
416
+ def find(cls, tokens_by_line):
417
+ """Find the first escaped command (%foo, !foo, etc.) in the cell.
418
+ """
419
+ for line in tokens_by_line:
420
+ if not line:
421
+ continue
422
+ ix = 0
423
+ ll = len(line)
424
+ while ll > ix and line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
425
+ ix += 1
426
+ if ix >= ll:
427
+ continue
428
+ if line[ix].string in ESCAPE_SINGLES:
429
+ return cls(line[ix].start)
430
+
431
+ def transform(self, lines):
432
+ """Transform an escaped line found by the ``find()`` classmethod.
433
+ """
434
+ start_line, start_col = self.start_line, self.start_col
435
+
436
+ indent = lines[start_line][:start_col]
437
+ end_line = find_end_of_continued_line(lines, start_line)
438
+ line = assemble_continued_line(lines, (start_line, start_col), end_line)
439
+
440
+ if len(line) > 1 and line[:2] in ESCAPE_DOUBLES:
441
+ escape, content = line[:2], line[2:]
442
+ else:
443
+ escape, content = line[:1], line[1:]
444
+
445
+ if escape in tr:
446
+ call = tr[escape](content)
447
+ else:
448
+ call = ''
449
+
450
+ lines_before = lines[:start_line]
451
+ new_line = indent + call + '\n'
452
+ lines_after = lines[end_line + 1:]
453
+
454
+ return lines_before + [new_line] + lines_after
455
+
456
+
457
+ _help_end_re = re.compile(
458
+ r"""(%{0,2}
459
+ (?!\d)[\w*]+ # Variable name
460
+ (\.(?!\d)[\w*]+|\[-?[0-9]+\])* # .etc.etc or [0], we only support literal integers.
461
+ )
462
+ (\?\??)$ # ? or ??
463
+ """,
464
+ re.VERBOSE,
465
+ )
466
+
467
+
468
+ class HelpEnd(TokenTransformBase):
469
+ """Transformer for help syntax: obj? and obj??"""
470
+ # This needs to be higher priority (lower number) than EscapedCommand so
471
+ # that inspecting magics (%foo?) works.
472
+ priority = 5
473
+
474
+ def __init__(self, start, q_locn):
475
+ super().__init__(start)
476
+ self.q_line = q_locn[0] - 1 # Shift from 1-indexed to 0-indexed
477
+ self.q_col = q_locn[1]
478
+
479
+ @classmethod
480
+ def find(cls, tokens_by_line):
481
+ """Find the first help command (foo?) in the cell.
482
+ """
483
+ for line in tokens_by_line:
484
+ # Last token is NEWLINE; look at last but one
485
+ if len(line) > 2 and line[-2].string == '?':
486
+ # Find the first token that's not INDENT/DEDENT
487
+ ix = 0
488
+ while line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
489
+ ix += 1
490
+ return cls(line[ix].start, line[-2].start)
491
+
492
+ def transform(self, lines):
493
+ """Transform a help command found by the ``find()`` classmethod.
494
+ """
495
+
496
+ piece = "".join(lines[self.start_line : self.q_line + 1])
497
+ indent, content = piece[: self.start_col], piece[self.start_col :]
498
+ lines_before = lines[: self.start_line]
499
+ lines_after = lines[self.q_line + 1 :]
500
+
501
+ m = _help_end_re.search(content)
502
+ if not m:
503
+ raise SyntaxError(content)
504
+ assert m is not None, content
505
+ target = m.group(1)
506
+ esc = m.group(3)
507
+
508
+
509
+ call = _make_help_call(target, esc)
510
+ new_line = indent + call + '\n'
511
+
512
+ return lines_before + [new_line] + lines_after
513
+
514
+ def make_tokens_by_line(lines:List[str]):
515
+ """Tokenize a series of lines and group tokens by line.
516
+
517
+ The tokens for a multiline Python string or expression are grouped as one
518
+ line. All lines except the last lines should keep their line ending ('\\n',
519
+ '\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)`
520
+ for example when passing block of text to this function.
521
+
522
+ """
523
+ # NL tokens are used inside multiline expressions, but also after blank
524
+ # lines or comments. This is intentional - see https://bugs.python.org/issue17061
525
+ # We want to group the former case together but split the latter, so we
526
+ # track parentheses level, similar to the internals of tokenize.
527
+
528
+ # reexported from token on 3.7+
529
+ NEWLINE, NL = tokenize.NEWLINE, tokenize.NL # type: ignore
530
+ tokens_by_line: List[List[Any]] = [[]]
531
+ if len(lines) > 1 and not lines[0].endswith(("\n", "\r", "\r\n", "\x0b", "\x0c")):
532
+ warnings.warn(
533
+ "`make_tokens_by_line` received a list of lines which do not have lineending markers ('\\n', '\\r', '\\r\\n', '\\x0b', '\\x0c'), behavior will be unspecified",
534
+ stacklevel=2,
535
+ )
536
+ parenlev = 0
537
+ try:
538
+ for token in tokenutil.generate_tokens_catch_errors(
539
+ iter(lines).__next__, extra_errors_to_catch=["expected EOF"]
540
+ ):
541
+ tokens_by_line[-1].append(token)
542
+ if (token.type == NEWLINE) \
543
+ or ((token.type == NL) and (parenlev <= 0)):
544
+ tokens_by_line.append([])
545
+ elif token.string in {'(', '[', '{'}:
546
+ parenlev += 1
547
+ elif token.string in {')', ']', '}'}:
548
+ if parenlev > 0:
549
+ parenlev -= 1
550
+ except tokenize.TokenError:
551
+ # Input ended in a multiline string or expression. That's OK for us.
552
+ pass
553
+
554
+
555
+ if not tokens_by_line[-1]:
556
+ tokens_by_line.pop()
557
+
558
+
559
+ return tokens_by_line
560
+
561
+
562
+ def has_sunken_brackets(tokens: List[tokenize.TokenInfo]):
563
+ """Check if the depth of brackets in the list of tokens drops below 0"""
564
+ parenlev = 0
565
+ for token in tokens:
566
+ if token.string in {"(", "[", "{"}:
567
+ parenlev += 1
568
+ elif token.string in {")", "]", "}"}:
569
+ parenlev -= 1
570
+ if parenlev < 0:
571
+ return True
572
+ return False
573
+
574
+
575
+ def show_linewise_tokens(s: str):
576
+ """For investigation and debugging"""
577
+ warnings.warn(
578
+ "show_linewise_tokens is deprecated since IPython 8.6",
579
+ DeprecationWarning,
580
+ stacklevel=2,
581
+ )
582
+ if not s.endswith("\n"):
583
+ s += "\n"
584
+ lines = s.splitlines(keepends=True)
585
+ for line in make_tokens_by_line(lines):
586
+ print("Line -------")
587
+ for tokinfo in line:
588
+ print(" ", tokinfo)
589
+
590
+ # Arbitrary limit to prevent getting stuck in infinite loops
591
+ TRANSFORM_LOOP_LIMIT = 500
592
+
593
+ class TransformerManager:
594
+ """Applies various transformations to a cell or code block.
595
+
596
+ The key methods for external use are ``transform_cell()``
597
+ and ``check_complete()``.
598
+ """
599
+ def __init__(self):
600
+ self.cleanup_transforms = [
601
+ leading_empty_lines,
602
+ leading_indent,
603
+ classic_prompt,
604
+ ipython_prompt,
605
+ ]
606
+ self.line_transforms = [
607
+ cell_magic,
608
+ ]
609
+ self.token_transformers = [
610
+ MagicAssign,
611
+ SystemAssign,
612
+ EscapedCommand,
613
+ HelpEnd,
614
+ ]
615
+
616
+ def do_one_token_transform(self, lines):
617
+ """Find and run the transform earliest in the code.
618
+
619
+ Returns (changed, lines).
620
+
621
+ This method is called repeatedly until changed is False, indicating
622
+ that all available transformations are complete.
623
+
624
+ The tokens following IPython special syntax might not be valid, so
625
+ the transformed code is retokenised every time to identify the next
626
+ piece of special syntax. Hopefully long code cells are mostly valid
627
+ Python, not using lots of IPython special syntax, so this shouldn't be
628
+ a performance issue.
629
+ """
630
+ tokens_by_line = make_tokens_by_line(lines)
631
+ candidates = []
632
+ for transformer_cls in self.token_transformers:
633
+ transformer = transformer_cls.find(tokens_by_line)
634
+ if transformer:
635
+ candidates.append(transformer)
636
+
637
+ if not candidates:
638
+ # Nothing to transform
639
+ return False, lines
640
+ ordered_transformers = sorted(candidates, key=TokenTransformBase.sortby)
641
+ for transformer in ordered_transformers:
642
+ try:
643
+ return True, transformer.transform(lines)
644
+ except SyntaxError:
645
+ pass
646
+ return False, lines
647
+
648
+ def do_token_transforms(self, lines):
649
+ for _ in range(TRANSFORM_LOOP_LIMIT):
650
+ changed, lines = self.do_one_token_transform(lines)
651
+ if not changed:
652
+ return lines
653
+
654
+ raise RuntimeError("Input transformation still changing after "
655
+ "%d iterations. Aborting." % TRANSFORM_LOOP_LIMIT)
656
+
657
+ def transform_cell(self, cell: str) -> str:
658
+ """Transforms a cell of input code"""
659
+ if not cell.endswith('\n'):
660
+ cell += '\n' # Ensure the cell has a trailing newline
661
+ lines = cell.splitlines(keepends=True)
662
+ for transform in self.cleanup_transforms + self.line_transforms:
663
+ lines = transform(lines)
664
+
665
+ lines = self.do_token_transforms(lines)
666
+ return ''.join(lines)
667
+
668
+ def check_complete(self, cell: str):
669
+ """Return whether a block of code is ready to execute, or should be continued
670
+
671
+ Parameters
672
+ ----------
673
+ cell : string
674
+ Python input code, which can be multiline.
675
+
676
+ Returns
677
+ -------
678
+ status : str
679
+ One of 'complete', 'incomplete', or 'invalid' if source is not a
680
+ prefix of valid code.
681
+ indent_spaces : int or None
682
+ The number of spaces by which to indent the next line of code. If
683
+ status is not 'incomplete', this is None.
684
+ """
685
+ # Remember if the lines ends in a new line.
686
+ ends_with_newline = False
687
+ for character in reversed(cell):
688
+ if character == '\n':
689
+ ends_with_newline = True
690
+ break
691
+ elif character.strip():
692
+ break
693
+ else:
694
+ continue
695
+
696
+ if not ends_with_newline:
697
+ # Append an newline for consistent tokenization
698
+ # See https://bugs.python.org/issue33899
699
+ cell += '\n'
700
+
701
+ lines = cell.splitlines(keepends=True)
702
+
703
+ if not lines:
704
+ return 'complete', None
705
+
706
+ for line in reversed(lines):
707
+ if not line.strip():
708
+ continue
709
+ elif line.strip("\n").endswith("\\"):
710
+ return "incomplete", find_last_indent(lines)
711
+ else:
712
+ break
713
+
714
+ try:
715
+ for transform in self.cleanup_transforms:
716
+ if not getattr(transform, 'has_side_effects', False):
717
+ lines = transform(lines)
718
+ except SyntaxError:
719
+ return 'invalid', None
720
+
721
+ if lines[0].startswith('%%'):
722
+ # Special case for cell magics - completion marked by blank line
723
+ if lines[-1].strip():
724
+ return 'incomplete', find_last_indent(lines)
725
+ else:
726
+ return 'complete', None
727
+
728
+ try:
729
+ for transform in self.line_transforms:
730
+ if not getattr(transform, 'has_side_effects', False):
731
+ lines = transform(lines)
732
+ lines = self.do_token_transforms(lines)
733
+ except SyntaxError:
734
+ return 'invalid', None
735
+
736
+ tokens_by_line = make_tokens_by_line(lines)
737
+
738
+ # Bail if we got one line and there are more closing parentheses than
739
+ # the opening ones
740
+ if (
741
+ len(lines) == 1
742
+ and tokens_by_line
743
+ and has_sunken_brackets(tokens_by_line[0])
744
+ ):
745
+ return "invalid", None
746
+
747
+ if not tokens_by_line:
748
+ return 'incomplete', find_last_indent(lines)
749
+
750
+ if (
751
+ tokens_by_line[-1][-1].type != tokenize.ENDMARKER
752
+ and tokens_by_line[-1][-1].type != tokenize.ERRORTOKEN
753
+ ):
754
+ # We're in a multiline string or expression
755
+ return 'incomplete', find_last_indent(lines)
756
+
757
+ newline_types = {tokenize.NEWLINE, tokenize.COMMENT, tokenize.ENDMARKER} # type: ignore
758
+
759
+ # Pop the last line which only contains DEDENTs and ENDMARKER
760
+ last_token_line = None
761
+ if {t.type for t in tokens_by_line[-1]} in [
762
+ {tokenize.DEDENT, tokenize.ENDMARKER},
763
+ {tokenize.ENDMARKER}
764
+ ] and len(tokens_by_line) > 1:
765
+ last_token_line = tokens_by_line.pop()
766
+
767
+ while tokens_by_line[-1] and tokens_by_line[-1][-1].type in newline_types:
768
+ tokens_by_line[-1].pop()
769
+
770
+ if not tokens_by_line[-1]:
771
+ return 'incomplete', find_last_indent(lines)
772
+
773
+ if tokens_by_line[-1][-1].string == ':':
774
+ # The last line starts a block (e.g. 'if foo:')
775
+ ix = 0
776
+ while tokens_by_line[-1][ix].type in {tokenize.INDENT, tokenize.DEDENT}:
777
+ ix += 1
778
+
779
+ indent = tokens_by_line[-1][ix].start[1]
780
+ return 'incomplete', indent + 4
781
+
782
+ if tokens_by_line[-1][0].line.endswith('\\'):
783
+ return 'incomplete', None
784
+
785
+ # At this point, our checks think the code is complete (or invalid).
786
+ # We'll use codeop.compile_command to check this with the real parser
787
+ try:
788
+ with warnings.catch_warnings():
789
+ warnings.simplefilter('error', SyntaxWarning)
790
+ res = compile_command(''.join(lines), symbol='exec')
791
+ except (SyntaxError, OverflowError, ValueError, TypeError,
792
+ MemoryError, SyntaxWarning):
793
+ return 'invalid', None
794
+ else:
795
+ if res is None:
796
+ return 'incomplete', find_last_indent(lines)
797
+
798
+ if last_token_line and last_token_line[0].type == tokenize.DEDENT:
799
+ if ends_with_newline:
800
+ return 'complete', None
801
+ return 'incomplete', find_last_indent(lines)
802
+
803
+ # If there's a blank line at the end, assume we're ready to execute
804
+ if not lines[-1].strip():
805
+ return 'complete', None
806
+
807
+ return 'complete', None
808
+
809
+
810
+ def find_last_indent(lines):
811
+ m = _indent_re.match(lines[-1])
812
+ if not m:
813
+ return 0
814
+ return len(m.group(0).replace('\t', ' '*4))
815
+
816
+
817
+ class MaybeAsyncCompile(Compile):
818
+ def __init__(self, extra_flags=0):
819
+ super().__init__()
820
+ self.flags |= extra_flags
821
+
822
+
823
+ class MaybeAsyncCommandCompiler(CommandCompiler):
824
+ def __init__(self, extra_flags=0):
825
+ self.compiler = MaybeAsyncCompile(extra_flags=extra_flags)
826
+
827
+
828
+ _extra_flags = ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
829
+
830
+ compile_command = MaybeAsyncCommandCompiler(extra_flags=_extra_flags)
openalex_env_map/lib/python3.10/site-packages/IPython/core/interactiveshell.py ADDED
The diff for this file is too large to render. See raw diff
 
openalex_env_map/lib/python3.10/site-packages/IPython/core/latex_symbols.py ADDED
@@ -0,0 +1,1301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+
3
+ # DO NOT EDIT THIS FILE BY HAND.
4
+
5
+ # To update this file, run the script /tools/gen_latex_symbols.py using Python 3
6
+
7
+ # This file is autogenerated from the file:
8
+ # https://raw.githubusercontent.com/JuliaLang/julia/master/base/latex_symbols.jl
9
+ # This original list is filtered to remove any unicode characters that are not valid
10
+ # Python identifiers.
11
+
12
+ latex_symbols = {
13
+
14
+ "\\euler" : "ℯ",
15
+ "\\^a" : "ᵃ",
16
+ "\\^b" : "ᵇ",
17
+ "\\^c" : "ᶜ",
18
+ "\\^d" : "ᵈ",
19
+ "\\^e" : "ᵉ",
20
+ "\\^f" : "ᶠ",
21
+ "\\^g" : "ᵍ",
22
+ "\\^h" : "ʰ",
23
+ "\\^i" : "ⁱ",
24
+ "\\^j" : "ʲ",
25
+ "\\^k" : "ᵏ",
26
+ "\\^l" : "ˡ",
27
+ "\\^m" : "ᵐ",
28
+ "\\^n" : "ⁿ",
29
+ "\\^o" : "ᵒ",
30
+ "\\^p" : "ᵖ",
31
+ "\\^r" : "ʳ",
32
+ "\\^s" : "ˢ",
33
+ "\\^t" : "ᵗ",
34
+ "\\^u" : "ᵘ",
35
+ "\\^v" : "ᵛ",
36
+ "\\^w" : "ʷ",
37
+ "\\^x" : "ˣ",
38
+ "\\^y" : "ʸ",
39
+ "\\^z" : "ᶻ",
40
+ "\\^A" : "ᴬ",
41
+ "\\^B" : "ᴮ",
42
+ "\\^D" : "ᴰ",
43
+ "\\^E" : "ᴱ",
44
+ "\\^G" : "ᴳ",
45
+ "\\^H" : "ᴴ",
46
+ "\\^I" : "ᴵ",
47
+ "\\^J" : "ᴶ",
48
+ "\\^K" : "ᴷ",
49
+ "\\^L" : "ᴸ",
50
+ "\\^M" : "ᴹ",
51
+ "\\^N" : "ᴺ",
52
+ "\\^O" : "ᴼ",
53
+ "\\^P" : "ᴾ",
54
+ "\\^R" : "ᴿ",
55
+ "\\^T" : "ᵀ",
56
+ "\\^U" : "ᵁ",
57
+ "\\^V" : "ⱽ",
58
+ "\\^W" : "ᵂ",
59
+ "\\^alpha" : "ᵅ",
60
+ "\\^beta" : "ᵝ",
61
+ "\\^gamma" : "ᵞ",
62
+ "\\^delta" : "ᵟ",
63
+ "\\^epsilon" : "ᵋ",
64
+ "\\^theta" : "ᶿ",
65
+ "\\^iota" : "ᶥ",
66
+ "\\^phi" : "ᵠ",
67
+ "\\^chi" : "ᵡ",
68
+ "\\^Phi" : "ᶲ",
69
+ "\\_a" : "ₐ",
70
+ "\\_e" : "ₑ",
71
+ "\\_h" : "ₕ",
72
+ "\\_i" : "ᵢ",
73
+ "\\_j" : "ⱼ",
74
+ "\\_k" : "ₖ",
75
+ "\\_l" : "ₗ",
76
+ "\\_m" : "ₘ",
77
+ "\\_n" : "ₙ",
78
+ "\\_o" : "ₒ",
79
+ "\\_p" : "ₚ",
80
+ "\\_r" : "ᵣ",
81
+ "\\_s" : "ₛ",
82
+ "\\_t" : "ₜ",
83
+ "\\_u" : "ᵤ",
84
+ "\\_v" : "ᵥ",
85
+ "\\_x" : "ₓ",
86
+ "\\_schwa" : "ₔ",
87
+ "\\_beta" : "ᵦ",
88
+ "\\_gamma" : "ᵧ",
89
+ "\\_rho" : "ᵨ",
90
+ "\\_phi" : "ᵩ",
91
+ "\\_chi" : "ᵪ",
92
+ "\\hbar" : "ħ",
93
+ "\\sout" : "̶",
94
+ "\\ordfeminine" : "ª",
95
+ "\\cdotp" : "·",
96
+ "\\ordmasculine" : "º",
97
+ "\\AA" : "Å",
98
+ "\\AE" : "Æ",
99
+ "\\DH" : "Ð",
100
+ "\\O" : "Ø",
101
+ "\\TH" : "Þ",
102
+ "\\ss" : "ß",
103
+ "\\aa" : "å",
104
+ "\\ae" : "æ",
105
+ "\\eth" : "ð",
106
+ "\\dh" : "ð",
107
+ "\\o" : "ø",
108
+ "\\th" : "þ",
109
+ "\\DJ" : "Đ",
110
+ "\\dj" : "đ",
111
+ "\\imath" : "ı",
112
+ "\\jmath" : "ȷ",
113
+ "\\L" : "Ł",
114
+ "\\l" : "ł",
115
+ "\\NG" : "Ŋ",
116
+ "\\ng" : "ŋ",
117
+ "\\OE" : "Œ",
118
+ "\\oe" : "œ",
119
+ "\\hvlig" : "ƕ",
120
+ "\\nrleg" : "ƞ",
121
+ "\\doublepipe" : "ǂ",
122
+ "\\trna" : "ɐ",
123
+ "\\trnsa" : "ɒ",
124
+ "\\openo" : "ɔ",
125
+ "\\rtld" : "ɖ",
126
+ "\\schwa" : "ə",
127
+ "\\varepsilon" : "ε",
128
+ "\\pgamma" : "ɣ",
129
+ "\\pbgam" : "ɤ",
130
+ "\\trnh" : "ɥ",
131
+ "\\btdl" : "ɬ",
132
+ "\\rtll" : "ɭ",
133
+ "\\trnm" : "ɯ",
134
+ "\\trnmlr" : "ɰ",
135
+ "\\ltlmr" : "ɱ",
136
+ "\\ltln" : "ɲ",
137
+ "\\rtln" : "ɳ",
138
+ "\\clomeg" : "ɷ",
139
+ "\\ltphi" : "ɸ",
140
+ "\\trnr" : "ɹ",
141
+ "\\trnrl" : "ɺ",
142
+ "\\rttrnr" : "ɻ",
143
+ "\\rl" : "ɼ",
144
+ "\\rtlr" : "ɽ",
145
+ "\\fhr" : "ɾ",
146
+ "\\rtls" : "ʂ",
147
+ "\\esh" : "ʃ",
148
+ "\\trnt" : "ʇ",
149
+ "\\rtlt" : "ʈ",
150
+ "\\pupsil" : "ʊ",
151
+ "\\pscrv" : "ʋ",
152
+ "\\invv" : "ʌ",
153
+ "\\invw" : "ʍ",
154
+ "\\trny" : "ʎ",
155
+ "\\rtlz" : "ʐ",
156
+ "\\yogh" : "ʒ",
157
+ "\\glst" : "ʔ",
158
+ "\\reglst" : "ʕ",
159
+ "\\inglst" : "ʖ",
160
+ "\\turnk" : "ʞ",
161
+ "\\dyogh" : "ʤ",
162
+ "\\tesh" : "ʧ",
163
+ "\\rasp" : "ʼ",
164
+ "\\verts" : "ˈ",
165
+ "\\verti" : "ˌ",
166
+ "\\lmrk" : "ː",
167
+ "\\hlmrk" : "ˑ",
168
+ "\\grave" : "̀",
169
+ "\\acute" : "́",
170
+ "\\hat" : "̂",
171
+ "\\tilde" : "̃",
172
+ "\\bar" : "̄",
173
+ "\\breve" : "̆",
174
+ "\\dot" : "̇",
175
+ "\\ddot" : "̈",
176
+ "\\ocirc" : "̊",
177
+ "\\H" : "̋",
178
+ "\\check" : "̌",
179
+ "\\palh" : "̡",
180
+ "\\rh" : "̢",
181
+ "\\c" : "̧",
182
+ "\\k" : "̨",
183
+ "\\sbbrg" : "̪",
184
+ "\\strike" : "̶",
185
+ "\\Alpha" : "Α",
186
+ "\\Beta" : "Β",
187
+ "\\Gamma" : "Γ",
188
+ "\\Delta" : "Δ",
189
+ "\\Epsilon" : "Ε",
190
+ "\\Zeta" : "Ζ",
191
+ "\\Eta" : "Η",
192
+ "\\Theta" : "Θ",
193
+ "\\Iota" : "Ι",
194
+ "\\Kappa" : "Κ",
195
+ "\\Lambda" : "Λ",
196
+ "\\Xi" : "Ξ",
197
+ "\\Pi" : "Π",
198
+ "\\Rho" : "Ρ",
199
+ "\\Sigma" : "Σ",
200
+ "\\Tau" : "Τ",
201
+ "\\Upsilon" : "Υ",
202
+ "\\Phi" : "Φ",
203
+ "\\Chi" : "Χ",
204
+ "\\Psi" : "Ψ",
205
+ "\\Omega" : "Ω",
206
+ "\\alpha" : "α",
207
+ "\\beta" : "β",
208
+ "\\gamma" : "γ",
209
+ "\\delta" : "δ",
210
+ "\\zeta" : "ζ",
211
+ "\\eta" : "η",
212
+ "\\theta" : "θ",
213
+ "\\iota" : "ι",
214
+ "\\kappa" : "κ",
215
+ "\\lambda" : "λ",
216
+ "\\mu" : "μ",
217
+ "\\nu" : "ν",
218
+ "\\xi" : "ξ",
219
+ "\\pi" : "π",
220
+ "\\rho" : "ρ",
221
+ "\\varsigma" : "ς",
222
+ "\\sigma" : "σ",
223
+ "\\tau" : "τ",
224
+ "\\upsilon" : "υ",
225
+ "\\varphi" : "φ",
226
+ "\\chi" : "χ",
227
+ "\\psi" : "ψ",
228
+ "\\omega" : "ω",
229
+ "\\vartheta" : "ϑ",
230
+ "\\phi" : "ϕ",
231
+ "\\varpi" : "ϖ",
232
+ "\\Stigma" : "Ϛ",
233
+ "\\Digamma" : "Ϝ",
234
+ "\\digamma" : "ϝ",
235
+ "\\Koppa" : "Ϟ",
236
+ "\\Sampi" : "Ϡ",
237
+ "\\varkappa" : "ϰ",
238
+ "\\varrho" : "ϱ",
239
+ "\\varTheta" : "ϴ",
240
+ "\\epsilon" : "ϵ",
241
+ "\\dddot" : "⃛",
242
+ "\\ddddot" : "⃜",
243
+ "\\hslash" : "ℏ",
244
+ "\\Im" : "ℑ",
245
+ "\\ell" : "ℓ",
246
+ "\\wp" : "℘",
247
+ "\\Re" : "ℜ",
248
+ "\\aleph" : "ℵ",
249
+ "\\beth" : "ℶ",
250
+ "\\gimel" : "ℷ",
251
+ "\\daleth" : "ℸ",
252
+ "\\bbPi" : "ℿ",
253
+ "\\Zbar" : "Ƶ",
254
+ "\\overbar" : "̅",
255
+ "\\ovhook" : "̉",
256
+ "\\candra" : "̐",
257
+ "\\oturnedcomma" : "̒",
258
+ "\\ocommatopright" : "̕",
259
+ "\\droang" : "̚",
260
+ "\\wideutilde" : "̰",
261
+ "\\not" : "̸",
262
+ "\\upMu" : "Μ",
263
+ "\\upNu" : "Ν",
264
+ "\\upOmicron" : "Ο",
265
+ "\\upepsilon" : "ε",
266
+ "\\upomicron" : "ο",
267
+ "\\upvarbeta" : "ϐ",
268
+ "\\upoldKoppa" : "Ϙ",
269
+ "\\upoldkoppa" : "ϙ",
270
+ "\\upstigma" : "ϛ",
271
+ "\\upkoppa" : "ϟ",
272
+ "\\upsampi" : "ϡ",
273
+ "\\tieconcat" : "⁀",
274
+ "\\leftharpoonaccent" : "⃐",
275
+ "\\rightharpoonaccent" : "⃑",
276
+ "\\vertoverlay" : "⃒",
277
+ "\\overleftarrow" : "⃖",
278
+ "\\vec" : "⃗",
279
+ "\\overleftrightarrow" : "⃡",
280
+ "\\annuity" : "⃧",
281
+ "\\threeunderdot" : "⃨",
282
+ "\\widebridgeabove" : "⃩",
283
+ "\\bbC" : "ℂ",
284
+ "\\eulermascheroni" : "ℇ",
285
+ "\\scrg" : "ℊ",
286
+ "\\scrH" : "ℋ",
287
+ "\\frakH" : "ℌ",
288
+ "\\bbH" : "ℍ",
289
+ "\\planck" : "ℎ",
290
+ "\\scrI" : "ℐ",
291
+ "\\scrL" : "ℒ",
292
+ "\\bbN" : "ℕ",
293
+ "\\bbP" : "ℙ",
294
+ "\\bbQ" : "ℚ",
295
+ "\\scrR" : "ℛ",
296
+ "\\bbR" : "ℝ",
297
+ "\\bbZ" : "ℤ",
298
+ "\\frakZ" : "ℨ",
299
+ "\\Angstrom" : "Å",
300
+ "\\scrB" : "ℬ",
301
+ "\\frakC" : "ℭ",
302
+ "\\scre" : "ℯ",
303
+ "\\scrE" : "ℰ",
304
+ "\\scrF" : "ℱ",
305
+ "\\Finv" : "Ⅎ",
306
+ "\\scrM" : "ℳ",
307
+ "\\scro" : "ℴ",
308
+ "\\bbgamma" : "ℽ",
309
+ "\\bbGamma" : "ℾ",
310
+ "\\bbiD" : "ⅅ",
311
+ "\\bbid" : "ⅆ",
312
+ "\\bbie" : "ⅇ",
313
+ "\\bbii" : "ⅈ",
314
+ "\\bbij" : "ⅉ",
315
+ "\\bfA" : "𝐀",
316
+ "\\bfB" : "𝐁",
317
+ "\\bfC" : "𝐂",
318
+ "\\bfD" : "𝐃",
319
+ "\\bfE" : "𝐄",
320
+ "\\bfF" : "𝐅",
321
+ "\\bfG" : "𝐆",
322
+ "\\bfH" : "𝐇",
323
+ "\\bfI" : "𝐈",
324
+ "\\bfJ" : "𝐉",
325
+ "\\bfK" : "𝐊",
326
+ "\\bfL" : "𝐋",
327
+ "\\bfM" : "𝐌",
328
+ "\\bfN" : "𝐍",
329
+ "\\bfO" : "𝐎",
330
+ "\\bfP" : "𝐏",
331
+ "\\bfQ" : "𝐐",
332
+ "\\bfR" : "𝐑",
333
+ "\\bfS" : "𝐒",
334
+ "\\bfT" : "𝐓",
335
+ "\\bfU" : "𝐔",
336
+ "\\bfV" : "𝐕",
337
+ "\\bfW" : "𝐖",
338
+ "\\bfX" : "𝐗",
339
+ "\\bfY" : "𝐘",
340
+ "\\bfZ" : "𝐙",
341
+ "\\bfa" : "𝐚",
342
+ "\\bfb" : "𝐛",
343
+ "\\bfc" : "𝐜",
344
+ "\\bfd" : "𝐝",
345
+ "\\bfe" : "𝐞",
346
+ "\\bff" : "𝐟",
347
+ "\\bfg" : "𝐠",
348
+ "\\bfh" : "𝐡",
349
+ "\\bfi" : "𝐢",
350
+ "\\bfj" : "𝐣",
351
+ "\\bfk" : "𝐤",
352
+ "\\bfl" : "𝐥",
353
+ "\\bfm" : "𝐦",
354
+ "\\bfn" : "𝐧",
355
+ "\\bfo" : "𝐨",
356
+ "\\bfp" : "𝐩",
357
+ "\\bfq" : "𝐪",
358
+ "\\bfr" : "𝐫",
359
+ "\\bfs" : "𝐬",
360
+ "\\bft" : "𝐭",
361
+ "\\bfu" : "𝐮",
362
+ "\\bfv" : "𝐯",
363
+ "\\bfw" : "𝐰",
364
+ "\\bfx" : "𝐱",
365
+ "\\bfy" : "𝐲",
366
+ "\\bfz" : "𝐳",
367
+ "\\itA" : "𝐴",
368
+ "\\itB" : "𝐵",
369
+ "\\itC" : "𝐶",
370
+ "\\itD" : "𝐷",
371
+ "\\itE" : "𝐸",
372
+ "\\itF" : "𝐹",
373
+ "\\itG" : "𝐺",
374
+ "\\itH" : "𝐻",
375
+ "\\itI" : "𝐼",
376
+ "\\itJ" : "𝐽",
377
+ "\\itK" : "𝐾",
378
+ "\\itL" : "𝐿",
379
+ "\\itM" : "𝑀",
380
+ "\\itN" : "𝑁",
381
+ "\\itO" : "𝑂",
382
+ "\\itP" : "𝑃",
383
+ "\\itQ" : "𝑄",
384
+ "\\itR" : "𝑅",
385
+ "\\itS" : "𝑆",
386
+ "\\itT" : "𝑇",
387
+ "\\itU" : "𝑈",
388
+ "\\itV" : "𝑉",
389
+ "\\itW" : "𝑊",
390
+ "\\itX" : "𝑋",
391
+ "\\itY" : "𝑌",
392
+ "\\itZ" : "𝑍",
393
+ "\\ita" : "𝑎",
394
+ "\\itb" : "𝑏",
395
+ "\\itc" : "𝑐",
396
+ "\\itd" : "𝑑",
397
+ "\\ite" : "𝑒",
398
+ "\\itf" : "𝑓",
399
+ "\\itg" : "𝑔",
400
+ "\\iti" : "𝑖",
401
+ "\\itj" : "𝑗",
402
+ "\\itk" : "𝑘",
403
+ "\\itl" : "𝑙",
404
+ "\\itm" : "𝑚",
405
+ "\\itn" : "𝑛",
406
+ "\\ito" : "𝑜",
407
+ "\\itp" : "𝑝",
408
+ "\\itq" : "𝑞",
409
+ "\\itr" : "𝑟",
410
+ "\\its" : "𝑠",
411
+ "\\itt" : "𝑡",
412
+ "\\itu" : "𝑢",
413
+ "\\itv" : "𝑣",
414
+ "\\itw" : "𝑤",
415
+ "\\itx" : "𝑥",
416
+ "\\ity" : "𝑦",
417
+ "\\itz" : "𝑧",
418
+ "\\biA" : "𝑨",
419
+ "\\biB" : "𝑩",
420
+ "\\biC" : "𝑪",
421
+ "\\biD" : "𝑫",
422
+ "\\biE" : "𝑬",
423
+ "\\biF" : "𝑭",
424
+ "\\biG" : "𝑮",
425
+ "\\biH" : "𝑯",
426
+ "\\biI" : "𝑰",
427
+ "\\biJ" : "𝑱",
428
+ "\\biK" : "𝑲",
429
+ "\\biL" : "𝑳",
430
+ "\\biM" : "𝑴",
431
+ "\\biN" : "𝑵",
432
+ "\\biO" : "𝑶",
433
+ "\\biP" : "𝑷",
434
+ "\\biQ" : "𝑸",
435
+ "\\biR" : "𝑹",
436
+ "\\biS" : "𝑺",
437
+ "\\biT" : "𝑻",
438
+ "\\biU" : "𝑼",
439
+ "\\biV" : "𝑽",
440
+ "\\biW" : "𝑾",
441
+ "\\biX" : "𝑿",
442
+ "\\biY" : "𝒀",
443
+ "\\biZ" : "𝒁",
444
+ "\\bia" : "𝒂",
445
+ "\\bib" : "𝒃",
446
+ "\\bic" : "𝒄",
447
+ "\\bid" : "𝒅",
448
+ "\\bie" : "𝒆",
449
+ "\\bif" : "𝒇",
450
+ "\\big" : "𝒈",
451
+ "\\bih" : "𝒉",
452
+ "\\bii" : "𝒊",
453
+ "\\bij" : "𝒋",
454
+ "\\bik" : "𝒌",
455
+ "\\bil" : "𝒍",
456
+ "\\bim" : "𝒎",
457
+ "\\bin" : "𝒏",
458
+ "\\bio" : "𝒐",
459
+ "\\bip" : "𝒑",
460
+ "\\biq" : "𝒒",
461
+ "\\bir" : "𝒓",
462
+ "\\bis" : "𝒔",
463
+ "\\bit" : "𝒕",
464
+ "\\biu" : "𝒖",
465
+ "\\biv" : "𝒗",
466
+ "\\biw" : "𝒘",
467
+ "\\bix" : "𝒙",
468
+ "\\biy" : "𝒚",
469
+ "\\biz" : "𝒛",
470
+ "\\scrA" : "𝒜",
471
+ "\\scrC" : "𝒞",
472
+ "\\scrD" : "𝒟",
473
+ "\\scrG" : "𝒢",
474
+ "\\scrJ" : "𝒥",
475
+ "\\scrK" : "𝒦",
476
+ "\\scrN" : "𝒩",
477
+ "\\scrO" : "𝒪",
478
+ "\\scrP" : "𝒫",
479
+ "\\scrQ" : "𝒬",
480
+ "\\scrS" : "𝒮",
481
+ "\\scrT" : "𝒯",
482
+ "\\scrU" : "𝒰",
483
+ "\\scrV" : "𝒱",
484
+ "\\scrW" : "𝒲",
485
+ "\\scrX" : "𝒳",
486
+ "\\scrY" : "𝒴",
487
+ "\\scrZ" : "𝒵",
488
+ "\\scra" : "𝒶",
489
+ "\\scrb" : "𝒷",
490
+ "\\scrc" : "𝒸",
491
+ "\\scrd" : "𝒹",
492
+ "\\scrf" : "𝒻",
493
+ "\\scrh" : "𝒽",
494
+ "\\scri" : "𝒾",
495
+ "\\scrj" : "𝒿",
496
+ "\\scrk" : "𝓀",
497
+ "\\scrm" : "𝓂",
498
+ "\\scrn" : "𝓃",
499
+ "\\scrp" : "𝓅",
500
+ "\\scrq" : "𝓆",
501
+ "\\scrr" : "𝓇",
502
+ "\\scrs" : "𝓈",
503
+ "\\scrt" : "𝓉",
504
+ "\\scru" : "𝓊",
505
+ "\\scrv" : "𝓋",
506
+ "\\scrw" : "𝓌",
507
+ "\\scrx" : "𝓍",
508
+ "\\scry" : "𝓎",
509
+ "\\scrz" : "𝓏",
510
+ "\\bscrA" : "𝓐",
511
+ "\\bscrB" : "𝓑",
512
+ "\\bscrC" : "𝓒",
513
+ "\\bscrD" : "𝓓",
514
+ "\\bscrE" : "𝓔",
515
+ "\\bscrF" : "𝓕",
516
+ "\\bscrG" : "𝓖",
517
+ "\\bscrH" : "𝓗",
518
+ "\\bscrI" : "𝓘",
519
+ "\\bscrJ" : "𝓙",
520
+ "\\bscrK" : "𝓚",
521
+ "\\bscrL" : "𝓛",
522
+ "\\bscrM" : "𝓜",
523
+ "\\bscrN" : "𝓝",
524
+ "\\bscrO" : "𝓞",
525
+ "\\bscrP" : "𝓟",
526
+ "\\bscrQ" : "𝓠",
527
+ "\\bscrR" : "𝓡",
528
+ "\\bscrS" : "𝓢",
529
+ "\\bscrT" : "𝓣",
530
+ "\\bscrU" : "𝓤",
531
+ "\\bscrV" : "𝓥",
532
+ "\\bscrW" : "𝓦",
533
+ "\\bscrX" : "𝓧",
534
+ "\\bscrY" : "𝓨",
535
+ "\\bscrZ" : "𝓩",
536
+ "\\bscra" : "𝓪",
537
+ "\\bscrb" : "𝓫",
538
+ "\\bscrc" : "𝓬",
539
+ "\\bscrd" : "𝓭",
540
+ "\\bscre" : "𝓮",
541
+ "\\bscrf" : "𝓯",
542
+ "\\bscrg" : "𝓰",
543
+ "\\bscrh" : "𝓱",
544
+ "\\bscri" : "𝓲",
545
+ "\\bscrj" : "𝓳",
546
+ "\\bscrk" : "𝓴",
547
+ "\\bscrl" : "𝓵",
548
+ "\\bscrm" : "𝓶",
549
+ "\\bscrn" : "𝓷",
550
+ "\\bscro" : "𝓸",
551
+ "\\bscrp" : "𝓹",
552
+ "\\bscrq" : "𝓺",
553
+ "\\bscrr" : "𝓻",
554
+ "\\bscrs" : "𝓼",
555
+ "\\bscrt" : "𝓽",
556
+ "\\bscru" : "𝓾",
557
+ "\\bscrv" : "𝓿",
558
+ "\\bscrw" : "𝔀",
559
+ "\\bscrx" : "𝔁",
560
+ "\\bscry" : "𝔂",
561
+ "\\bscrz" : "𝔃",
562
+ "\\frakA" : "𝔄",
563
+ "\\frakB" : "𝔅",
564
+ "\\frakD" : "𝔇",
565
+ "\\frakE" : "𝔈",
566
+ "\\frakF" : "𝔉",
567
+ "\\frakG" : "𝔊",
568
+ "\\frakJ" : "𝔍",
569
+ "\\frakK" : "𝔎",
570
+ "\\frakL" : "𝔏",
571
+ "\\frakM" : "𝔐",
572
+ "\\frakN" : "𝔑",
573
+ "\\frakO" : "𝔒",
574
+ "\\frakP" : "𝔓",
575
+ "\\frakQ" : "𝔔",
576
+ "\\frakS" : "𝔖",
577
+ "\\frakT" : "𝔗",
578
+ "\\frakU" : "𝔘",
579
+ "\\frakV" : "𝔙",
580
+ "\\frakW" : "𝔚",
581
+ "\\frakX" : "𝔛",
582
+ "\\frakY" : "𝔜",
583
+ "\\fraka" : "𝔞",
584
+ "\\frakb" : "𝔟",
585
+ "\\frakc" : "𝔠",
586
+ "\\frakd" : "𝔡",
587
+ "\\frake" : "𝔢",
588
+ "\\frakf" : "𝔣",
589
+ "\\frakg" : "𝔤",
590
+ "\\frakh" : "𝔥",
591
+ "\\fraki" : "𝔦",
592
+ "\\frakj" : "𝔧",
593
+ "\\frakk" : "𝔨",
594
+ "\\frakl" : "𝔩",
595
+ "\\frakm" : "𝔪",
596
+ "\\frakn" : "𝔫",
597
+ "\\frako" : "𝔬",
598
+ "\\frakp" : "𝔭",
599
+ "\\frakq" : "𝔮",
600
+ "\\frakr" : "𝔯",
601
+ "\\fraks" : "𝔰",
602
+ "\\frakt" : "𝔱",
603
+ "\\fraku" : "𝔲",
604
+ "\\frakv" : "𝔳",
605
+ "\\frakw" : "𝔴",
606
+ "\\frakx" : "𝔵",
607
+ "\\fraky" : "𝔶",
608
+ "\\frakz" : "𝔷",
609
+ "\\bbA" : "𝔸",
610
+ "\\bbB" : "𝔹",
611
+ "\\bbD" : "𝔻",
612
+ "\\bbE" : "𝔼",
613
+ "\\bbF" : "𝔽",
614
+ "\\bbG" : "𝔾",
615
+ "\\bbI" : "𝕀",
616
+ "\\bbJ" : "𝕁",
617
+ "\\bbK" : "𝕂",
618
+ "\\bbL" : "𝕃",
619
+ "\\bbM" : "𝕄",
620
+ "\\bbO" : "𝕆",
621
+ "\\bbS" : "𝕊",
622
+ "\\bbT" : "𝕋",
623
+ "\\bbU" : "𝕌",
624
+ "\\bbV" : "𝕍",
625
+ "\\bbW" : "𝕎",
626
+ "\\bbX" : "𝕏",
627
+ "\\bbY" : "𝕐",
628
+ "\\bba" : "𝕒",
629
+ "\\bbb" : "𝕓",
630
+ "\\bbc" : "𝕔",
631
+ "\\bbd" : "𝕕",
632
+ "\\bbe" : "𝕖",
633
+ "\\bbf" : "𝕗",
634
+ "\\bbg" : "𝕘",
635
+ "\\bbh" : "𝕙",
636
+ "\\bbi" : "𝕚",
637
+ "\\bbj" : "𝕛",
638
+ "\\bbk" : "𝕜",
639
+ "\\bbl" : "𝕝",
640
+ "\\bbm" : "𝕞",
641
+ "\\bbn" : "𝕟",
642
+ "\\bbo" : "𝕠",
643
+ "\\bbp" : "𝕡",
644
+ "\\bbq" : "𝕢",
645
+ "\\bbr" : "𝕣",
646
+ "\\bbs" : "𝕤",
647
+ "\\bbt" : "𝕥",
648
+ "\\bbu" : "𝕦",
649
+ "\\bbv" : "𝕧",
650
+ "\\bbw" : "𝕨",
651
+ "\\bbx" : "𝕩",
652
+ "\\bby" : "𝕪",
653
+ "\\bbz" : "𝕫",
654
+ "\\bfrakA" : "𝕬",
655
+ "\\bfrakB" : "𝕭",
656
+ "\\bfrakC" : "𝕮",
657
+ "\\bfrakD" : "𝕯",
658
+ "\\bfrakE" : "𝕰",
659
+ "\\bfrakF" : "𝕱",
660
+ "\\bfrakG" : "𝕲",
661
+ "\\bfrakH" : "𝕳",
662
+ "\\bfrakI" : "𝕴",
663
+ "\\bfrakJ" : "𝕵",
664
+ "\\bfrakK" : "𝕶",
665
+ "\\bfrakL" : "𝕷",
666
+ "\\bfrakM" : "𝕸",
667
+ "\\bfrakN" : "𝕹",
668
+ "\\bfrakO" : "𝕺",
669
+ "\\bfrakP" : "𝕻",
670
+ "\\bfrakQ" : "𝕼",
671
+ "\\bfrakR" : "𝕽",
672
+ "\\bfrakS" : "𝕾",
673
+ "\\bfrakT" : "𝕿",
674
+ "\\bfrakU" : "𝖀",
675
+ "\\bfrakV" : "𝖁",
676
+ "\\bfrakW" : "𝖂",
677
+ "\\bfrakX" : "𝖃",
678
+ "\\bfrakY" : "𝖄",
679
+ "\\bfrakZ" : "𝖅",
680
+ "\\bfraka" : "𝖆",
681
+ "\\bfrakb" : "𝖇",
682
+ "\\bfrakc" : "𝖈",
683
+ "\\bfrakd" : "𝖉",
684
+ "\\bfrake" : "𝖊",
685
+ "\\bfrakf" : "𝖋",
686
+ "\\bfrakg" : "𝖌",
687
+ "\\bfrakh" : "𝖍",
688
+ "\\bfraki" : "𝖎",
689
+ "\\bfrakj" : "𝖏",
690
+ "\\bfrakk" : "𝖐",
691
+ "\\bfrakl" : "𝖑",
692
+ "\\bfrakm" : "𝖒",
693
+ "\\bfrakn" : "𝖓",
694
+ "\\bfrako" : "𝖔",
695
+ "\\bfrakp" : "𝖕",
696
+ "\\bfrakq" : "𝖖",
697
+ "\\bfrakr" : "𝖗",
698
+ "\\bfraks" : "𝖘",
699
+ "\\bfrakt" : "𝖙",
700
+ "\\bfraku" : "𝖚",
701
+ "\\bfrakv" : "𝖛",
702
+ "\\bfrakw" : "𝖜",
703
+ "\\bfrakx" : "𝖝",
704
+ "\\bfraky" : "𝖞",
705
+ "\\bfrakz" : "𝖟",
706
+ "\\sansA" : "𝖠",
707
+ "\\sansB" : "𝖡",
708
+ "\\sansC" : "𝖢",
709
+ "\\sansD" : "𝖣",
710
+ "\\sansE" : "𝖤",
711
+ "\\sansF" : "𝖥",
712
+ "\\sansG" : "𝖦",
713
+ "\\sansH" : "𝖧",
714
+ "\\sansI" : "𝖨",
715
+ "\\sansJ" : "𝖩",
716
+ "\\sansK" : "𝖪",
717
+ "\\sansL" : "𝖫",
718
+ "\\sansM" : "𝖬",
719
+ "\\sansN" : "𝖭",
720
+ "\\sansO" : "𝖮",
721
+ "\\sansP" : "𝖯",
722
+ "\\sansQ" : "𝖰",
723
+ "\\sansR" : "𝖱",
724
+ "\\sansS" : "𝖲",
725
+ "\\sansT" : "𝖳",
726
+ "\\sansU" : "𝖴",
727
+ "\\sansV" : "𝖵",
728
+ "\\sansW" : "𝖶",
729
+ "\\sansX" : "𝖷",
730
+ "\\sansY" : "𝖸",
731
+ "\\sansZ" : "𝖹",
732
+ "\\sansa" : "𝖺",
733
+ "\\sansb" : "𝖻",
734
+ "\\sansc" : "𝖼",
735
+ "\\sansd" : "𝖽",
736
+ "\\sanse" : "𝖾",
737
+ "\\sansf" : "𝖿",
738
+ "\\sansg" : "𝗀",
739
+ "\\sansh" : "𝗁",
740
+ "\\sansi" : "𝗂",
741
+ "\\sansj" : "𝗃",
742
+ "\\sansk" : "𝗄",
743
+ "\\sansl" : "𝗅",
744
+ "\\sansm" : "𝗆",
745
+ "\\sansn" : "𝗇",
746
+ "\\sanso" : "𝗈",
747
+ "\\sansp" : "𝗉",
748
+ "\\sansq" : "𝗊",
749
+ "\\sansr" : "𝗋",
750
+ "\\sanss" : "𝗌",
751
+ "\\sanst" : "𝗍",
752
+ "\\sansu" : "𝗎",
753
+ "\\sansv" : "𝗏",
754
+ "\\sansw" : "𝗐",
755
+ "\\sansx" : "𝗑",
756
+ "\\sansy" : "𝗒",
757
+ "\\sansz" : "𝗓",
758
+ "\\bsansA" : "𝗔",
759
+ "\\bsansB" : "𝗕",
760
+ "\\bsansC" : "𝗖",
761
+ "\\bsansD" : "𝗗",
762
+ "\\bsansE" : "𝗘",
763
+ "\\bsansF" : "𝗙",
764
+ "\\bsansG" : "𝗚",
765
+ "\\bsansH" : "𝗛",
766
+ "\\bsansI" : "𝗜",
767
+ "\\bsansJ" : "𝗝",
768
+ "\\bsansK" : "𝗞",
769
+ "\\bsansL" : "𝗟",
770
+ "\\bsansM" : "𝗠",
771
+ "\\bsansN" : "𝗡",
772
+ "\\bsansO" : "𝗢",
773
+ "\\bsansP" : "𝗣",
774
+ "\\bsansQ" : "𝗤",
775
+ "\\bsansR" : "𝗥",
776
+ "\\bsansS" : "𝗦",
777
+ "\\bsansT" : "𝗧",
778
+ "\\bsansU" : "𝗨",
779
+ "\\bsansV" : "𝗩",
780
+ "\\bsansW" : "𝗪",
781
+ "\\bsansX" : "𝗫",
782
+ "\\bsansY" : "𝗬",
783
+ "\\bsansZ" : "𝗭",
784
+ "\\bsansa" : "𝗮",
785
+ "\\bsansb" : "𝗯",
786
+ "\\bsansc" : "𝗰",
787
+ "\\bsansd" : "𝗱",
788
+ "\\bsanse" : "𝗲",
789
+ "\\bsansf" : "𝗳",
790
+ "\\bsansg" : "𝗴",
791
+ "\\bsansh" : "𝗵",
792
+ "\\bsansi" : "𝗶",
793
+ "\\bsansj" : "𝗷",
794
+ "\\bsansk" : "𝗸",
795
+ "\\bsansl" : "𝗹",
796
+ "\\bsansm" : "𝗺",
797
+ "\\bsansn" : "𝗻",
798
+ "\\bsanso" : "𝗼",
799
+ "\\bsansp" : "𝗽",
800
+ "\\bsansq" : "𝗾",
801
+ "\\bsansr" : "𝗿",
802
+ "\\bsanss" : "𝘀",
803
+ "\\bsanst" : "𝘁",
804
+ "\\bsansu" : "𝘂",
805
+ "\\bsansv" : "𝘃",
806
+ "\\bsansw" : "𝘄",
807
+ "\\bsansx" : "𝘅",
808
+ "\\bsansy" : "𝘆",
809
+ "\\bsansz" : "𝘇",
810
+ "\\isansA" : "𝘈",
811
+ "\\isansB" : "𝘉",
812
+ "\\isansC" : "𝘊",
813
+ "\\isansD" : "𝘋",
814
+ "\\isansE" : "𝘌",
815
+ "\\isansF" : "𝘍",
816
+ "\\isansG" : "𝘎",
817
+ "\\isansH" : "𝘏",
818
+ "\\isansI" : "𝘐",
819
+ "\\isansJ" : "𝘑",
820
+ "\\isansK" : "𝘒",
821
+ "\\isansL" : "𝘓",
822
+ "\\isansM" : "𝘔",
823
+ "\\isansN" : "𝘕",
824
+ "\\isansO" : "𝘖",
825
+ "\\isansP" : "𝘗",
826
+ "\\isansQ" : "𝘘",
827
+ "\\isansR" : "𝘙",
828
+ "\\isansS" : "𝘚",
829
+ "\\isansT" : "𝘛",
830
+ "\\isansU" : "𝘜",
831
+ "\\isansV" : "𝘝",
832
+ "\\isansW" : "𝘞",
833
+ "\\isansX" : "𝘟",
834
+ "\\isansY" : "𝘠",
835
+ "\\isansZ" : "𝘡",
836
+ "\\isansa" : "𝘢",
837
+ "\\isansb" : "𝘣",
838
+ "\\isansc" : "𝘤",
839
+ "\\isansd" : "𝘥",
840
+ "\\isanse" : "𝘦",
841
+ "\\isansf" : "𝘧",
842
+ "\\isansg" : "𝘨",
843
+ "\\isansh" : "𝘩",
844
+ "\\isansi" : "𝘪",
845
+ "\\isansj" : "𝘫",
846
+ "\\isansk" : "𝘬",
847
+ "\\isansl" : "𝘭",
848
+ "\\isansm" : "𝘮",
849
+ "\\isansn" : "𝘯",
850
+ "\\isanso" : "𝘰",
851
+ "\\isansp" : "𝘱",
852
+ "\\isansq" : "𝘲",
853
+ "\\isansr" : "𝘳",
854
+ "\\isanss" : "𝘴",
855
+ "\\isanst" : "𝘵",
856
+ "\\isansu" : "𝘶",
857
+ "\\isansv" : "𝘷",
858
+ "\\isansw" : "𝘸",
859
+ "\\isansx" : "𝘹",
860
+ "\\isansy" : "𝘺",
861
+ "\\isansz" : "𝘻",
862
+ "\\bisansA" : "𝘼",
863
+ "\\bisansB" : "𝘽",
864
+ "\\bisansC" : "𝘾",
865
+ "\\bisansD" : "𝘿",
866
+ "\\bisansE" : "𝙀",
867
+ "\\bisansF" : "𝙁",
868
+ "\\bisansG" : "𝙂",
869
+ "\\bisansH" : "𝙃",
870
+ "\\bisansI" : "𝙄",
871
+ "\\bisansJ" : "𝙅",
872
+ "\\bisansK" : "𝙆",
873
+ "\\bisansL" : "𝙇",
874
+ "\\bisansM" : "𝙈",
875
+ "\\bisansN" : "𝙉",
876
+ "\\bisansO" : "𝙊",
877
+ "\\bisansP" : "𝙋",
878
+ "\\bisansQ" : "𝙌",
879
+ "\\bisansR" : "𝙍",
880
+ "\\bisansS" : "𝙎",
881
+ "\\bisansT" : "𝙏",
882
+ "\\bisansU" : "𝙐",
883
+ "\\bisansV" : "𝙑",
884
+ "\\bisansW" : "𝙒",
885
+ "\\bisansX" : "𝙓",
886
+ "\\bisansY" : "𝙔",
887
+ "\\bisansZ" : "𝙕",
888
+ "\\bisansa" : "𝙖",
889
+ "\\bisansb" : "𝙗",
890
+ "\\bisansc" : "𝙘",
891
+ "\\bisansd" : "𝙙",
892
+ "\\bisanse" : "𝙚",
893
+ "\\bisansf" : "𝙛",
894
+ "\\bisansg" : "𝙜",
895
+ "\\bisansh" : "𝙝",
896
+ "\\bisansi" : "𝙞",
897
+ "\\bisansj" : "𝙟",
898
+ "\\bisansk" : "𝙠",
899
+ "\\bisansl" : "𝙡",
900
+ "\\bisansm" : "𝙢",
901
+ "\\bisansn" : "𝙣",
902
+ "\\bisanso" : "𝙤",
903
+ "\\bisansp" : "𝙥",
904
+ "\\bisansq" : "𝙦",
905
+ "\\bisansr" : "𝙧",
906
+ "\\bisanss" : "𝙨",
907
+ "\\bisanst" : "𝙩",
908
+ "\\bisansu" : "𝙪",
909
+ "\\bisansv" : "𝙫",
910
+ "\\bisansw" : "𝙬",
911
+ "\\bisansx" : "𝙭",
912
+ "\\bisansy" : "𝙮",
913
+ "\\bisansz" : "𝙯",
914
+ "\\ttA" : "𝙰",
915
+ "\\ttB" : "𝙱",
916
+ "\\ttC" : "𝙲",
917
+ "\\ttD" : "𝙳",
918
+ "\\ttE" : "𝙴",
919
+ "\\ttF" : "𝙵",
920
+ "\\ttG" : "𝙶",
921
+ "\\ttH" : "𝙷",
922
+ "\\ttI" : "𝙸",
923
+ "\\ttJ" : "𝙹",
924
+ "\\ttK" : "𝙺",
925
+ "\\ttL" : "𝙻",
926
+ "\\ttM" : "𝙼",
927
+ "\\ttN" : "𝙽",
928
+ "\\ttO" : "𝙾",
929
+ "\\ttP" : "𝙿",
930
+ "\\ttQ" : "𝚀",
931
+ "\\ttR" : "𝚁",
932
+ "\\ttS" : "𝚂",
933
+ "\\ttT" : "𝚃",
934
+ "\\ttU" : "𝚄",
935
+ "\\ttV" : "𝚅",
936
+ "\\ttW" : "𝚆",
937
+ "\\ttX" : "𝚇",
938
+ "\\ttY" : "𝚈",
939
+ "\\ttZ" : "𝚉",
940
+ "\\tta" : "𝚊",
941
+ "\\ttb" : "𝚋",
942
+ "\\ttc" : "𝚌",
943
+ "\\ttd" : "𝚍",
944
+ "\\tte" : "𝚎",
945
+ "\\ttf" : "𝚏",
946
+ "\\ttg" : "𝚐",
947
+ "\\tth" : "𝚑",
948
+ "\\tti" : "𝚒",
949
+ "\\ttj" : "𝚓",
950
+ "\\ttk" : "𝚔",
951
+ "\\ttl" : "𝚕",
952
+ "\\ttm" : "𝚖",
953
+ "\\ttn" : "𝚗",
954
+ "\\tto" : "𝚘",
955
+ "\\ttp" : "𝚙",
956
+ "\\ttq" : "𝚚",
957
+ "\\ttr" : "𝚛",
958
+ "\\tts" : "𝚜",
959
+ "\\ttt" : "𝚝",
960
+ "\\ttu" : "𝚞",
961
+ "\\ttv" : "𝚟",
962
+ "\\ttw" : "𝚠",
963
+ "\\ttx" : "𝚡",
964
+ "\\tty" : "𝚢",
965
+ "\\ttz" : "𝚣",
966
+ "\\bfAlpha" : "𝚨",
967
+ "\\bfBeta" : "𝚩",
968
+ "\\bfGamma" : "𝚪",
969
+ "\\bfDelta" : "𝚫",
970
+ "\\bfEpsilon" : "𝚬",
971
+ "\\bfZeta" : "𝚭",
972
+ "\\bfEta" : "𝚮",
973
+ "\\bfTheta" : "𝚯",
974
+ "\\bfIota" : "𝚰",
975
+ "\\bfKappa" : "𝚱",
976
+ "\\bfLambda" : "𝚲",
977
+ "\\bfMu" : "𝚳",
978
+ "\\bfNu" : "𝚴",
979
+ "\\bfXi" : "𝚵",
980
+ "\\bfOmicron" : "𝚶",
981
+ "\\bfPi" : "𝚷",
982
+ "\\bfRho" : "𝚸",
983
+ "\\bfvarTheta" : "𝚹",
984
+ "\\bfSigma" : "𝚺",
985
+ "\\bfTau" : "𝚻",
986
+ "\\bfUpsilon" : "𝚼",
987
+ "\\bfPhi" : "𝚽",
988
+ "\\bfChi" : "𝚾",
989
+ "\\bfPsi" : "𝚿",
990
+ "\\bfOmega" : "𝛀",
991
+ "\\bfalpha" : "𝛂",
992
+ "\\bfbeta" : "𝛃",
993
+ "\\bfgamma" : "𝛄",
994
+ "\\bfdelta" : "𝛅",
995
+ "\\bfepsilon" : "𝛆",
996
+ "\\bfzeta" : "𝛇",
997
+ "\\bfeta" : "𝛈",
998
+ "\\bftheta" : "𝛉",
999
+ "\\bfiota" : "𝛊",
1000
+ "\\bfkappa" : "𝛋",
1001
+ "\\bflambda" : "𝛌",
1002
+ "\\bfmu" : "𝛍",
1003
+ "\\bfnu" : "𝛎",
1004
+ "\\bfxi" : "𝛏",
1005
+ "\\bfomicron" : "𝛐",
1006
+ "\\bfpi" : "𝛑",
1007
+ "\\bfrho" : "𝛒",
1008
+ "\\bfvarsigma" : "𝛓",
1009
+ "\\bfsigma" : "𝛔",
1010
+ "\\bftau" : "𝛕",
1011
+ "\\bfupsilon" : "𝛖",
1012
+ "\\bfvarphi" : "𝛗",
1013
+ "\\bfchi" : "𝛘",
1014
+ "\\bfpsi" : "𝛙",
1015
+ "\\bfomega" : "𝛚",
1016
+ "\\bfvarepsilon" : "𝛜",
1017
+ "\\bfvartheta" : "𝛝",
1018
+ "\\bfvarkappa" : "𝛞",
1019
+ "\\bfphi" : "𝛟",
1020
+ "\\bfvarrho" : "𝛠",
1021
+ "\\bfvarpi" : "𝛡",
1022
+ "\\itAlpha" : "𝛢",
1023
+ "\\itBeta" : "𝛣",
1024
+ "\\itGamma" : "𝛤",
1025
+ "\\itDelta" : "𝛥",
1026
+ "\\itEpsilon" : "𝛦",
1027
+ "\\itZeta" : "𝛧",
1028
+ "\\itEta" : "𝛨",
1029
+ "\\itTheta" : "𝛩",
1030
+ "\\itIota" : "𝛪",
1031
+ "\\itKappa" : "𝛫",
1032
+ "\\itLambda" : "𝛬",
1033
+ "\\itMu" : "𝛭",
1034
+ "\\itNu" : "𝛮",
1035
+ "\\itXi" : "𝛯",
1036
+ "\\itOmicron" : "𝛰",
1037
+ "\\itPi" : "𝛱",
1038
+ "\\itRho" : "𝛲",
1039
+ "\\itvarTheta" : "𝛳",
1040
+ "\\itSigma" : "𝛴",
1041
+ "\\itTau" : "𝛵",
1042
+ "\\itUpsilon" : "𝛶",
1043
+ "\\itPhi" : "𝛷",
1044
+ "\\itChi" : "𝛸",
1045
+ "\\itPsi" : "𝛹",
1046
+ "\\itOmega" : "𝛺",
1047
+ "\\italpha" : "𝛼",
1048
+ "\\itbeta" : "𝛽",
1049
+ "\\itgamma" : "𝛾",
1050
+ "\\itdelta" : "𝛿",
1051
+ "\\itepsilon" : "𝜀",
1052
+ "\\itzeta" : "𝜁",
1053
+ "\\iteta" : "𝜂",
1054
+ "\\ittheta" : "𝜃",
1055
+ "\\itiota" : "𝜄",
1056
+ "\\itkappa" : "𝜅",
1057
+ "\\itlambda" : "𝜆",
1058
+ "\\itmu" : "𝜇",
1059
+ "\\itnu" : "𝜈",
1060
+ "\\itxi" : "𝜉",
1061
+ "\\itomicron" : "𝜊",
1062
+ "\\itpi" : "𝜋",
1063
+ "\\itrho" : "𝜌",
1064
+ "\\itvarsigma" : "𝜍",
1065
+ "\\itsigma" : "𝜎",
1066
+ "\\ittau" : "𝜏",
1067
+ "\\itupsilon" : "𝜐",
1068
+ "\\itphi" : "𝜑",
1069
+ "\\itchi" : "𝜒",
1070
+ "\\itpsi" : "𝜓",
1071
+ "\\itomega" : "𝜔",
1072
+ "\\itvarepsilon" : "𝜖",
1073
+ "\\itvartheta" : "𝜗",
1074
+ "\\itvarkappa" : "𝜘",
1075
+ "\\itvarphi" : "𝜙",
1076
+ "\\itvarrho" : "𝜚",
1077
+ "\\itvarpi" : "𝜛",
1078
+ "\\biAlpha" : "𝜜",
1079
+ "\\biBeta" : "𝜝",
1080
+ "\\biGamma" : "𝜞",
1081
+ "\\biDelta" : "𝜟",
1082
+ "\\biEpsilon" : "𝜠",
1083
+ "\\biZeta" : "𝜡",
1084
+ "\\biEta" : "𝜢",
1085
+ "\\biTheta" : "𝜣",
1086
+ "\\biIota" : "𝜤",
1087
+ "\\biKappa" : "𝜥",
1088
+ "\\biLambda" : "𝜦",
1089
+ "\\biMu" : "𝜧",
1090
+ "\\biNu" : "𝜨",
1091
+ "\\biXi" : "𝜩",
1092
+ "\\biOmicron" : "𝜪",
1093
+ "\\biPi" : "𝜫",
1094
+ "\\biRho" : "𝜬",
1095
+ "\\bivarTheta" : "𝜭",
1096
+ "\\biSigma" : "𝜮",
1097
+ "\\biTau" : "𝜯",
1098
+ "\\biUpsilon" : "𝜰",
1099
+ "\\biPhi" : "𝜱",
1100
+ "\\biChi" : "𝜲",
1101
+ "\\biPsi" : "𝜳",
1102
+ "\\biOmega" : "𝜴",
1103
+ "\\bialpha" : "𝜶",
1104
+ "\\bibeta" : "𝜷",
1105
+ "\\bigamma" : "𝜸",
1106
+ "\\bidelta" : "𝜹",
1107
+ "\\biepsilon" : "𝜺",
1108
+ "\\bizeta" : "𝜻",
1109
+ "\\bieta" : "𝜼",
1110
+ "\\bitheta" : "𝜽",
1111
+ "\\biiota" : "𝜾",
1112
+ "\\bikappa" : "𝜿",
1113
+ "\\bilambda" : "𝝀",
1114
+ "\\bimu" : "𝝁",
1115
+ "\\binu" : "𝝂",
1116
+ "\\bixi" : "𝝃",
1117
+ "\\biomicron" : "𝝄",
1118
+ "\\bipi" : "𝝅",
1119
+ "\\birho" : "𝝆",
1120
+ "\\bivarsigma" : "𝝇",
1121
+ "\\bisigma" : "𝝈",
1122
+ "\\bitau" : "𝝉",
1123
+ "\\biupsilon" : "𝝊",
1124
+ "\\biphi" : "𝝋",
1125
+ "\\bichi" : "𝝌",
1126
+ "\\bipsi" : "𝝍",
1127
+ "\\biomega" : "𝝎",
1128
+ "\\bivarepsilon" : "𝝐",
1129
+ "\\bivartheta" : "𝝑",
1130
+ "\\bivarkappa" : "𝝒",
1131
+ "\\bivarphi" : "𝝓",
1132
+ "\\bivarrho" : "𝝔",
1133
+ "\\bivarpi" : "𝝕",
1134
+ "\\bsansAlpha" : "𝝖",
1135
+ "\\bsansBeta" : "𝝗",
1136
+ "\\bsansGamma" : "𝝘",
1137
+ "\\bsansDelta" : "𝝙",
1138
+ "\\bsansEpsilon" : "𝝚",
1139
+ "\\bsansZeta" : "𝝛",
1140
+ "\\bsansEta" : "𝝜",
1141
+ "\\bsansTheta" : "𝝝",
1142
+ "\\bsansIota" : "𝝞",
1143
+ "\\bsansKappa" : "𝝟",
1144
+ "\\bsansLambda" : "𝝠",
1145
+ "\\bsansMu" : "𝝡",
1146
+ "\\bsansNu" : "𝝢",
1147
+ "\\bsansXi" : "𝝣",
1148
+ "\\bsansOmicron" : "𝝤",
1149
+ "\\bsansPi" : "𝝥",
1150
+ "\\bsansRho" : "𝝦",
1151
+ "\\bsansvarTheta" : "𝝧",
1152
+ "\\bsansSigma" : "𝝨",
1153
+ "\\bsansTau" : "𝝩",
1154
+ "\\bsansUpsilon" : "𝝪",
1155
+ "\\bsansPhi" : "𝝫",
1156
+ "\\bsansChi" : "𝝬",
1157
+ "\\bsansPsi" : "𝝭",
1158
+ "\\bsansOmega" : "𝝮",
1159
+ "\\bsansalpha" : "𝝰",
1160
+ "\\bsansbeta" : "𝝱",
1161
+ "\\bsansgamma" : "𝝲",
1162
+ "\\bsansdelta" : "𝝳",
1163
+ "\\bsansepsilon" : "𝝴",
1164
+ "\\bsanszeta" : "𝝵",
1165
+ "\\bsanseta" : "𝝶",
1166
+ "\\bsanstheta" : "𝝷",
1167
+ "\\bsansiota" : "𝝸",
1168
+ "\\bsanskappa" : "𝝹",
1169
+ "\\bsanslambda" : "𝝺",
1170
+ "\\bsansmu" : "𝝻",
1171
+ "\\bsansnu" : "𝝼",
1172
+ "\\bsansxi" : "𝝽",
1173
+ "\\bsansomicron" : "𝝾",
1174
+ "\\bsanspi" : "𝝿",
1175
+ "\\bsansrho" : "𝞀",
1176
+ "\\bsansvarsigma" : "𝞁",
1177
+ "\\bsanssigma" : "𝞂",
1178
+ "\\bsanstau" : "𝞃",
1179
+ "\\bsansupsilon" : "𝞄",
1180
+ "\\bsansphi" : "𝞅",
1181
+ "\\bsanschi" : "𝞆",
1182
+ "\\bsanspsi" : "𝞇",
1183
+ "\\bsansomega" : "𝞈",
1184
+ "\\bsansvarepsilon" : "𝞊",
1185
+ "\\bsansvartheta" : "𝞋",
1186
+ "\\bsansvarkappa" : "𝞌",
1187
+ "\\bsansvarphi" : "𝞍",
1188
+ "\\bsansvarrho" : "𝞎",
1189
+ "\\bsansvarpi" : "𝞏",
1190
+ "\\bisansAlpha" : "𝞐",
1191
+ "\\bisansBeta" : "𝞑",
1192
+ "\\bisansGamma" : "𝞒",
1193
+ "\\bisansDelta" : "𝞓",
1194
+ "\\bisansEpsilon" : "𝞔",
1195
+ "\\bisansZeta" : "𝞕",
1196
+ "\\bisansEta" : "𝞖",
1197
+ "\\bisansTheta" : "𝞗",
1198
+ "\\bisansIota" : "𝞘",
1199
+ "\\bisansKappa" : "𝞙",
1200
+ "\\bisansLambda" : "𝞚",
1201
+ "\\bisansMu" : "𝞛",
1202
+ "\\bisansNu" : "𝞜",
1203
+ "\\bisansXi" : "𝞝",
1204
+ "\\bisansOmicron" : "𝞞",
1205
+ "\\bisansPi" : "𝞟",
1206
+ "\\bisansRho" : "𝞠",
1207
+ "\\bisansvarTheta" : "𝞡",
1208
+ "\\bisansSigma" : "𝞢",
1209
+ "\\bisansTau" : "𝞣",
1210
+ "\\bisansUpsilon" : "𝞤",
1211
+ "\\bisansPhi" : "𝞥",
1212
+ "\\bisansChi" : "𝞦",
1213
+ "\\bisansPsi" : "𝞧",
1214
+ "\\bisansOmega" : "𝞨",
1215
+ "\\bisansalpha" : "𝞪",
1216
+ "\\bisansbeta" : "𝞫",
1217
+ "\\bisansgamma" : "𝞬",
1218
+ "\\bisansdelta" : "𝞭",
1219
+ "\\bisansepsilon" : "𝞮",
1220
+ "\\bisanszeta" : "𝞯",
1221
+ "\\bisanseta" : "𝞰",
1222
+ "\\bisanstheta" : "𝞱",
1223
+ "\\bisansiota" : "𝞲",
1224
+ "\\bisanskappa" : "𝞳",
1225
+ "\\bisanslambda" : "𝞴",
1226
+ "\\bisansmu" : "𝞵",
1227
+ "\\bisansnu" : "𝞶",
1228
+ "\\bisansxi" : "𝞷",
1229
+ "\\bisansomicron" : "𝞸",
1230
+ "\\bisanspi" : "𝞹",
1231
+ "\\bisansrho" : "𝞺",
1232
+ "\\bisansvarsigma" : "𝞻",
1233
+ "\\bisanssigma" : "𝞼",
1234
+ "\\bisanstau" : "𝞽",
1235
+ "\\bisansupsilon" : "𝞾",
1236
+ "\\bisansphi" : "𝞿",
1237
+ "\\bisanschi" : "𝟀",
1238
+ "\\bisanspsi" : "𝟁",
1239
+ "\\bisansomega" : "𝟂",
1240
+ "\\bisansvarepsilon" : "𝟄",
1241
+ "\\bisansvartheta" : "𝟅",
1242
+ "\\bisansvarkappa" : "𝟆",
1243
+ "\\bisansvarphi" : "𝟇",
1244
+ "\\bisansvarrho" : "𝟈",
1245
+ "\\bisansvarpi" : "𝟉",
1246
+ "\\bfzero" : "𝟎",
1247
+ "\\bfone" : "𝟏",
1248
+ "\\bftwo" : "𝟐",
1249
+ "\\bfthree" : "𝟑",
1250
+ "\\bffour" : "𝟒",
1251
+ "\\bffive" : "𝟓",
1252
+ "\\bfsix" : "𝟔",
1253
+ "\\bfseven" : "𝟕",
1254
+ "\\bfeight" : "𝟖",
1255
+ "\\bfnine" : "𝟗",
1256
+ "\\bbzero" : "𝟘",
1257
+ "\\bbone" : "𝟙",
1258
+ "\\bbtwo" : "𝟚",
1259
+ "\\bbthree" : "𝟛",
1260
+ "\\bbfour" : "𝟜",
1261
+ "\\bbfive" : "𝟝",
1262
+ "\\bbsix" : "𝟞",
1263
+ "\\bbseven" : "𝟟",
1264
+ "\\bbeight" : "𝟠",
1265
+ "\\bbnine" : "𝟡",
1266
+ "\\sanszero" : "𝟢",
1267
+ "\\sansone" : "𝟣",
1268
+ "\\sanstwo" : "𝟤",
1269
+ "\\sansthree" : "𝟥",
1270
+ "\\sansfour" : "𝟦",
1271
+ "\\sansfive" : "𝟧",
1272
+ "\\sanssix" : "𝟨",
1273
+ "\\sansseven" : "𝟩",
1274
+ "\\sanseight" : "𝟪",
1275
+ "\\sansnine" : "𝟫",
1276
+ "\\bsanszero" : "𝟬",
1277
+ "\\bsansone" : "𝟭",
1278
+ "\\bsanstwo" : "𝟮",
1279
+ "\\bsansthree" : "𝟯",
1280
+ "\\bsansfour" : "𝟰",
1281
+ "\\bsansfive" : "𝟱",
1282
+ "\\bsanssix" : "𝟲",
1283
+ "\\bsansseven" : "𝟳",
1284
+ "\\bsanseight" : "𝟴",
1285
+ "\\bsansnine" : "𝟵",
1286
+ "\\ttzero" : "𝟶",
1287
+ "\\ttone" : "𝟷",
1288
+ "\\tttwo" : "𝟸",
1289
+ "\\ttthree" : "𝟹",
1290
+ "\\ttfour" : "𝟺",
1291
+ "\\ttfive" : "𝟻",
1292
+ "\\ttsix" : "𝟼",
1293
+ "\\ttseven" : "𝟽",
1294
+ "\\tteight" : "𝟾",
1295
+ "\\ttnine" : "𝟿",
1296
+ "\\underbar" : "̲",
1297
+ "\\underleftrightarrow" : "͍",
1298
+ }
1299
+
1300
+
1301
+ reverse_latex_symbol = { v:k for k,v in latex_symbols.items()}
openalex_env_map/lib/python3.10/site-packages/IPython/core/logger.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Logger class for IPython's logging facilities.
2
+ """
3
+
4
+ #*****************************************************************************
5
+ # Copyright (C) 2001 Janko Hauser <[email protected]> and
6
+ # Copyright (C) 2001-2006 Fernando Perez <[email protected]>
7
+ #
8
+ # Distributed under the terms of the BSD License. The full license is in
9
+ # the file COPYING, distributed as part of this software.
10
+ #*****************************************************************************
11
+
12
+ #****************************************************************************
13
+ # Modules and globals
14
+
15
+ # Python standard modules
16
+ import glob
17
+ import io
18
+ import logging
19
+ import os
20
+ import time
21
+
22
+
23
+ # prevent jedi/parso's debug messages pipe into interactiveshell
24
+ logging.getLogger("parso").setLevel(logging.WARNING)
25
+
26
+ #****************************************************************************
27
+ # FIXME: This class isn't a mixin anymore, but it still needs attributes from
28
+ # ipython and does input cache management. Finish cleanup later...
29
+
30
+ class Logger(object):
31
+ """A Logfile class with different policies for file creation"""
32
+
33
+ def __init__(self, home_dir, logfname='Logger.log', loghead=u'',
34
+ logmode='over'):
35
+
36
+ # this is the full ipython instance, we need some attributes from it
37
+ # which won't exist until later. What a mess, clean up later...
38
+ self.home_dir = home_dir
39
+
40
+ self.logfname = logfname
41
+ self.loghead = loghead
42
+ self.logmode = logmode
43
+ self.logfile = None
44
+
45
+ # Whether to log raw or processed input
46
+ self.log_raw_input = False
47
+
48
+ # whether to also log output
49
+ self.log_output = False
50
+
51
+ # whether to put timestamps before each log entry
52
+ self.timestamp = False
53
+
54
+ # activity control flags
55
+ self.log_active = False
56
+
57
+ # logmode is a validated property
58
+ def _set_mode(self,mode):
59
+ if mode not in ['append','backup','global','over','rotate']:
60
+ raise ValueError('invalid log mode %s given' % mode)
61
+ self._logmode = mode
62
+
63
+ def _get_mode(self):
64
+ return self._logmode
65
+
66
+ logmode = property(_get_mode,_set_mode)
67
+
68
+ def logstart(self, logfname=None, loghead=None, logmode=None,
69
+ log_output=False, timestamp=False, log_raw_input=False):
70
+ """Generate a new log-file with a default header.
71
+
72
+ Raises RuntimeError if the log has already been started"""
73
+
74
+ if self.logfile is not None:
75
+ raise RuntimeError('Log file is already active: %s' %
76
+ self.logfname)
77
+
78
+ # The parameters can override constructor defaults
79
+ if logfname is not None: self.logfname = logfname
80
+ if loghead is not None: self.loghead = loghead
81
+ if logmode is not None: self.logmode = logmode
82
+
83
+ # Parameters not part of the constructor
84
+ self.timestamp = timestamp
85
+ self.log_output = log_output
86
+ self.log_raw_input = log_raw_input
87
+
88
+ # init depending on the log mode requested
89
+ isfile = os.path.isfile
90
+ logmode = self.logmode
91
+
92
+ if logmode == 'append':
93
+ self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
94
+
95
+ elif logmode == 'backup':
96
+ if isfile(self.logfname):
97
+ backup_logname = self.logfname+'~'
98
+ # Manually remove any old backup, since os.rename may fail
99
+ # under Windows.
100
+ if isfile(backup_logname):
101
+ os.remove(backup_logname)
102
+ os.rename(self.logfname,backup_logname)
103
+ self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
104
+
105
+ elif logmode == 'global':
106
+ self.logfname = os.path.join(self.home_dir,self.logfname)
107
+ self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
108
+
109
+ elif logmode == 'over':
110
+ if isfile(self.logfname):
111
+ os.remove(self.logfname)
112
+ self.logfile = io.open(self.logfname,'w', encoding='utf-8')
113
+
114
+ elif logmode == 'rotate':
115
+ if isfile(self.logfname):
116
+ if isfile(self.logfname+'.001~'):
117
+ old = glob.glob(self.logfname+'.*~')
118
+ old.sort()
119
+ old.reverse()
120
+ for f in old:
121
+ root, ext = os.path.splitext(f)
122
+ num = int(ext[1:-1])+1
123
+ os.rename(f, root+'.'+repr(num).zfill(3)+'~')
124
+ os.rename(self.logfname, self.logfname+'.001~')
125
+ self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
126
+
127
+ if logmode != 'append':
128
+ self.logfile.write(self.loghead)
129
+
130
+ self.logfile.flush()
131
+ self.log_active = True
132
+
133
+ def switch_log(self,val):
134
+ """Switch logging on/off. val should be ONLY a boolean."""
135
+
136
+ if val not in [False,True,0,1]:
137
+ raise ValueError('Call switch_log ONLY with a boolean argument, '
138
+ 'not with: %s' % val)
139
+
140
+ label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
141
+
142
+ if self.logfile is None:
143
+ print("""
144
+ Logging hasn't been started yet (use logstart for that).
145
+
146
+ %logon/%logoff are for temporarily starting and stopping logging for a logfile
147
+ which already exists. But you must first start the logging process with
148
+ %logstart (optionally giving a logfile name).""")
149
+
150
+ else:
151
+ if self.log_active == val:
152
+ print('Logging is already',label[val])
153
+ else:
154
+ print('Switching logging',label[val])
155
+ self.log_active = not self.log_active
156
+ self.log_active_out = self.log_active
157
+
158
+ def logstate(self):
159
+ """Print a status message about the logger."""
160
+ if self.logfile is None:
161
+ print('Logging has not been activated.')
162
+ else:
163
+ state = self.log_active and 'active' or 'temporarily suspended'
164
+ print('Filename :', self.logfname)
165
+ print('Mode :', self.logmode)
166
+ print('Output logging :', self.log_output)
167
+ print('Raw input log :', self.log_raw_input)
168
+ print('Timestamping :', self.timestamp)
169
+ print('State :', state)
170
+
171
+ def log(self, line_mod, line_ori):
172
+ """Write the sources to a log.
173
+
174
+ Inputs:
175
+
176
+ - line_mod: possibly modified input, such as the transformations made
177
+ by input prefilters or input handlers of various kinds. This should
178
+ always be valid Python.
179
+
180
+ - line_ori: unmodified input line from the user. This is not
181
+ necessarily valid Python.
182
+ """
183
+
184
+ # Write the log line, but decide which one according to the
185
+ # log_raw_input flag, set when the log is started.
186
+ if self.log_raw_input:
187
+ self.log_write(line_ori)
188
+ else:
189
+ self.log_write(line_mod)
190
+
191
+ def log_write(self, data, kind='input'):
192
+ """Write data to the log file, if active"""
193
+
194
+ # print('data: %r' % data) # dbg
195
+ if self.log_active and data:
196
+ write = self.logfile.write
197
+ if kind=='input':
198
+ if self.timestamp:
199
+ write(time.strftime('# %a, %d %b %Y %H:%M:%S\n', time.localtime()))
200
+ write(data)
201
+ elif kind=='output' and self.log_output:
202
+ odata = u'\n'.join([u'#[Out]# %s' % s
203
+ for s in data.splitlines()])
204
+ write(u'%s\n' % odata)
205
+ try:
206
+ self.logfile.flush()
207
+ except OSError:
208
+ print("Failed to flush the log file.")
209
+ print(
210
+ f"Please check that {self.logfname} exists and have the right permissions."
211
+ )
212
+ print(
213
+ "Also consider turning off the log with `%logstop` to avoid this warning."
214
+ )
215
+
216
+ def logstop(self):
217
+ """Fully stop logging and close log file.
218
+
219
+ In order to start logging again, a new logstart() call needs to be
220
+ made, possibly (though not necessarily) with a new filename, mode and
221
+ other options."""
222
+
223
+ if self.logfile is not None:
224
+ self.logfile.close()
225
+ self.logfile = None
226
+ else:
227
+ print("Logging hadn't been started.")
228
+ self.log_active = False
229
+
230
+ # For backwards compatibility, in case anyone was using this.
231
+ close_log = logstop
openalex_env_map/lib/python3.10/site-packages/IPython/core/macro.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Support for interactive macros in IPython"""
2
+
3
+ #*****************************************************************************
4
+ # Copyright (C) 2001-2005 Fernando Perez <[email protected]>
5
+ #
6
+ # Distributed under the terms of the BSD License. The full license is in
7
+ # the file COPYING, distributed as part of this software.
8
+ #*****************************************************************************
9
+
10
+ import re
11
+
12
+ from IPython.utils.encoding import DEFAULT_ENCODING
13
+
14
+ coding_declaration = re.compile(r"#\s*coding[:=]\s*([-\w.]+)")
15
+
16
+ class Macro(object):
17
+ """Simple class to store the value of macros as strings.
18
+
19
+ Macro is just a callable that executes a string of IPython
20
+ input when called.
21
+ """
22
+
23
+ def __init__(self,code):
24
+ """store the macro value, as a single string which can be executed"""
25
+ lines = []
26
+ enc = None
27
+ for line in code.splitlines():
28
+ coding_match = coding_declaration.match(line)
29
+ if coding_match:
30
+ enc = coding_match.group(1)
31
+ else:
32
+ lines.append(line)
33
+ code = "\n".join(lines)
34
+ if isinstance(code, bytes):
35
+ code = code.decode(enc or DEFAULT_ENCODING)
36
+ self.value = code + '\n'
37
+
38
+ def __str__(self):
39
+ return self.value
40
+
41
+ def __repr__(self):
42
+ return 'IPython.macro.Macro(%s)' % repr(self.value)
43
+
44
+ def __getstate__(self):
45
+ """ needed for safe pickling via %store """
46
+ return {'value': self.value}
47
+
48
+ def __add__(self, other):
49
+ if isinstance(other, Macro):
50
+ return Macro(self.value + other.value)
51
+ elif isinstance(other, str):
52
+ return Macro(self.value + other)
53
+ raise TypeError
openalex_env_map/lib/python3.10/site-packages/IPython/core/magic.py ADDED
@@ -0,0 +1,759 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """Magic functions for InteractiveShell.
3
+ """
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Copyright (C) 2001 Janko Hauser <[email protected]> and
7
+ # Copyright (C) 2001 Fernando Perez <[email protected]>
8
+ # Copyright (C) 2008 The IPython Development Team
9
+
10
+ # Distributed under the terms of the BSD License. The full license is in
11
+ # the file COPYING, distributed as part of this software.
12
+ #-----------------------------------------------------------------------------
13
+
14
+ import os
15
+ import re
16
+ import sys
17
+ from getopt import getopt, GetoptError
18
+
19
+ from traitlets.config.configurable import Configurable
20
+ from . import oinspect
21
+ from .error import UsageError
22
+ from .inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
23
+ from ..utils.ipstruct import Struct
24
+ from ..utils.process import arg_split
25
+ from ..utils.text import dedent
26
+ from traitlets import Bool, Dict, Instance, observe
27
+ from logging import error
28
+
29
+ import typing as t
30
+
31
+ #-----------------------------------------------------------------------------
32
+ # Globals
33
+ #-----------------------------------------------------------------------------
34
+
35
+ # A dict we'll use for each class that has magics, used as temporary storage to
36
+ # pass information between the @line/cell_magic method decorators and the
37
+ # @magics_class class decorator, because the method decorators have no
38
+ # access to the class when they run. See for more details:
39
+ # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
40
+
41
+ magics: t.Dict = dict(line={}, cell={})
42
+
43
+ magic_kinds = ('line', 'cell')
44
+ magic_spec = ('line', 'cell', 'line_cell')
45
+ magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
46
+
47
+ #-----------------------------------------------------------------------------
48
+ # Utility classes and functions
49
+ #-----------------------------------------------------------------------------
50
+
51
+ class Bunch: pass
52
+
53
+
54
+ def on_off(tag):
55
+ """Return an ON/OFF string for a 1/0 input. Simple utility function."""
56
+ return ['OFF','ON'][tag]
57
+
58
+
59
+ def compress_dhist(dh):
60
+ """Compress a directory history into a new one with at most 20 entries.
61
+
62
+ Return a new list made from the first and last 10 elements of dhist after
63
+ removal of duplicates.
64
+ """
65
+ head, tail = dh[:-10], dh[-10:]
66
+
67
+ newhead = []
68
+ done = set()
69
+ for h in head:
70
+ if h in done:
71
+ continue
72
+ newhead.append(h)
73
+ done.add(h)
74
+
75
+ return newhead + tail
76
+
77
+
78
+ def needs_local_scope(func):
79
+ """Decorator to mark magic functions which need to local scope to run."""
80
+ func.needs_local_scope = True
81
+ return func
82
+
83
+ #-----------------------------------------------------------------------------
84
+ # Class and method decorators for registering magics
85
+ #-----------------------------------------------------------------------------
86
+
87
+ def magics_class(cls):
88
+ """Class decorator for all subclasses of the main Magics class.
89
+
90
+ Any class that subclasses Magics *must* also apply this decorator, to
91
+ ensure that all the methods that have been decorated as line/cell magics
92
+ get correctly registered in the class instance. This is necessary because
93
+ when method decorators run, the class does not exist yet, so they
94
+ temporarily store their information into a module global. Application of
95
+ this class decorator copies that global data to the class instance and
96
+ clears the global.
97
+
98
+ Obviously, this mechanism is not thread-safe, which means that the
99
+ *creation* of subclasses of Magic should only be done in a single-thread
100
+ context. Instantiation of the classes has no restrictions. Given that
101
+ these classes are typically created at IPython startup time and before user
102
+ application code becomes active, in practice this should not pose any
103
+ problems.
104
+ """
105
+ cls.registered = True
106
+ cls.magics = dict(line = magics['line'],
107
+ cell = magics['cell'])
108
+ magics['line'] = {}
109
+ magics['cell'] = {}
110
+ return cls
111
+
112
+
113
+ def record_magic(dct, magic_kind, magic_name, func):
114
+ """Utility function to store a function as a magic of a specific kind.
115
+
116
+ Parameters
117
+ ----------
118
+ dct : dict
119
+ A dictionary with 'line' and 'cell' subdicts.
120
+ magic_kind : str
121
+ Kind of magic to be stored.
122
+ magic_name : str
123
+ Key to store the magic as.
124
+ func : function
125
+ Callable object to store.
126
+ """
127
+ if magic_kind == 'line_cell':
128
+ dct['line'][magic_name] = dct['cell'][magic_name] = func
129
+ else:
130
+ dct[magic_kind][magic_name] = func
131
+
132
+
133
+ def validate_type(magic_kind):
134
+ """Ensure that the given magic_kind is valid.
135
+
136
+ Check that the given magic_kind is one of the accepted spec types (stored
137
+ in the global `magic_spec`), raise ValueError otherwise.
138
+ """
139
+ if magic_kind not in magic_spec:
140
+ raise ValueError('magic_kind must be one of %s, %s given' %
141
+ magic_kinds, magic_kind)
142
+
143
+
144
+ # The docstrings for the decorator below will be fairly similar for the two
145
+ # types (method and function), so we generate them here once and reuse the
146
+ # templates below.
147
+ _docstring_template = \
148
+ """Decorate the given {0} as {1} magic.
149
+
150
+ The decorator can be used with or without arguments, as follows.
151
+
152
+ i) without arguments: it will create a {1} magic named as the {0} being
153
+ decorated::
154
+
155
+ @deco
156
+ def foo(...)
157
+
158
+ will create a {1} magic named `foo`.
159
+
160
+ ii) with one string argument: which will be used as the actual name of the
161
+ resulting magic::
162
+
163
+ @deco('bar')
164
+ def foo(...)
165
+
166
+ will create a {1} magic named `bar`.
167
+
168
+ To register a class magic use ``Interactiveshell.register_magic(class or instance)``.
169
+ """
170
+
171
+ # These two are decorator factories. While they are conceptually very similar,
172
+ # there are enough differences in the details that it's simpler to have them
173
+ # written as completely standalone functions rather than trying to share code
174
+ # and make a single one with convoluted logic.
175
+
176
+ def _method_magic_marker(magic_kind):
177
+ """Decorator factory for methods in Magics subclasses.
178
+ """
179
+
180
+ validate_type(magic_kind)
181
+
182
+ # This is a closure to capture the magic_kind. We could also use a class,
183
+ # but it's overkill for just that one bit of state.
184
+ def magic_deco(arg):
185
+ if callable(arg):
186
+ # "Naked" decorator call (just @foo, no args)
187
+ func = arg
188
+ name = func.__name__
189
+ retval = arg
190
+ record_magic(magics, magic_kind, name, name)
191
+ elif isinstance(arg, str):
192
+ # Decorator called with arguments (@foo('bar'))
193
+ name = arg
194
+ def mark(func, *a, **kw):
195
+ record_magic(magics, magic_kind, name, func.__name__)
196
+ return func
197
+ retval = mark
198
+ else:
199
+ raise TypeError("Decorator can only be called with "
200
+ "string or function")
201
+ return retval
202
+
203
+ # Ensure the resulting decorator has a usable docstring
204
+ magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
205
+ return magic_deco
206
+
207
+
208
+ def _function_magic_marker(magic_kind):
209
+ """Decorator factory for standalone functions.
210
+ """
211
+ validate_type(magic_kind)
212
+
213
+ # This is a closure to capture the magic_kind. We could also use a class,
214
+ # but it's overkill for just that one bit of state.
215
+ def magic_deco(arg):
216
+ # Find get_ipython() in the caller's namespace
217
+ caller = sys._getframe(1)
218
+ for ns in ['f_locals', 'f_globals', 'f_builtins']:
219
+ get_ipython = getattr(caller, ns).get('get_ipython')
220
+ if get_ipython is not None:
221
+ break
222
+ else:
223
+ raise NameError('Decorator can only run in context where '
224
+ '`get_ipython` exists')
225
+
226
+ ip = get_ipython()
227
+
228
+ if callable(arg):
229
+ # "Naked" decorator call (just @foo, no args)
230
+ func = arg
231
+ name = func.__name__
232
+ ip.register_magic_function(func, magic_kind, name)
233
+ retval = arg
234
+ elif isinstance(arg, str):
235
+ # Decorator called with arguments (@foo('bar'))
236
+ name = arg
237
+ def mark(func, *a, **kw):
238
+ ip.register_magic_function(func, magic_kind, name)
239
+ return func
240
+ retval = mark
241
+ else:
242
+ raise TypeError("Decorator can only be called with "
243
+ "string or function")
244
+ return retval
245
+
246
+ # Ensure the resulting decorator has a usable docstring
247
+ ds = _docstring_template.format('function', magic_kind)
248
+
249
+ ds += dedent("""
250
+ Note: this decorator can only be used in a context where IPython is already
251
+ active, so that the `get_ipython()` call succeeds. You can therefore use
252
+ it in your startup files loaded after IPython initializes, but *not* in the
253
+ IPython configuration file itself, which is executed before IPython is
254
+ fully up and running. Any file located in the `startup` subdirectory of
255
+ your configuration profile will be OK in this sense.
256
+ """)
257
+
258
+ magic_deco.__doc__ = ds
259
+ return magic_deco
260
+
261
+
262
+ MAGIC_NO_VAR_EXPAND_ATTR = "_ipython_magic_no_var_expand"
263
+ MAGIC_OUTPUT_CAN_BE_SILENCED = "_ipython_magic_output_can_be_silenced"
264
+
265
+
266
+ def no_var_expand(magic_func):
267
+ """Mark a magic function as not needing variable expansion
268
+
269
+ By default, IPython interprets `{a}` or `$a` in the line passed to magics
270
+ as variables that should be interpolated from the interactive namespace
271
+ before passing the line to the magic function.
272
+ This is not always desirable, e.g. when the magic executes Python code
273
+ (%timeit, %time, etc.).
274
+ Decorate magics with `@no_var_expand` to opt-out of variable expansion.
275
+
276
+ .. versionadded:: 7.3
277
+ """
278
+ setattr(magic_func, MAGIC_NO_VAR_EXPAND_ATTR, True)
279
+ return magic_func
280
+
281
+
282
+ def output_can_be_silenced(magic_func):
283
+ """Mark a magic function so its output may be silenced.
284
+
285
+ The output is silenced if the Python code used as a parameter of
286
+ the magic ends in a semicolon, not counting a Python comment that can
287
+ follow it.
288
+ """
289
+ setattr(magic_func, MAGIC_OUTPUT_CAN_BE_SILENCED, True)
290
+ return magic_func
291
+
292
+ # Create the actual decorators for public use
293
+
294
+ # These three are used to decorate methods in class definitions
295
+ line_magic = _method_magic_marker('line')
296
+ cell_magic = _method_magic_marker('cell')
297
+ line_cell_magic = _method_magic_marker('line_cell')
298
+
299
+ # These three decorate standalone functions and perform the decoration
300
+ # immediately. They can only run where get_ipython() works
301
+ register_line_magic = _function_magic_marker('line')
302
+ register_cell_magic = _function_magic_marker('cell')
303
+ register_line_cell_magic = _function_magic_marker('line_cell')
304
+
305
+ #-----------------------------------------------------------------------------
306
+ # Core Magic classes
307
+ #-----------------------------------------------------------------------------
308
+
309
+ class MagicsManager(Configurable):
310
+ """Object that handles all magic-related functionality for IPython.
311
+ """
312
+ # Non-configurable class attributes
313
+
314
+ # A two-level dict, first keyed by magic type, then by magic function, and
315
+ # holding the actual callable object as value. This is the dict used for
316
+ # magic function dispatch
317
+ magics = Dict()
318
+ lazy_magics = Dict(
319
+ help="""
320
+ Mapping from magic names to modules to load.
321
+
322
+ This can be used in IPython/IPykernel configuration to declare lazy magics
323
+ that will only be imported/registered on first use.
324
+
325
+ For example::
326
+
327
+ c.MagicsManager.lazy_magics = {
328
+ "my_magic": "slow.to.import",
329
+ "my_other_magic": "also.slow",
330
+ }
331
+
332
+ On first invocation of `%my_magic`, `%%my_magic`, `%%my_other_magic` or
333
+ `%%my_other_magic`, the corresponding module will be loaded as an ipython
334
+ extensions as if you had previously done `%load_ext ipython`.
335
+
336
+ Magics names should be without percent(s) as magics can be both cell
337
+ and line magics.
338
+
339
+ Lazy loading happen relatively late in execution process, and
340
+ complex extensions that manipulate Python/IPython internal state or global state
341
+ might not support lazy loading.
342
+ """
343
+ ).tag(
344
+ config=True,
345
+ )
346
+
347
+ # A registry of the original objects that we've been given holding magics.
348
+ registry = Dict()
349
+
350
+ shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
351
+
352
+ auto_magic = Bool(True, help=
353
+ "Automatically call line magics without requiring explicit % prefix"
354
+ ).tag(config=True)
355
+ @observe('auto_magic')
356
+ def _auto_magic_changed(self, change):
357
+ self.shell.automagic = change['new']
358
+
359
+ _auto_status = [
360
+ 'Automagic is OFF, % prefix IS needed for line magics.',
361
+ 'Automagic is ON, % prefix IS NOT needed for line magics.']
362
+
363
+ user_magics = Instance('IPython.core.magics.UserMagics', allow_none=True)
364
+
365
+ def __init__(self, shell=None, config=None, user_magics=None, **traits):
366
+
367
+ super(MagicsManager, self).__init__(shell=shell, config=config,
368
+ user_magics=user_magics, **traits)
369
+ self.magics = dict(line={}, cell={})
370
+ # Let's add the user_magics to the registry for uniformity, so *all*
371
+ # registered magic containers can be found there.
372
+ self.registry[user_magics.__class__.__name__] = user_magics
373
+
374
+ def auto_status(self):
375
+ """Return descriptive string with automagic status."""
376
+ return self._auto_status[self.auto_magic]
377
+
378
+ def lsmagic(self):
379
+ """Return a dict of currently available magic functions.
380
+
381
+ The return dict has the keys 'line' and 'cell', corresponding to the
382
+ two types of magics we support. Each value is a list of names.
383
+ """
384
+ return self.magics
385
+
386
+ def lsmagic_docs(self, brief=False, missing=''):
387
+ """Return dict of documentation of magic functions.
388
+
389
+ The return dict has the keys 'line' and 'cell', corresponding to the
390
+ two types of magics we support. Each value is a dict keyed by magic
391
+ name whose value is the function docstring. If a docstring is
392
+ unavailable, the value of `missing` is used instead.
393
+
394
+ If brief is True, only the first line of each docstring will be returned.
395
+ """
396
+ docs = {}
397
+ for m_type in self.magics:
398
+ m_docs = {}
399
+ for m_name, m_func in self.magics[m_type].items():
400
+ if m_func.__doc__:
401
+ if brief:
402
+ m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
403
+ else:
404
+ m_docs[m_name] = m_func.__doc__.rstrip()
405
+ else:
406
+ m_docs[m_name] = missing
407
+ docs[m_type] = m_docs
408
+ return docs
409
+
410
+ def register_lazy(self, name: str, fully_qualified_name: str):
411
+ """
412
+ Lazily register a magic via an extension.
413
+
414
+
415
+ Parameters
416
+ ----------
417
+ name : str
418
+ Name of the magic you wish to register.
419
+ fully_qualified_name :
420
+ Fully qualified name of the module/submodule that should be loaded
421
+ as an extensions when the magic is first called.
422
+ It is assumed that loading this extensions will register the given
423
+ magic.
424
+ """
425
+
426
+ self.lazy_magics[name] = fully_qualified_name
427
+
428
+ def register(self, *magic_objects):
429
+ """Register one or more instances of Magics.
430
+
431
+ Take one or more classes or instances of classes that subclass the main
432
+ `core.Magic` class, and register them with IPython to use the magic
433
+ functions they provide. The registration process will then ensure that
434
+ any methods that have decorated to provide line and/or cell magics will
435
+ be recognized with the `%x`/`%%x` syntax as a line/cell magic
436
+ respectively.
437
+
438
+ If classes are given, they will be instantiated with the default
439
+ constructor. If your classes need a custom constructor, you should
440
+ instanitate them first and pass the instance.
441
+
442
+ The provided arguments can be an arbitrary mix of classes and instances.
443
+
444
+ Parameters
445
+ ----------
446
+ *magic_objects : one or more classes or instances
447
+ """
448
+ # Start by validating them to ensure they have all had their magic
449
+ # methods registered at the instance level
450
+ for m in magic_objects:
451
+ if not m.registered:
452
+ raise ValueError("Class of magics %r was constructed without "
453
+ "the @register_magics class decorator")
454
+ if isinstance(m, type):
455
+ # If we're given an uninstantiated class
456
+ m = m(shell=self.shell)
457
+
458
+ # Now that we have an instance, we can register it and update the
459
+ # table of callables
460
+ self.registry[m.__class__.__name__] = m
461
+ for mtype in magic_kinds:
462
+ self.magics[mtype].update(m.magics[mtype])
463
+
464
+ def register_function(self, func, magic_kind='line', magic_name=None):
465
+ """Expose a standalone function as magic function for IPython.
466
+
467
+ This will create an IPython magic (line, cell or both) from a
468
+ standalone function. The functions should have the following
469
+ signatures:
470
+
471
+ * For line magics: `def f(line)`
472
+ * For cell magics: `def f(line, cell)`
473
+ * For a function that does both: `def f(line, cell=None)`
474
+
475
+ In the latter case, the function will be called with `cell==None` when
476
+ invoked as `%f`, and with cell as a string when invoked as `%%f`.
477
+
478
+ Parameters
479
+ ----------
480
+ func : callable
481
+ Function to be registered as a magic.
482
+ magic_kind : str
483
+ Kind of magic, one of 'line', 'cell' or 'line_cell'
484
+ magic_name : optional str
485
+ If given, the name the magic will have in the IPython namespace. By
486
+ default, the name of the function itself is used.
487
+ """
488
+
489
+ # Create the new method in the user_magics and register it in the
490
+ # global table
491
+ validate_type(magic_kind)
492
+ magic_name = func.__name__ if magic_name is None else magic_name
493
+ setattr(self.user_magics, magic_name, func)
494
+ record_magic(self.magics, magic_kind, magic_name, func)
495
+
496
+ def register_alias(self, alias_name, magic_name, magic_kind='line', magic_params=None):
497
+ """Register an alias to a magic function.
498
+
499
+ The alias is an instance of :class:`MagicAlias`, which holds the
500
+ name and kind of the magic it should call. Binding is done at
501
+ call time, so if the underlying magic function is changed the alias
502
+ will call the new function.
503
+
504
+ Parameters
505
+ ----------
506
+ alias_name : str
507
+ The name of the magic to be registered.
508
+ magic_name : str
509
+ The name of an existing magic.
510
+ magic_kind : str
511
+ Kind of magic, one of 'line' or 'cell'
512
+ """
513
+
514
+ # `validate_type` is too permissive, as it allows 'line_cell'
515
+ # which we do not handle.
516
+ if magic_kind not in magic_kinds:
517
+ raise ValueError('magic_kind must be one of %s, %s given' %
518
+ magic_kinds, magic_kind)
519
+
520
+ alias = MagicAlias(self.shell, magic_name, magic_kind, magic_params)
521
+ setattr(self.user_magics, alias_name, alias)
522
+ record_magic(self.magics, magic_kind, alias_name, alias)
523
+
524
+ # Key base class that provides the central functionality for magics.
525
+
526
+
527
+ class Magics(Configurable):
528
+ """Base class for implementing magic functions.
529
+
530
+ Shell functions which can be reached as %function_name. All magic
531
+ functions should accept a string, which they can parse for their own
532
+ needs. This can make some functions easier to type, eg `%cd ../`
533
+ vs. `%cd("../")`
534
+
535
+ Classes providing magic functions need to subclass this class, and they
536
+ MUST:
537
+
538
+ - Use the method decorators `@line_magic` and `@cell_magic` to decorate
539
+ individual methods as magic functions, AND
540
+
541
+ - Use the class decorator `@magics_class` to ensure that the magic
542
+ methods are properly registered at the instance level upon instance
543
+ initialization.
544
+
545
+ See :mod:`magic_functions` for examples of actual implementation classes.
546
+ """
547
+ # Dict holding all command-line options for each magic.
548
+ options_table = None
549
+ # Dict for the mapping of magic names to methods, set by class decorator
550
+ magics = None
551
+ # Flag to check that the class decorator was properly applied
552
+ registered = False
553
+ # Instance of IPython shell
554
+ shell = None
555
+
556
+ def __init__(self, shell=None, **kwargs):
557
+ if not(self.__class__.registered):
558
+ raise ValueError('Magics subclass without registration - '
559
+ 'did you forget to apply @magics_class?')
560
+ if shell is not None:
561
+ if hasattr(shell, 'configurables'):
562
+ shell.configurables.append(self)
563
+ if hasattr(shell, 'config'):
564
+ kwargs.setdefault('parent', shell)
565
+
566
+ self.shell = shell
567
+ self.options_table = {}
568
+ # The method decorators are run when the instance doesn't exist yet, so
569
+ # they can only record the names of the methods they are supposed to
570
+ # grab. Only now, that the instance exists, can we create the proper
571
+ # mapping to bound methods. So we read the info off the original names
572
+ # table and replace each method name by the actual bound method.
573
+ # But we mustn't clobber the *class* mapping, in case of multiple instances.
574
+ class_magics = self.magics
575
+ self.magics = {}
576
+ for mtype in magic_kinds:
577
+ tab = self.magics[mtype] = {}
578
+ cls_tab = class_magics[mtype]
579
+ for magic_name, meth_name in cls_tab.items():
580
+ if isinstance(meth_name, str):
581
+ # it's a method name, grab it
582
+ tab[magic_name] = getattr(self, meth_name)
583
+ else:
584
+ # it's the real thing
585
+ tab[magic_name] = meth_name
586
+ # Configurable **needs** to be initiated at the end or the config
587
+ # magics get screwed up.
588
+ super(Magics, self).__init__(**kwargs)
589
+
590
+ def arg_err(self,func):
591
+ """Print docstring if incorrect arguments were passed"""
592
+ print('Error in arguments:')
593
+ print(oinspect.getdoc(func))
594
+
595
+ def format_latex(self, strng):
596
+ """Format a string for latex inclusion."""
597
+
598
+ # Characters that need to be escaped for latex:
599
+ escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
600
+ # Magic command names as headers:
601
+ cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
602
+ re.MULTILINE)
603
+ # Magic commands
604
+ cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
605
+ re.MULTILINE)
606
+ # Paragraph continue
607
+ par_re = re.compile(r'\\$',re.MULTILINE)
608
+
609
+ # The "\n" symbol
610
+ newline_re = re.compile(r'\\n')
611
+
612
+ # Now build the string for output:
613
+ #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
614
+ strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
615
+ strng)
616
+ strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
617
+ strng = par_re.sub(r'\\\\',strng)
618
+ strng = escape_re.sub(r'\\\1',strng)
619
+ strng = newline_re.sub(r'\\textbackslash{}n',strng)
620
+ return strng
621
+
622
+ def parse_options(self, arg_str, opt_str, *long_opts, **kw):
623
+ """Parse options passed to an argument string.
624
+
625
+ The interface is similar to that of :func:`getopt.getopt`, but it
626
+ returns a :class:`~IPython.utils.struct.Struct` with the options as keys
627
+ and the stripped argument string still as a string.
628
+
629
+ arg_str is quoted as a true sys.argv vector by using shlex.split.
630
+ This allows us to easily expand variables, glob files, quote
631
+ arguments, etc.
632
+
633
+ Parameters
634
+ ----------
635
+ arg_str : str
636
+ The arguments to parse.
637
+ opt_str : str
638
+ The options specification.
639
+ mode : str, default 'string'
640
+ If given as 'list', the argument string is returned as a list (split
641
+ on whitespace) instead of a string.
642
+ list_all : bool, default False
643
+ Put all option values in lists. Normally only options
644
+ appearing more than once are put in a list.
645
+ posix : bool, default True
646
+ Whether to split the input line in POSIX mode or not, as per the
647
+ conventions outlined in the :mod:`shlex` module from the standard
648
+ library.
649
+ """
650
+
651
+ # inject default options at the beginning of the input line
652
+ caller = sys._getframe(1).f_code.co_name
653
+ arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
654
+
655
+ mode = kw.get('mode','string')
656
+ if mode not in ['string','list']:
657
+ raise ValueError('incorrect mode given: %s' % mode)
658
+ # Get options
659
+ list_all = kw.get('list_all',0)
660
+ posix = kw.get('posix', os.name == 'posix')
661
+ strict = kw.get('strict', True)
662
+
663
+ preserve_non_opts = kw.get("preserve_non_opts", False)
664
+ remainder_arg_str = arg_str
665
+
666
+ # Check if we have more than one argument to warrant extra processing:
667
+ odict = {} # Dictionary with options
668
+ args = arg_str.split()
669
+ if len(args) >= 1:
670
+ # If the list of inputs only has 0 or 1 thing in it, there's no
671
+ # need to look for options
672
+ argv = arg_split(arg_str, posix, strict)
673
+ # Do regular option processing
674
+ try:
675
+ opts,args = getopt(argv, opt_str, long_opts)
676
+ except GetoptError as e:
677
+ raise UsageError(
678
+ '%s ( allowed: "%s" %s)' % (e.msg, opt_str, " ".join(long_opts))
679
+ ) from e
680
+ for o, a in opts:
681
+ if mode == "string" and preserve_non_opts:
682
+ # remove option-parts from the original args-string and preserve remaining-part.
683
+ # This relies on the arg_split(...) and getopt(...)'s impl spec, that the parsed options are
684
+ # returned in the original order.
685
+ remainder_arg_str = remainder_arg_str.replace(o, "", 1).replace(
686
+ a, "", 1
687
+ )
688
+ if o.startswith("--"):
689
+ o = o[2:]
690
+ else:
691
+ o = o[1:]
692
+ try:
693
+ odict[o].append(a)
694
+ except AttributeError:
695
+ odict[o] = [odict[o],a]
696
+ except KeyError:
697
+ if list_all:
698
+ odict[o] = [a]
699
+ else:
700
+ odict[o] = a
701
+
702
+ # Prepare opts,args for return
703
+ opts = Struct(odict)
704
+ if mode == 'string':
705
+ if preserve_non_opts:
706
+ args = remainder_arg_str.lstrip()
707
+ else:
708
+ args = " ".join(args)
709
+
710
+ return opts,args
711
+
712
+ def default_option(self, fn, optstr):
713
+ """Make an entry in the options_table for fn, with value optstr"""
714
+
715
+ if fn not in self.lsmagic():
716
+ error("%s is not a magic function" % fn)
717
+ self.options_table[fn] = optstr
718
+
719
+
720
+ class MagicAlias(object):
721
+ """An alias to another magic function.
722
+
723
+ An alias is determined by its magic name and magic kind. Lookup
724
+ is done at call time, so if the underlying magic changes the alias
725
+ will call the new function.
726
+
727
+ Use the :meth:`MagicsManager.register_alias` method or the
728
+ `%alias_magic` magic function to create and register a new alias.
729
+ """
730
+ def __init__(self, shell, magic_name, magic_kind, magic_params=None):
731
+ self.shell = shell
732
+ self.magic_name = magic_name
733
+ self.magic_params = magic_params
734
+ self.magic_kind = magic_kind
735
+
736
+ self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
737
+ self.__doc__ = "Alias for `%s`." % self.pretty_target
738
+
739
+ self._in_call = False
740
+
741
+ def __call__(self, *args, **kwargs):
742
+ """Call the magic alias."""
743
+ fn = self.shell.find_magic(self.magic_name, self.magic_kind)
744
+ if fn is None:
745
+ raise UsageError("Magic `%s` not found." % self.pretty_target)
746
+
747
+ # Protect against infinite recursion.
748
+ if self._in_call:
749
+ raise UsageError("Infinite recursion detected; "
750
+ "magic aliases cannot call themselves.")
751
+ self._in_call = True
752
+ try:
753
+ if self.magic_params:
754
+ args_list = list(args)
755
+ args_list[0] = self.magic_params + " " + args[0]
756
+ args = tuple(args_list)
757
+ return fn(*args, **kwargs)
758
+ finally:
759
+ self._in_call = False
openalex_env_map/lib/python3.10/site-packages/IPython/core/magic_arguments.py ADDED
@@ -0,0 +1,310 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ''' A decorator-based method of constructing IPython magics with `argparse`
2
+ option handling.
3
+
4
+ New magic functions can be defined like so::
5
+
6
+ from IPython.core.magic_arguments import (argument, magic_arguments,
7
+ parse_argstring)
8
+
9
+ @magic_arguments()
10
+ @argument('-o', '--option', help='An optional argument.')
11
+ @argument('arg', type=int, help='An integer positional argument.')
12
+ def magic_cool(self, arg):
13
+ """ A really cool magic command.
14
+
15
+ """
16
+ args = parse_argstring(magic_cool, arg)
17
+ ...
18
+
19
+ The `@magic_arguments` decorator marks the function as having argparse arguments.
20
+ The `@argument` decorator adds an argument using the same syntax as argparse's
21
+ `add_argument()` method. More sophisticated uses may also require the
22
+ `@argument_group` or `@kwds` decorator to customize the formatting and the
23
+ parsing.
24
+
25
+ Help text for the magic is automatically generated from the docstring and the
26
+ arguments::
27
+
28
+ In[1]: %cool?
29
+ %cool [-o OPTION] arg
30
+
31
+ A really cool magic command.
32
+
33
+ positional arguments:
34
+ arg An integer positional argument.
35
+
36
+ optional arguments:
37
+ -o OPTION, --option OPTION
38
+ An optional argument.
39
+
40
+ Here is an elaborated example that uses default parameters in `argument` and calls the `args` in the cell magic::
41
+
42
+ from IPython.core.magic import register_cell_magic
43
+ from IPython.core.magic_arguments import (argument, magic_arguments,
44
+ parse_argstring)
45
+
46
+
47
+ @magic_arguments()
48
+ @argument(
49
+ "--option",
50
+ "-o",
51
+ help=("Add an option here"),
52
+ )
53
+ @argument(
54
+ "--style",
55
+ "-s",
56
+ default="foo",
57
+ help=("Add some style arguments"),
58
+ )
59
+ @register_cell_magic
60
+ def my_cell_magic(line, cell):
61
+ args = parse_argstring(my_cell_magic, line)
62
+ print(f"{args.option=}")
63
+ print(f"{args.style=}")
64
+ print(f"{cell=}")
65
+
66
+ In a jupyter notebook, this cell magic can be executed like this::
67
+
68
+ %%my_cell_magic -o Hello
69
+ print("bar")
70
+ i = 42
71
+
72
+ Inheritance diagram:
73
+
74
+ .. inheritance-diagram:: IPython.core.magic_arguments
75
+ :parts: 3
76
+
77
+ '''
78
+ #-----------------------------------------------------------------------------
79
+ # Copyright (C) 2010-2011, IPython Development Team.
80
+ #
81
+ # Distributed under the terms of the Modified BSD License.
82
+ #
83
+ # The full license is in the file COPYING.txt, distributed with this software.
84
+ #-----------------------------------------------------------------------------
85
+ import argparse
86
+ import re
87
+
88
+ # Our own imports
89
+ from IPython.core.error import UsageError
90
+ from IPython.utils.decorators import undoc
91
+ from IPython.utils.process import arg_split
92
+ from IPython.utils.text import dedent
93
+
94
+ NAME_RE = re.compile(r"[a-zA-Z][a-zA-Z0-9_-]*$")
95
+
96
+ @undoc
97
+ class MagicHelpFormatter(argparse.RawDescriptionHelpFormatter):
98
+ """A HelpFormatter with a couple of changes to meet our needs.
99
+ """
100
+ # Modified to dedent text.
101
+ def _fill_text(self, text, width, indent):
102
+ return argparse.RawDescriptionHelpFormatter._fill_text(self, dedent(text), width, indent)
103
+
104
+ # Modified to wrap argument placeholders in <> where necessary.
105
+ def _format_action_invocation(self, action):
106
+ if not action.option_strings:
107
+ metavar, = self._metavar_formatter(action, action.dest)(1)
108
+ return metavar
109
+
110
+ else:
111
+ parts = []
112
+
113
+ # if the Optional doesn't take a value, format is:
114
+ # -s, --long
115
+ if action.nargs == 0:
116
+ parts.extend(action.option_strings)
117
+
118
+ # if the Optional takes a value, format is:
119
+ # -s ARGS, --long ARGS
120
+ else:
121
+ default = action.dest.upper()
122
+ args_string = self._format_args(action, default)
123
+ # IPYTHON MODIFICATION: If args_string is not a plain name, wrap
124
+ # it in <> so it's valid RST.
125
+ if not NAME_RE.match(args_string):
126
+ args_string = "<%s>" % args_string
127
+ for option_string in action.option_strings:
128
+ parts.append('%s %s' % (option_string, args_string))
129
+
130
+ return ', '.join(parts)
131
+
132
+ # Override the default prefix ('usage') to our % magic escape,
133
+ # in a code block.
134
+ def add_usage(self, usage, actions, groups, prefix="::\n\n %"):
135
+ super(MagicHelpFormatter, self).add_usage(usage, actions, groups, prefix)
136
+
137
+ class MagicArgumentParser(argparse.ArgumentParser):
138
+ """ An ArgumentParser tweaked for use by IPython magics.
139
+ """
140
+ def __init__(self,
141
+ prog=None,
142
+ usage=None,
143
+ description=None,
144
+ epilog=None,
145
+ parents=None,
146
+ formatter_class=MagicHelpFormatter,
147
+ prefix_chars='-',
148
+ argument_default=None,
149
+ conflict_handler='error',
150
+ add_help=False):
151
+ if parents is None:
152
+ parents = []
153
+ super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
154
+ description=description, epilog=epilog,
155
+ parents=parents, formatter_class=formatter_class,
156
+ prefix_chars=prefix_chars, argument_default=argument_default,
157
+ conflict_handler=conflict_handler, add_help=add_help)
158
+
159
+ def error(self, message):
160
+ """ Raise a catchable error instead of exiting.
161
+ """
162
+ raise UsageError(message)
163
+
164
+ def parse_argstring(self, argstring):
165
+ """ Split a string into an argument list and parse that argument list.
166
+ """
167
+ argv = arg_split(argstring)
168
+ return self.parse_args(argv)
169
+
170
+
171
+ def construct_parser(magic_func):
172
+ """ Construct an argument parser using the function decorations.
173
+ """
174
+ kwds = getattr(magic_func, 'argcmd_kwds', {})
175
+ if 'description' not in kwds:
176
+ kwds['description'] = getattr(magic_func, '__doc__', None)
177
+ arg_name = real_name(magic_func)
178
+ parser = MagicArgumentParser(arg_name, **kwds)
179
+ # Reverse the list of decorators in order to apply them in the
180
+ # order in which they appear in the source.
181
+ group = None
182
+ for deco in magic_func.decorators[::-1]:
183
+ result = deco.add_to_parser(parser, group)
184
+ if result is not None:
185
+ group = result
186
+
187
+ # Replace the magic function's docstring with the full help text.
188
+ magic_func.__doc__ = parser.format_help()
189
+
190
+ return parser
191
+
192
+
193
+ def parse_argstring(magic_func, argstring):
194
+ """ Parse the string of arguments for the given magic function.
195
+ """
196
+ return magic_func.parser.parse_argstring(argstring)
197
+
198
+
199
+ def real_name(magic_func):
200
+ """ Find the real name of the magic.
201
+ """
202
+ magic_name = magic_func.__name__
203
+ if magic_name.startswith('magic_'):
204
+ magic_name = magic_name[len('magic_'):]
205
+ return getattr(magic_func, 'argcmd_name', magic_name)
206
+
207
+
208
+ class ArgDecorator(object):
209
+ """ Base class for decorators to add ArgumentParser information to a method.
210
+ """
211
+
212
+ def __call__(self, func):
213
+ if not getattr(func, 'has_arguments', False):
214
+ func.has_arguments = True
215
+ func.decorators = []
216
+ func.decorators.append(self)
217
+ return func
218
+
219
+ def add_to_parser(self, parser, group):
220
+ """ Add this object's information to the parser, if necessary.
221
+ """
222
+ pass
223
+
224
+
225
+ class magic_arguments(ArgDecorator):
226
+ """ Mark the magic as having argparse arguments and possibly adjust the
227
+ name.
228
+ """
229
+
230
+ def __init__(self, name=None):
231
+ self.name = name
232
+
233
+ def __call__(self, func):
234
+ if not getattr(func, 'has_arguments', False):
235
+ func.has_arguments = True
236
+ func.decorators = []
237
+ if self.name is not None:
238
+ func.argcmd_name = self.name
239
+ # This should be the first decorator in the list of decorators, thus the
240
+ # last to execute. Build the parser.
241
+ func.parser = construct_parser(func)
242
+ return func
243
+
244
+
245
+ class ArgMethodWrapper(ArgDecorator):
246
+
247
+ """
248
+ Base class to define a wrapper for ArgumentParser method.
249
+
250
+ Child class must define either `_method_name` or `add_to_parser`.
251
+
252
+ """
253
+
254
+ _method_name: str
255
+
256
+ def __init__(self, *args, **kwds):
257
+ self.args = args
258
+ self.kwds = kwds
259
+
260
+ def add_to_parser(self, parser, group):
261
+ """ Add this object's information to the parser.
262
+ """
263
+ if group is not None:
264
+ parser = group
265
+ getattr(parser, self._method_name)(*self.args, **self.kwds)
266
+ return None
267
+
268
+
269
+ class argument(ArgMethodWrapper):
270
+ """ Store arguments and keywords to pass to add_argument().
271
+
272
+ Instances also serve to decorate command methods.
273
+ """
274
+ _method_name = 'add_argument'
275
+
276
+
277
+ class defaults(ArgMethodWrapper):
278
+ """ Store arguments and keywords to pass to set_defaults().
279
+
280
+ Instances also serve to decorate command methods.
281
+ """
282
+ _method_name = 'set_defaults'
283
+
284
+
285
+ class argument_group(ArgMethodWrapper):
286
+ """ Store arguments and keywords to pass to add_argument_group().
287
+
288
+ Instances also serve to decorate command methods.
289
+ """
290
+
291
+ def add_to_parser(self, parser, group):
292
+ """ Add this object's information to the parser.
293
+ """
294
+ return parser.add_argument_group(*self.args, **self.kwds)
295
+
296
+
297
+ class kwds(ArgDecorator):
298
+ """ Provide other keywords to the sub-parser constructor.
299
+ """
300
+ def __init__(self, **kwds):
301
+ self.kwds = kwds
302
+
303
+ def __call__(self, func):
304
+ func = super(kwds, self).__call__(func)
305
+ func.argcmd_kwds = self.kwds
306
+ return func
307
+
308
+
309
+ __all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
310
+ 'parse_argstring']
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/__init__.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of all the magic functions built into IPython.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ from ..magic import Magics, magics_class
16
+ from .auto import AutoMagics
17
+ from .basic import BasicMagics, AsyncMagics
18
+ from .code import CodeMagics, MacroToEdit
19
+ from .config import ConfigMagics
20
+ from .display import DisplayMagics
21
+ from .execution import ExecutionMagics
22
+ from .extension import ExtensionMagics
23
+ from .history import HistoryMagics
24
+ from .logging import LoggingMagics
25
+ from .namespace import NamespaceMagics
26
+ from .osm import OSMagics
27
+ from .packaging import PackagingMagics
28
+ from .pylab import PylabMagics
29
+ from .script import ScriptMagics
30
+
31
+ #-----------------------------------------------------------------------------
32
+ # Magic implementation classes
33
+ #-----------------------------------------------------------------------------
34
+
35
+ @magics_class
36
+ class UserMagics(Magics):
37
+ """Placeholder for user-defined magics to be added at runtime.
38
+
39
+ All magics are eventually merged into a single namespace at runtime, but we
40
+ use this class to isolate the magics defined dynamically by the user into
41
+ their own class.
42
+ """
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/ast_mod.py ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module contains utility function and classes to inject simple ast
3
+ transformations based on code strings into IPython. While it is already possible
4
+ with ast-transformers it is not easy to directly manipulate ast.
5
+
6
+
7
+ IPython has pre-code and post-code hooks, but are ran from within the IPython
8
+ machinery so may be inappropriate, for example for performance measurement.
9
+
10
+ This module give you tools to simplify this, and expose 2 classes:
11
+
12
+ - `ReplaceCodeTransformer` which is a simple ast transformer based on code
13
+ template,
14
+
15
+ and for advance case:
16
+
17
+ - `Mangler` which is a simple ast transformer that mangle names in the ast.
18
+
19
+
20
+ Example, let's try to make a simple version of the ``timeit`` magic, that run a
21
+ code snippet 10 times and print the average time taken.
22
+
23
+ Basically we want to run :
24
+
25
+ .. code-block:: python
26
+
27
+ from time import perf_counter
28
+ now = perf_counter()
29
+ for i in range(10):
30
+ __code__ # our code
31
+ print(f"Time taken: {(perf_counter() - now)/10}")
32
+ __ret__ # the result of the last statement
33
+
34
+ Where ``__code__`` is the code snippet we want to run, and ``__ret__`` is the
35
+ result, so that if we for example run `dataframe.head()` IPython still display
36
+ the head of dataframe instead of nothing.
37
+
38
+ Here is a complete example of a file `timit2.py` that define such a magic:
39
+
40
+ .. code-block:: python
41
+
42
+ from IPython.core.magic import (
43
+ Magics,
44
+ magics_class,
45
+ line_cell_magic,
46
+ )
47
+ from IPython.core.magics.ast_mod import ReplaceCodeTransformer
48
+ from textwrap import dedent
49
+ import ast
50
+
51
+ template = template = dedent('''
52
+ from time import perf_counter
53
+ now = perf_counter()
54
+ for i in range(10):
55
+ __code__
56
+ print(f"Time taken: {(perf_counter() - now)/10}")
57
+ __ret__
58
+ '''
59
+ )
60
+
61
+
62
+ @magics_class
63
+ class AstM(Magics):
64
+ @line_cell_magic
65
+ def t2(self, line, cell):
66
+ transformer = ReplaceCodeTransformer.from_string(template)
67
+ transformer.debug = True
68
+ transformer.mangler.debug = True
69
+ new_code = transformer.visit(ast.parse(cell))
70
+ return exec(compile(new_code, "<ast>", "exec"))
71
+
72
+
73
+ def load_ipython_extension(ip):
74
+ ip.register_magics(AstM)
75
+
76
+
77
+
78
+ .. code-block:: python
79
+
80
+ In [1]: %load_ext timit2
81
+
82
+ In [2]: %%t2
83
+ ...: import time
84
+ ...: time.sleep(0.05)
85
+ ...:
86
+ ...:
87
+ Time taken: 0.05435649999999441
88
+
89
+
90
+ If you wish to ran all the code enter in IPython in an ast transformer, you can
91
+ do so as well:
92
+
93
+ .. code-block:: python
94
+
95
+ In [1]: from IPython.core.magics.ast_mod import ReplaceCodeTransformer
96
+ ...:
97
+ ...: template = '''
98
+ ...: from time import perf_counter
99
+ ...: now = perf_counter()
100
+ ...: __code__
101
+ ...: print(f"Code ran in {perf_counter()-now}")
102
+ ...: __ret__'''
103
+ ...:
104
+ ...: get_ipython().ast_transformers.append(ReplaceCodeTransformer.from_string(template))
105
+
106
+ In [2]: 1+1
107
+ Code ran in 3.40410006174352e-05
108
+ Out[2]: 2
109
+
110
+
111
+
112
+ Hygiene and Mangling
113
+ --------------------
114
+
115
+ The ast transformer above is not hygienic, it may not work if the user code use
116
+ the same variable names as the ones used in the template. For example.
117
+
118
+ To help with this by default the `ReplaceCodeTransformer` will mangle all names
119
+ staring with 3 underscores. This is a simple heuristic that should work in most
120
+ case, but can be cumbersome in some case. We provide a `Mangler` class that can
121
+ be overridden to change the mangling heuristic, or simply use the `mangle_all`
122
+ utility function. It will _try_ to mangle all names (except `__ret__` and
123
+ `__code__`), but this include builtins (``print``, ``range``, ``type``) and
124
+ replace those by invalid identifiers py prepending ``mangle-``:
125
+ ``mangle-print``, ``mangle-range``, ``mangle-type`` etc. This is not a problem
126
+ as currently Python AST support invalid identifiers, but it may not be the case
127
+ in the future.
128
+
129
+ You can set `ReplaceCodeTransformer.debug=True` and
130
+ `ReplaceCodeTransformer.mangler.debug=True` to see the code after mangling and
131
+ transforming:
132
+
133
+ .. code-block:: python
134
+
135
+
136
+ In [1]: from IPython.core.magics.ast_mod import ReplaceCodeTransformer, mangle_all
137
+ ...:
138
+ ...: template = '''
139
+ ...: from builtins import type, print
140
+ ...: from time import perf_counter
141
+ ...: now = perf_counter()
142
+ ...: __code__
143
+ ...: print(f"Code ran in {perf_counter()-now}")
144
+ ...: __ret__'''
145
+ ...:
146
+ ...: transformer = ReplaceCodeTransformer.from_string(template, mangling_predicate=mangle_all)
147
+
148
+
149
+ In [2]: transformer.debug = True
150
+ ...: transformer.mangler.debug = True
151
+ ...: get_ipython().ast_transformers.append(transformer)
152
+
153
+ In [3]: 1+1
154
+ Mangling Alias mangle-type
155
+ Mangling Alias mangle-print
156
+ Mangling Alias mangle-perf_counter
157
+ Mangling now
158
+ Mangling perf_counter
159
+ Not mangling __code__
160
+ Mangling print
161
+ Mangling perf_counter
162
+ Mangling now
163
+ Not mangling __ret__
164
+ ---- Transformed code ----
165
+ from builtins import type as mangle-type, print as mangle-print
166
+ from time import perf_counter as mangle-perf_counter
167
+ mangle-now = mangle-perf_counter()
168
+ ret-tmp = 1 + 1
169
+ mangle-print(f'Code ran in {mangle-perf_counter() - mangle-now}')
170
+ ret-tmp
171
+ ---- ---------------- ----
172
+ Code ran in 0.00013654199938173406
173
+ Out[3]: 2
174
+
175
+
176
+ """
177
+
178
+ __skip_doctest__ = True
179
+
180
+
181
+ from ast import (
182
+ NodeTransformer,
183
+ Store,
184
+ Load,
185
+ Name,
186
+ Expr,
187
+ Assign,
188
+ Module,
189
+ Import,
190
+ ImportFrom,
191
+ )
192
+ import ast
193
+ import copy
194
+
195
+ from typing import Dict, Optional, Union
196
+
197
+
198
+ mangle_all = lambda name: False if name in ("__ret__", "__code__") else True
199
+
200
+
201
+ class Mangler(NodeTransformer):
202
+ """
203
+ Mangle given names in and ast tree to make sure they do not conflict with
204
+ user code.
205
+ """
206
+
207
+ enabled: bool = True
208
+ debug: bool = False
209
+
210
+ def log(self, *args, **kwargs):
211
+ if self.debug:
212
+ print(*args, **kwargs)
213
+
214
+ def __init__(self, predicate=None):
215
+ if predicate is None:
216
+ predicate = lambda name: name.startswith("___")
217
+ self.predicate = predicate
218
+
219
+ def visit_Name(self, node):
220
+ if self.predicate(node.id):
221
+ self.log("Mangling", node.id)
222
+ # Once in the ast we do not need
223
+ # names to be valid identifiers.
224
+ node.id = "mangle-" + node.id
225
+ else:
226
+ self.log("Not mangling", node.id)
227
+ return node
228
+
229
+ def visit_FunctionDef(self, node):
230
+ if self.predicate(node.name):
231
+ self.log("Mangling", node.name)
232
+ node.name = "mangle-" + node.name
233
+ else:
234
+ self.log("Not mangling", node.name)
235
+
236
+ for arg in node.args.args:
237
+ if self.predicate(arg.arg):
238
+ self.log("Mangling function arg", arg.arg)
239
+ arg.arg = "mangle-" + arg.arg
240
+ else:
241
+ self.log("Not mangling function arg", arg.arg)
242
+ return self.generic_visit(node)
243
+
244
+ def visit_ImportFrom(self, node: ImportFrom):
245
+ return self._visit_Import_and_ImportFrom(node)
246
+
247
+ def visit_Import(self, node: Import):
248
+ return self._visit_Import_and_ImportFrom(node)
249
+
250
+ def _visit_Import_and_ImportFrom(self, node: Union[Import, ImportFrom]):
251
+ for alias in node.names:
252
+ asname = alias.name if alias.asname is None else alias.asname
253
+ if self.predicate(asname):
254
+ new_name: str = "mangle-" + asname
255
+ self.log("Mangling Alias", new_name)
256
+ alias.asname = new_name
257
+ else:
258
+ self.log("Not mangling Alias", alias.asname)
259
+ return node
260
+
261
+
262
+ class ReplaceCodeTransformer(NodeTransformer):
263
+ enabled: bool = True
264
+ debug: bool = False
265
+ mangler: Mangler
266
+
267
+ def __init__(
268
+ self, template: Module, mapping: Optional[Dict] = None, mangling_predicate=None
269
+ ):
270
+ assert isinstance(mapping, (dict, type(None)))
271
+ assert isinstance(mangling_predicate, (type(None), type(lambda: None)))
272
+ assert isinstance(template, ast.Module)
273
+ self.template = template
274
+ self.mangler = Mangler(predicate=mangling_predicate)
275
+ if mapping is None:
276
+ mapping = {}
277
+ self.mapping = mapping
278
+
279
+ @classmethod
280
+ def from_string(
281
+ cls, template: str, mapping: Optional[Dict] = None, mangling_predicate=None
282
+ ):
283
+ return cls(
284
+ ast.parse(template), mapping=mapping, mangling_predicate=mangling_predicate
285
+ )
286
+
287
+ def visit_Module(self, code):
288
+ if not self.enabled:
289
+ return code
290
+ # if not isinstance(code, ast.Module):
291
+ # recursively called...
292
+ # return generic_visit(self, code)
293
+ last = code.body[-1]
294
+ if isinstance(last, Expr):
295
+ code.body.pop()
296
+ code.body.append(Assign([Name("ret-tmp", ctx=Store())], value=last.value))
297
+ ast.fix_missing_locations(code)
298
+ ret = Expr(value=Name("ret-tmp", ctx=Load()))
299
+ ret = ast.fix_missing_locations(ret)
300
+ self.mapping["__ret__"] = ret
301
+ else:
302
+ self.mapping["__ret__"] = ast.parse("None").body[0]
303
+ self.mapping["__code__"] = code.body
304
+ tpl = ast.fix_missing_locations(self.template)
305
+
306
+ tx = copy.deepcopy(tpl)
307
+ tx = self.mangler.visit(tx)
308
+ node = self.generic_visit(tx)
309
+ node_2 = ast.fix_missing_locations(node)
310
+ if self.debug:
311
+ print("---- Transformed code ----")
312
+ print(ast.unparse(node_2))
313
+ print("---- ---------------- ----")
314
+ return node_2
315
+
316
+ # this does not work as the name might be in a list and one might want to extend the list.
317
+ # def visit_Name(self, name):
318
+ # if name.id in self.mapping and name.id == "__ret__":
319
+ # print(name, "in mapping")
320
+ # if isinstance(name.ctx, ast.Store):
321
+ # return Name("tmp", ctx=Store())
322
+ # else:
323
+ # return copy.deepcopy(self.mapping[name.id])
324
+ # return name
325
+
326
+ def visit_Expr(self, expr):
327
+ if isinstance(expr.value, Name) and expr.value.id in self.mapping:
328
+ if self.mapping[expr.value.id] is not None:
329
+ return copy.deepcopy(self.mapping[expr.value.id])
330
+ return self.generic_visit(expr)
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/auto.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of magic functions that control various automatic behaviors.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ # Our own packages
16
+ from IPython.core.magic import Bunch, Magics, magics_class, line_magic
17
+ from IPython.testing.skipdoctest import skip_doctest
18
+ from logging import error
19
+
20
+ #-----------------------------------------------------------------------------
21
+ # Magic implementation classes
22
+ #-----------------------------------------------------------------------------
23
+
24
+ @magics_class
25
+ class AutoMagics(Magics):
26
+ """Magics that control various autoX behaviors."""
27
+
28
+ def __init__(self, shell):
29
+ super(AutoMagics, self).__init__(shell)
30
+ # namespace for holding state we may need
31
+ self._magic_state = Bunch()
32
+
33
+ @line_magic
34
+ def automagic(self, parameter_s=''):
35
+ """Make magic functions callable without having to type the initial %.
36
+
37
+ Without arguments toggles on/off (when off, you must call it as
38
+ %automagic, of course). With arguments it sets the value, and you can
39
+ use any of (case insensitive):
40
+
41
+ - on, 1, True: to activate
42
+
43
+ - off, 0, False: to deactivate.
44
+
45
+ Note that magic functions have lowest priority, so if there's a
46
+ variable whose name collides with that of a magic fn, automagic won't
47
+ work for that function (you get the variable instead). However, if you
48
+ delete the variable (del var), the previously shadowed magic function
49
+ becomes visible to automagic again."""
50
+
51
+ arg = parameter_s.lower()
52
+ mman = self.shell.magics_manager
53
+ if arg in ('on', '1', 'true'):
54
+ val = True
55
+ elif arg in ('off', '0', 'false'):
56
+ val = False
57
+ else:
58
+ val = not mman.auto_magic
59
+ mman.auto_magic = val
60
+ print('\n' + self.shell.magics_manager.auto_status())
61
+
62
+ @skip_doctest
63
+ @line_magic
64
+ def autocall(self, parameter_s=''):
65
+ """Make functions callable without having to type parentheses.
66
+
67
+ Usage:
68
+
69
+ %autocall [mode]
70
+
71
+ The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
72
+ value is toggled on and off (remembering the previous state).
73
+
74
+ In more detail, these values mean:
75
+
76
+ 0 -> fully disabled
77
+
78
+ 1 -> active, but do not apply if there are no arguments on the line.
79
+
80
+ In this mode, you get::
81
+
82
+ In [1]: callable
83
+ Out[1]: <built-in function callable>
84
+
85
+ In [2]: callable 'hello'
86
+ ------> callable('hello')
87
+ Out[2]: False
88
+
89
+ 2 -> Active always. Even if no arguments are present, the callable
90
+ object is called::
91
+
92
+ In [2]: float
93
+ ------> float()
94
+ Out[2]: 0.0
95
+
96
+ Note that even with autocall off, you can still use '/' at the start of
97
+ a line to treat the first argument on the command line as a function
98
+ and add parentheses to it::
99
+
100
+ In [8]: /str 43
101
+ ------> str(43)
102
+ Out[8]: '43'
103
+
104
+ # all-random (note for auto-testing)
105
+ """
106
+
107
+ valid_modes = {
108
+ 0: "Off",
109
+ 1: "Smart",
110
+ 2: "Full",
111
+ }
112
+
113
+ def errorMessage() -> str:
114
+ error = "Valid modes: "
115
+ for k, v in valid_modes.items():
116
+ error += str(k) + "->" + v + ", "
117
+ error = error[:-2] # remove tailing `, ` after last element
118
+ return error
119
+
120
+ if parameter_s:
121
+ if not parameter_s in map(str, valid_modes.keys()):
122
+ error(errorMessage())
123
+ return
124
+ arg = int(parameter_s)
125
+ else:
126
+ arg = 'toggle'
127
+
128
+ if not arg in (*list(valid_modes.keys()), "toggle"):
129
+ error(errorMessage())
130
+ return
131
+
132
+ if arg in (valid_modes.keys()):
133
+ self.shell.autocall = arg
134
+ else: # toggle
135
+ if self.shell.autocall:
136
+ self._magic_state.autocall_save = self.shell.autocall
137
+ self.shell.autocall = 0
138
+ else:
139
+ try:
140
+ self.shell.autocall = self._magic_state.autocall_save
141
+ except AttributeError:
142
+ self.shell.autocall = self._magic_state.autocall_save = 1
143
+
144
+ print("Automatic calling is:", list(valid_modes.values())[self.shell.autocall])
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/basic.py ADDED
@@ -0,0 +1,666 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of basic magic functions."""
2
+
3
+
4
+ from logging import error
5
+ import io
6
+ import os
7
+ from pprint import pformat
8
+ import sys
9
+ from warnings import warn
10
+
11
+ from traitlets.utils.importstring import import_item
12
+ from IPython.core import magic_arguments, page
13
+ from IPython.core.error import UsageError
14
+ from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
15
+ from IPython.utils.text import format_screen, dedent, indent
16
+ from IPython.testing.skipdoctest import skip_doctest
17
+ from IPython.utils.ipstruct import Struct
18
+
19
+
20
+ class MagicsDisplay(object):
21
+ def __init__(self, magics_manager, ignore=None):
22
+ self.ignore = ignore if ignore else []
23
+ self.magics_manager = magics_manager
24
+
25
+ def _lsmagic(self):
26
+ """The main implementation of the %lsmagic"""
27
+ mesc = magic_escapes['line']
28
+ cesc = magic_escapes['cell']
29
+ mman = self.magics_manager
30
+ magics = mman.lsmagic()
31
+ out = ['Available line magics:',
32
+ mesc + (' '+mesc).join(sorted([m for m,v in magics['line'].items() if (v not in self.ignore)])),
33
+ '',
34
+ 'Available cell magics:',
35
+ cesc + (' '+cesc).join(sorted([m for m,v in magics['cell'].items() if (v not in self.ignore)])),
36
+ '',
37
+ mman.auto_status()]
38
+ return '\n'.join(out)
39
+
40
+ def _repr_pretty_(self, p, cycle):
41
+ p.text(self._lsmagic())
42
+
43
+ def __repr__(self):
44
+ return self.__str__()
45
+
46
+ def __str__(self):
47
+ return self._lsmagic()
48
+
49
+ def _jsonable(self):
50
+ """turn magics dict into jsonable dict of the same structure
51
+
52
+ replaces object instances with their class names as strings
53
+ """
54
+ magic_dict = {}
55
+ mman = self.magics_manager
56
+ magics = mman.lsmagic()
57
+ for key, subdict in magics.items():
58
+ d = {}
59
+ magic_dict[key] = d
60
+ for name, obj in subdict.items():
61
+ try:
62
+ classname = obj.__self__.__class__.__name__
63
+ except AttributeError:
64
+ classname = 'Other'
65
+
66
+ d[name] = classname
67
+ return magic_dict
68
+
69
+ def _repr_json_(self):
70
+ return self._jsonable()
71
+
72
+
73
+ @magics_class
74
+ class BasicMagics(Magics):
75
+ """Magics that provide central IPython functionality.
76
+
77
+ These are various magics that don't fit into specific categories but that
78
+ are all part of the base 'IPython experience'."""
79
+
80
+ @skip_doctest
81
+ @magic_arguments.magic_arguments()
82
+ @magic_arguments.argument(
83
+ '-l', '--line', action='store_true',
84
+ help="""Create a line magic alias."""
85
+ )
86
+ @magic_arguments.argument(
87
+ '-c', '--cell', action='store_true',
88
+ help="""Create a cell magic alias."""
89
+ )
90
+ @magic_arguments.argument(
91
+ 'name',
92
+ help="""Name of the magic to be created."""
93
+ )
94
+ @magic_arguments.argument(
95
+ 'target',
96
+ help="""Name of the existing line or cell magic."""
97
+ )
98
+ @magic_arguments.argument(
99
+ '-p', '--params', default=None,
100
+ help="""Parameters passed to the magic function."""
101
+ )
102
+ @line_magic
103
+ def alias_magic(self, line=''):
104
+ """Create an alias for an existing line or cell magic.
105
+
106
+ Examples
107
+ --------
108
+ ::
109
+
110
+ In [1]: %alias_magic t timeit
111
+ Created `%t` as an alias for `%timeit`.
112
+ Created `%%t` as an alias for `%%timeit`.
113
+
114
+ In [2]: %t -n1 pass
115
+ 107 ns ± 43.6 ns per loop (mean ± std. dev. of 7 runs, 1 loop each)
116
+
117
+ In [3]: %%t -n1
118
+ ...: pass
119
+ ...:
120
+ 107 ns ± 58.3 ns per loop (mean ± std. dev. of 7 runs, 1 loop each)
121
+
122
+ In [4]: %alias_magic --cell whereami pwd
123
+ UsageError: Cell magic function `%%pwd` not found.
124
+ In [5]: %alias_magic --line whereami pwd
125
+ Created `%whereami` as an alias for `%pwd`.
126
+
127
+ In [6]: %whereami
128
+ Out[6]: '/home/testuser'
129
+
130
+ In [7]: %alias_magic h history -p "-l 30" --line
131
+ Created `%h` as an alias for `%history -l 30`.
132
+ """
133
+
134
+ args = magic_arguments.parse_argstring(self.alias_magic, line)
135
+ shell = self.shell
136
+ mman = self.shell.magics_manager
137
+ escs = ''.join(magic_escapes.values())
138
+
139
+ target = args.target.lstrip(escs)
140
+ name = args.name.lstrip(escs)
141
+
142
+ params = args.params
143
+ if (params and
144
+ ((params.startswith('"') and params.endswith('"'))
145
+ or (params.startswith("'") and params.endswith("'")))):
146
+ params = params[1:-1]
147
+
148
+ # Find the requested magics.
149
+ m_line = shell.find_magic(target, 'line')
150
+ m_cell = shell.find_magic(target, 'cell')
151
+ if args.line and m_line is None:
152
+ raise UsageError('Line magic function `%s%s` not found.' %
153
+ (magic_escapes['line'], target))
154
+ if args.cell and m_cell is None:
155
+ raise UsageError('Cell magic function `%s%s` not found.' %
156
+ (magic_escapes['cell'], target))
157
+
158
+ # If --line and --cell are not specified, default to the ones
159
+ # that are available.
160
+ if not args.line and not args.cell:
161
+ if not m_line and not m_cell:
162
+ raise UsageError(
163
+ 'No line or cell magic with name `%s` found.' % target
164
+ )
165
+ args.line = bool(m_line)
166
+ args.cell = bool(m_cell)
167
+
168
+ params_str = "" if params is None else " " + params
169
+
170
+ if args.line:
171
+ mman.register_alias(name, target, 'line', params)
172
+ print('Created `%s%s` as an alias for `%s%s%s`.' % (
173
+ magic_escapes['line'], name,
174
+ magic_escapes['line'], target, params_str))
175
+
176
+ if args.cell:
177
+ mman.register_alias(name, target, 'cell', params)
178
+ print('Created `%s%s` as an alias for `%s%s%s`.' % (
179
+ magic_escapes['cell'], name,
180
+ magic_escapes['cell'], target, params_str))
181
+
182
+ @line_magic
183
+ def lsmagic(self, parameter_s=''):
184
+ """List currently available magic functions."""
185
+ return MagicsDisplay(self.shell.magics_manager, ignore=[])
186
+
187
+ def _magic_docs(self, brief=False, rest=False):
188
+ """Return docstrings from magic functions."""
189
+ mman = self.shell.magics_manager
190
+ docs = mman.lsmagic_docs(brief, missing='No documentation')
191
+
192
+ if rest:
193
+ format_string = '**%s%s**::\n\n%s\n\n'
194
+ else:
195
+ format_string = '%s%s:\n%s\n'
196
+
197
+ return ''.join(
198
+ [format_string % (magic_escapes['line'], fname,
199
+ indent(dedent(fndoc)))
200
+ for fname, fndoc in sorted(docs['line'].items())]
201
+ +
202
+ [format_string % (magic_escapes['cell'], fname,
203
+ indent(dedent(fndoc)))
204
+ for fname, fndoc in sorted(docs['cell'].items())]
205
+ )
206
+
207
+ @line_magic
208
+ def magic(self, parameter_s=''):
209
+ """Print information about the magic function system.
210
+
211
+ Supported formats: -latex, -brief, -rest
212
+ """
213
+
214
+ mode = ''
215
+ try:
216
+ mode = parameter_s.split()[0][1:]
217
+ except IndexError:
218
+ pass
219
+
220
+ brief = (mode == 'brief')
221
+ rest = (mode == 'rest')
222
+ magic_docs = self._magic_docs(brief, rest)
223
+
224
+ if mode == 'latex':
225
+ print(self.format_latex(magic_docs))
226
+ return
227
+ else:
228
+ magic_docs = format_screen(magic_docs)
229
+
230
+ out = ["""
231
+ IPython's 'magic' functions
232
+ ===========================
233
+
234
+ The magic function system provides a series of functions which allow you to
235
+ control the behavior of IPython itself, plus a lot of system-type
236
+ features. There are two kinds of magics, line-oriented and cell-oriented.
237
+
238
+ Line magics are prefixed with the % character and work much like OS
239
+ command-line calls: they get as an argument the rest of the line, where
240
+ arguments are passed without parentheses or quotes. For example, this will
241
+ time the given statement::
242
+
243
+ %timeit range(1000)
244
+
245
+ Cell magics are prefixed with a double %%, and they are functions that get as
246
+ an argument not only the rest of the line, but also the lines below it in a
247
+ separate argument. These magics are called with two arguments: the rest of the
248
+ call line and the body of the cell, consisting of the lines below the first.
249
+ For example::
250
+
251
+ %%timeit x = numpy.random.randn((100, 100))
252
+ numpy.linalg.svd(x)
253
+
254
+ will time the execution of the numpy svd routine, running the assignment of x
255
+ as part of the setup phase, which is not timed.
256
+
257
+ In a line-oriented client (the terminal or Qt console IPython), starting a new
258
+ input with %% will automatically enter cell mode, and IPython will continue
259
+ reading input until a blank line is given. In the notebook, simply type the
260
+ whole cell as one entity, but keep in mind that the %% escape can only be at
261
+ the very start of the cell.
262
+
263
+ NOTE: If you have 'automagic' enabled (via the command line option or with the
264
+ %automagic function), you don't need to type in the % explicitly for line
265
+ magics; cell magics always require an explicit '%%' escape. By default,
266
+ IPython ships with automagic on, so you should only rarely need the % escape.
267
+
268
+ Example: typing '%cd mydir' (without the quotes) changes your working directory
269
+ to 'mydir', if it exists.
270
+
271
+ For a list of the available magic functions, use %lsmagic. For a description
272
+ of any of them, type %magic_name?, e.g. '%cd?'.
273
+
274
+ Currently the magic system has the following functions:""",
275
+ magic_docs,
276
+ "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
277
+ str(self.lsmagic()),
278
+ ]
279
+ page.page('\n'.join(out))
280
+
281
+
282
+ @line_magic
283
+ def page(self, parameter_s=''):
284
+ """Pretty print the object and display it through a pager.
285
+
286
+ %page [options] OBJECT
287
+
288
+ If no object is given, use _ (last output).
289
+
290
+ Options:
291
+
292
+ -r: page str(object), don't pretty-print it."""
293
+
294
+ # After a function contributed by Olivier Aubert, slightly modified.
295
+
296
+ # Process options/args
297
+ opts, args = self.parse_options(parameter_s, 'r')
298
+ raw = 'r' in opts
299
+
300
+ oname = args and args or '_'
301
+ info = self.shell._ofind(oname)
302
+ if info.found:
303
+ if raw:
304
+ txt = str(info.obj)
305
+ else:
306
+ txt = pformat(info.obj)
307
+ page.page(txt)
308
+ else:
309
+ print('Object `%s` not found' % oname)
310
+
311
+ @line_magic
312
+ def pprint(self, parameter_s=''):
313
+ """Toggle pretty printing on/off."""
314
+ ptformatter = self.shell.display_formatter.formatters['text/plain']
315
+ ptformatter.pprint = bool(1 - ptformatter.pprint)
316
+ print('Pretty printing has been turned',
317
+ ['OFF','ON'][ptformatter.pprint])
318
+
319
+ @line_magic
320
+ def colors(self, parameter_s=''):
321
+ """Switch color scheme for prompts, info system and exception handlers.
322
+
323
+ Currently implemented schemes: NoColor, Linux, LightBG.
324
+
325
+ Color scheme names are not case-sensitive.
326
+
327
+ Examples
328
+ --------
329
+ To get a plain black and white terminal::
330
+
331
+ %colors nocolor
332
+ """
333
+ def color_switch_err(name):
334
+ warn('Error changing %s color schemes.\n%s' %
335
+ (name, sys.exc_info()[1]), stacklevel=2)
336
+
337
+
338
+ new_scheme = parameter_s.strip()
339
+ if not new_scheme:
340
+ raise UsageError(
341
+ "%colors: you must specify a color scheme. See '%colors?'")
342
+ # local shortcut
343
+ shell = self.shell
344
+
345
+ # Set shell colour scheme
346
+ try:
347
+ shell.colors = new_scheme
348
+ shell.refresh_style()
349
+ except:
350
+ color_switch_err('shell')
351
+
352
+ # Set exception colors
353
+ try:
354
+ shell.InteractiveTB.set_colors(scheme = new_scheme)
355
+ shell.SyntaxTB.set_colors(scheme = new_scheme)
356
+ except:
357
+ color_switch_err('exception')
358
+
359
+ # Set info (for 'object?') colors
360
+ if shell.color_info:
361
+ try:
362
+ shell.inspector.set_active_scheme(new_scheme)
363
+ except:
364
+ color_switch_err('object inspector')
365
+ else:
366
+ shell.inspector.set_active_scheme('NoColor')
367
+
368
+ @line_magic
369
+ def xmode(self, parameter_s=''):
370
+ """Switch modes for the exception handlers.
371
+
372
+ Valid modes: Plain, Context, Verbose, and Minimal.
373
+
374
+ If called without arguments, acts as a toggle.
375
+
376
+ When in verbose mode the value `--show` (and `--hide`)
377
+ will respectively show (or hide) frames with ``__tracebackhide__ =
378
+ True`` value set.
379
+ """
380
+
381
+ def xmode_switch_err(name):
382
+ warn('Error changing %s exception modes.\n%s' %
383
+ (name,sys.exc_info()[1]))
384
+
385
+ shell = self.shell
386
+ if parameter_s.strip() == "--show":
387
+ shell.InteractiveTB.skip_hidden = False
388
+ return
389
+ if parameter_s.strip() == "--hide":
390
+ shell.InteractiveTB.skip_hidden = True
391
+ return
392
+
393
+ new_mode = parameter_s.strip().capitalize()
394
+ try:
395
+ shell.InteractiveTB.set_mode(mode=new_mode)
396
+ print('Exception reporting mode:',shell.InteractiveTB.mode)
397
+ except:
398
+ xmode_switch_err('user')
399
+
400
+ @line_magic
401
+ def quickref(self, arg):
402
+ """ Show a quick reference sheet """
403
+ from IPython.core.usage import quick_reference
404
+ qr = quick_reference + self._magic_docs(brief=True)
405
+ page.page(qr)
406
+
407
+ @line_magic
408
+ def doctest_mode(self, parameter_s=''):
409
+ """Toggle doctest mode on and off.
410
+
411
+ This mode is intended to make IPython behave as much as possible like a
412
+ plain Python shell, from the perspective of how its prompts, exceptions
413
+ and output look. This makes it easy to copy and paste parts of a
414
+ session into doctests. It does so by:
415
+
416
+ - Changing the prompts to the classic ``>>>`` ones.
417
+ - Changing the exception reporting mode to 'Plain'.
418
+ - Disabling pretty-printing of output.
419
+
420
+ Note that IPython also supports the pasting of code snippets that have
421
+ leading '>>>' and '...' prompts in them. This means that you can paste
422
+ doctests from files or docstrings (even if they have leading
423
+ whitespace), and the code will execute correctly. You can then use
424
+ '%history -t' to see the translated history; this will give you the
425
+ input after removal of all the leading prompts and whitespace, which
426
+ can be pasted back into an editor.
427
+
428
+ With these features, you can switch into this mode easily whenever you
429
+ need to do testing and changes to doctests, without having to leave
430
+ your existing IPython session.
431
+ """
432
+
433
+ # Shorthands
434
+ shell = self.shell
435
+ meta = shell.meta
436
+ disp_formatter = self.shell.display_formatter
437
+ ptformatter = disp_formatter.formatters['text/plain']
438
+ # dstore is a data store kept in the instance metadata bag to track any
439
+ # changes we make, so we can undo them later.
440
+ dstore = meta.setdefault('doctest_mode',Struct())
441
+ save_dstore = dstore.setdefault
442
+
443
+ # save a few values we'll need to recover later
444
+ mode = save_dstore('mode',False)
445
+ save_dstore('rc_pprint',ptformatter.pprint)
446
+ save_dstore('xmode',shell.InteractiveTB.mode)
447
+ save_dstore('rc_separate_out',shell.separate_out)
448
+ save_dstore('rc_separate_out2',shell.separate_out2)
449
+ save_dstore('rc_separate_in',shell.separate_in)
450
+ save_dstore('rc_active_types',disp_formatter.active_types)
451
+
452
+ if not mode:
453
+ # turn on
454
+
455
+ # Prompt separators like plain python
456
+ shell.separate_in = ''
457
+ shell.separate_out = ''
458
+ shell.separate_out2 = ''
459
+
460
+
461
+ ptformatter.pprint = False
462
+ disp_formatter.active_types = ['text/plain']
463
+
464
+ shell.run_line_magic("xmode", "Plain")
465
+ else:
466
+ # turn off
467
+ shell.separate_in = dstore.rc_separate_in
468
+
469
+ shell.separate_out = dstore.rc_separate_out
470
+ shell.separate_out2 = dstore.rc_separate_out2
471
+
472
+ ptformatter.pprint = dstore.rc_pprint
473
+ disp_formatter.active_types = dstore.rc_active_types
474
+
475
+ shell.run_line_magic("xmode", dstore.xmode)
476
+
477
+ # mode here is the state before we switch; switch_doctest_mode takes
478
+ # the mode we're switching to.
479
+ shell.switch_doctest_mode(not mode)
480
+
481
+ # Store new mode and inform
482
+ dstore.mode = bool(not mode)
483
+ mode_label = ['OFF','ON'][dstore.mode]
484
+ print('Doctest mode is:', mode_label)
485
+
486
+ @line_magic
487
+ def gui(self, parameter_s=''):
488
+ """Enable or disable IPython GUI event loop integration.
489
+
490
+ %gui [GUINAME]
491
+
492
+ This magic replaces IPython's threaded shells that were activated
493
+ using the (pylab/wthread/etc.) command line flags. GUI toolkits
494
+ can now be enabled at runtime and keyboard
495
+ interrupts should work without any problems. The following toolkits
496
+ are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
497
+
498
+ %gui wx # enable wxPython event loop integration
499
+ %gui qt # enable PyQt/PySide event loop integration
500
+ # with the latest version available.
501
+ %gui qt6 # enable PyQt6/PySide6 event loop integration
502
+ %gui qt5 # enable PyQt5/PySide2 event loop integration
503
+ %gui gtk # enable PyGTK event loop integration
504
+ %gui gtk3 # enable Gtk3 event loop integration
505
+ %gui gtk4 # enable Gtk4 event loop integration
506
+ %gui tk # enable Tk event loop integration
507
+ %gui osx # enable Cocoa event loop integration
508
+ # (requires %matplotlib 1.1)
509
+ %gui # disable all event loop integration
510
+
511
+ WARNING: after any of these has been called you can simply create
512
+ an application object, but DO NOT start the event loop yourself, as
513
+ we have already handled that.
514
+ """
515
+ opts, arg = self.parse_options(parameter_s, '')
516
+ if arg=='': arg = None
517
+ try:
518
+ return self.shell.enable_gui(arg)
519
+ except Exception as e:
520
+ # print simple error message, rather than traceback if we can't
521
+ # hook up the GUI
522
+ error(str(e))
523
+
524
+ @skip_doctest
525
+ @line_magic
526
+ def precision(self, s=''):
527
+ """Set floating point precision for pretty printing.
528
+
529
+ Can set either integer precision or a format string.
530
+
531
+ If numpy has been imported and precision is an int,
532
+ numpy display precision will also be set, via ``numpy.set_printoptions``.
533
+
534
+ If no argument is given, defaults will be restored.
535
+
536
+ Examples
537
+ --------
538
+ ::
539
+
540
+ In [1]: from math import pi
541
+
542
+ In [2]: %precision 3
543
+ Out[2]: '%.3f'
544
+
545
+ In [3]: pi
546
+ Out[3]: 3.142
547
+
548
+ In [4]: %precision %i
549
+ Out[4]: '%i'
550
+
551
+ In [5]: pi
552
+ Out[5]: 3
553
+
554
+ In [6]: %precision %e
555
+ Out[6]: '%e'
556
+
557
+ In [7]: pi**10
558
+ Out[7]: 9.364805e+04
559
+
560
+ In [8]: %precision
561
+ Out[8]: '%r'
562
+
563
+ In [9]: pi**10
564
+ Out[9]: 93648.047476082982
565
+ """
566
+ ptformatter = self.shell.display_formatter.formatters['text/plain']
567
+ ptformatter.float_precision = s
568
+ return ptformatter.float_format
569
+
570
+ @magic_arguments.magic_arguments()
571
+ @magic_arguments.argument(
572
+ 'filename', type=str,
573
+ help='Notebook name or filename'
574
+ )
575
+ @line_magic
576
+ def notebook(self, s):
577
+ """Export and convert IPython notebooks.
578
+
579
+ This function can export the current IPython history to a notebook file.
580
+ For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb".
581
+ """
582
+ args = magic_arguments.parse_argstring(self.notebook, s)
583
+ outfname = os.path.expanduser(args.filename)
584
+
585
+ from nbformat import write, v4
586
+
587
+ cells = []
588
+ hist = list(self.shell.history_manager.get_range())
589
+ if(len(hist)<=1):
590
+ raise ValueError('History is empty, cannot export')
591
+ for session, execution_count, source in hist[:-1]:
592
+ cells.append(v4.new_code_cell(
593
+ execution_count=execution_count,
594
+ source=source
595
+ ))
596
+ nb = v4.new_notebook(cells=cells)
597
+ with io.open(outfname, "w", encoding="utf-8") as f:
598
+ write(nb, f, version=4)
599
+
600
+ @magics_class
601
+ class AsyncMagics(BasicMagics):
602
+
603
+ @line_magic
604
+ def autoawait(self, parameter_s):
605
+ """
606
+ Allow to change the status of the autoawait option.
607
+
608
+ This allow you to set a specific asynchronous code runner.
609
+
610
+ If no value is passed, print the currently used asynchronous integration
611
+ and whether it is activated.
612
+
613
+ It can take a number of value evaluated in the following order:
614
+
615
+ - False/false/off deactivate autoawait integration
616
+ - True/true/on activate autoawait integration using configured default
617
+ loop
618
+ - asyncio/curio/trio activate autoawait integration and use integration
619
+ with said library.
620
+
621
+ - `sync` turn on the pseudo-sync integration (mostly used for
622
+ `IPython.embed()` which does not run IPython with a real eventloop and
623
+ deactivate running asynchronous code. Turning on Asynchronous code with
624
+ the pseudo sync loop is undefined behavior and may lead IPython to crash.
625
+
626
+ If the passed parameter does not match any of the above and is a python
627
+ identifier, get said object from user namespace and set it as the
628
+ runner, and activate autoawait.
629
+
630
+ If the object is a fully qualified object name, attempt to import it and
631
+ set it as the runner, and activate autoawait.
632
+
633
+ The exact behavior of autoawait is experimental and subject to change
634
+ across version of IPython and Python.
635
+ """
636
+
637
+ param = parameter_s.strip()
638
+ d = {True: "on", False: "off"}
639
+
640
+ if not param:
641
+ print("IPython autoawait is `{}`, and set to use `{}`".format(
642
+ d[self.shell.autoawait],
643
+ self.shell.loop_runner
644
+ ))
645
+ return None
646
+
647
+ if param.lower() in ('false', 'off'):
648
+ self.shell.autoawait = False
649
+ return None
650
+ if param.lower() in ('true', 'on'):
651
+ self.shell.autoawait = True
652
+ return None
653
+
654
+ if param in self.shell.loop_runner_map:
655
+ self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param]
656
+ return None
657
+
658
+ if param in self.shell.user_ns :
659
+ self.shell.loop_runner = self.shell.user_ns[param]
660
+ self.shell.autoawait = True
661
+ return None
662
+
663
+ runner = import_item(param)
664
+
665
+ self.shell.loop_runner = runner
666
+ self.shell.autoawait = True
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/code.py ADDED
@@ -0,0 +1,757 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of code management magic functions.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ # Stdlib
16
+ import inspect
17
+ import io
18
+ import os
19
+ import re
20
+ import sys
21
+ import ast
22
+ from itertools import chain
23
+ from urllib.request import Request, urlopen
24
+ from urllib.parse import urlencode
25
+ from pathlib import Path
26
+
27
+ # Our own packages
28
+ from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
29
+ from IPython.core.macro import Macro
30
+ from IPython.core.magic import Magics, magics_class, line_magic
31
+ from IPython.core.oinspect import find_file, find_source_lines
32
+ from IPython.core.release import version
33
+ from IPython.testing.skipdoctest import skip_doctest
34
+ from IPython.utils.contexts import preserve_keys
35
+ from IPython.utils.path import get_py_filename
36
+ from warnings import warn
37
+ from logging import error
38
+ from IPython.utils.text import get_text_list
39
+
40
+ #-----------------------------------------------------------------------------
41
+ # Magic implementation classes
42
+ #-----------------------------------------------------------------------------
43
+
44
+ # Used for exception handling in magic_edit
45
+ class MacroToEdit(ValueError): pass
46
+
47
+ ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
48
+
49
+ # To match, e.g. 8-10 1:5 :10 3-
50
+ range_re = re.compile(r"""
51
+ (?P<start>\d+)?
52
+ ((?P<sep>[\-:])
53
+ (?P<end>\d+)?)?
54
+ $""", re.VERBOSE)
55
+
56
+
57
+ def extract_code_ranges(ranges_str):
58
+ """Turn a string of range for %%load into 2-tuples of (start, stop)
59
+ ready to use as a slice of the content split by lines.
60
+
61
+ Examples
62
+ --------
63
+ list(extract_input_ranges("5-10 2"))
64
+ [(4, 10), (1, 2)]
65
+ """
66
+ for range_str in ranges_str.split():
67
+ rmatch = range_re.match(range_str)
68
+ if not rmatch:
69
+ continue
70
+ sep = rmatch.group("sep")
71
+ start = rmatch.group("start")
72
+ end = rmatch.group("end")
73
+
74
+ if sep == '-':
75
+ start = int(start) - 1 if start else None
76
+ end = int(end) if end else None
77
+ elif sep == ':':
78
+ start = int(start) - 1 if start else None
79
+ end = int(end) - 1 if end else None
80
+ else:
81
+ end = int(start)
82
+ start = int(start) - 1
83
+ yield (start, end)
84
+
85
+
86
+ def extract_symbols(code, symbols):
87
+ """
88
+ Return a tuple (blocks, not_found)
89
+ where ``blocks`` is a list of code fragments
90
+ for each symbol parsed from code, and ``not_found`` are
91
+ symbols not found in the code.
92
+
93
+ For example::
94
+
95
+ In [1]: code = '''a = 10
96
+ ...: def b(): return 42
97
+ ...: class A: pass'''
98
+
99
+ In [2]: extract_symbols(code, 'A,b,z')
100
+ Out[2]: (['class A: pass\\n', 'def b(): return 42\\n'], ['z'])
101
+ """
102
+ symbols = symbols.split(',')
103
+
104
+ # this will raise SyntaxError if code isn't valid Python
105
+ py_code = ast.parse(code)
106
+
107
+ marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
108
+ code = code.split('\n')
109
+
110
+ symbols_lines = {}
111
+
112
+ # we already know the start_lineno of each symbol (marks).
113
+ # To find each end_lineno, we traverse in reverse order until each
114
+ # non-blank line
115
+ end = len(code)
116
+ for name, start in reversed(marks):
117
+ while not code[end - 1].strip():
118
+ end -= 1
119
+ if name:
120
+ symbols_lines[name] = (start - 1, end)
121
+ end = start - 1
122
+
123
+ # Now symbols_lines is a map
124
+ # {'symbol_name': (start_lineno, end_lineno), ...}
125
+
126
+ # fill a list with chunks of codes for each requested symbol
127
+ blocks = []
128
+ not_found = []
129
+ for symbol in symbols:
130
+ if symbol in symbols_lines:
131
+ start, end = symbols_lines[symbol]
132
+ blocks.append('\n'.join(code[start:end]) + '\n')
133
+ else:
134
+ not_found.append(symbol)
135
+
136
+ return blocks, not_found
137
+
138
+ def strip_initial_indent(lines):
139
+ """For %load, strip indent from lines until finding an unindented line.
140
+
141
+ https://github.com/ipython/ipython/issues/9775
142
+ """
143
+ indent_re = re.compile(r'\s+')
144
+
145
+ it = iter(lines)
146
+ first_line = next(it)
147
+ indent_match = indent_re.match(first_line)
148
+
149
+ if indent_match:
150
+ # First line was indented
151
+ indent = indent_match.group()
152
+ yield first_line[len(indent):]
153
+
154
+ for line in it:
155
+ if line.startswith(indent):
156
+ yield line[len(indent) :]
157
+ elif line in ("\n", "\r\n") or len(line) == 0:
158
+ yield line
159
+ else:
160
+ # Less indented than the first line - stop dedenting
161
+ yield line
162
+ break
163
+ else:
164
+ yield first_line
165
+
166
+ # Pass the remaining lines through without dedenting
167
+ for line in it:
168
+ yield line
169
+
170
+
171
+ class InteractivelyDefined(Exception):
172
+ """Exception for interactively defined variable in magic_edit"""
173
+ def __init__(self, index):
174
+ self.index = index
175
+
176
+
177
+ @magics_class
178
+ class CodeMagics(Magics):
179
+ """Magics related to code management (loading, saving, editing, ...)."""
180
+
181
+ def __init__(self, *args, **kwargs):
182
+ self._knowntemps = set()
183
+ super(CodeMagics, self).__init__(*args, **kwargs)
184
+
185
+ @line_magic
186
+ def save(self, parameter_s=''):
187
+ """Save a set of lines or a macro to a given filename.
188
+
189
+ Usage:\\
190
+ %save [options] filename [history]
191
+
192
+ Options:
193
+
194
+ -r: use 'raw' input. By default, the 'processed' history is used,
195
+ so that magics are loaded in their transformed version to valid
196
+ Python. If this option is given, the raw input as typed as the
197
+ command line is used instead.
198
+
199
+ -f: force overwrite. If file exists, %save will prompt for overwrite
200
+ unless -f is given.
201
+
202
+ -a: append to the file instead of overwriting it.
203
+
204
+ The history argument uses the same syntax as %history for input ranges,
205
+ then saves the lines to the filename you specify.
206
+
207
+ If no ranges are specified, saves history of the current session up to
208
+ this point.
209
+
210
+ It adds a '.py' extension to the file if you don't do so yourself, and
211
+ it asks for confirmation before overwriting existing files.
212
+
213
+ If `-r` option is used, the default extension is `.ipy`.
214
+ """
215
+
216
+ opts,args = self.parse_options(parameter_s,'fra',mode='list')
217
+ if not args:
218
+ raise UsageError('Missing filename.')
219
+ raw = 'r' in opts
220
+ force = 'f' in opts
221
+ append = 'a' in opts
222
+ mode = 'a' if append else 'w'
223
+ ext = '.ipy' if raw else '.py'
224
+ fname, codefrom = args[0], " ".join(args[1:])
225
+ if not fname.endswith(('.py','.ipy')):
226
+ fname += ext
227
+ fname = os.path.expanduser(fname)
228
+ file_exists = os.path.isfile(fname)
229
+ if file_exists and not force and not append:
230
+ try:
231
+ overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
232
+ except StdinNotImplementedError:
233
+ print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
234
+ return
235
+ if not overwrite :
236
+ print('Operation cancelled.')
237
+ return
238
+ try:
239
+ cmds = self.shell.find_user_code(codefrom,raw)
240
+ except (TypeError, ValueError) as e:
241
+ print(e.args[0])
242
+ return
243
+ with io.open(fname, mode, encoding="utf-8") as f:
244
+ if not file_exists or not append:
245
+ f.write("# coding: utf-8\n")
246
+ f.write(cmds)
247
+ # make sure we end on a newline
248
+ if not cmds.endswith('\n'):
249
+ f.write('\n')
250
+ print('The following commands were written to file `%s`:' % fname)
251
+ print(cmds)
252
+
253
+ @line_magic
254
+ def pastebin(self, parameter_s=''):
255
+ """Upload code to dpaste.com, returning the URL.
256
+
257
+ Usage:\\
258
+ %pastebin [-d "Custom description"][-e 24] 1-7
259
+
260
+ The argument can be an input history range, a filename, or the name of a
261
+ string or macro.
262
+
263
+ If no arguments are given, uploads the history of this session up to
264
+ this point.
265
+
266
+ Options:
267
+
268
+ -d: Pass a custom description. The default will say
269
+ "Pasted from IPython".
270
+ -e: Pass number of days for the link to be expired.
271
+ The default will be 7 days.
272
+ """
273
+ opts, args = self.parse_options(parameter_s, "d:e:")
274
+
275
+ try:
276
+ code = self.shell.find_user_code(args)
277
+ except (ValueError, TypeError) as e:
278
+ print(e.args[0])
279
+ return
280
+
281
+ expiry_days = 7
282
+ try:
283
+ expiry_days = int(opts.get("e", 7))
284
+ except ValueError as e:
285
+ print(e.args[0].capitalize())
286
+ return
287
+ if expiry_days < 1 or expiry_days > 365:
288
+ print("Expiry days should be in range of 1 to 365")
289
+ return
290
+
291
+ post_data = urlencode(
292
+ {
293
+ "title": opts.get("d", "Pasted from IPython"),
294
+ "syntax": "python",
295
+ "content": code,
296
+ "expiry_days": expiry_days,
297
+ }
298
+ ).encode("utf-8")
299
+
300
+ request = Request(
301
+ "https://dpaste.com/api/v2/",
302
+ headers={"User-Agent": "IPython v{}".format(version)},
303
+ )
304
+ response = urlopen(request, post_data)
305
+ return response.headers.get('Location')
306
+
307
+ @line_magic
308
+ def loadpy(self, arg_s):
309
+ """Alias of `%load`
310
+
311
+ `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
312
+ extension. So it has been renamed simply into %load. You can look at
313
+ `%load`'s docstring for more info.
314
+ """
315
+ self.load(arg_s)
316
+
317
+ @line_magic
318
+ def load(self, arg_s):
319
+ """Load code into the current frontend.
320
+
321
+ Usage:\\
322
+ %load [options] source
323
+
324
+ where source can be a filename, URL, input history range, macro, or
325
+ element in the user namespace
326
+
327
+ If no arguments are given, loads the history of this session up to this
328
+ point.
329
+
330
+ Options:
331
+
332
+ -r <lines>: Specify lines or ranges of lines to load from the source.
333
+ Ranges could be specified as x-y (x..y) or in python-style x:y
334
+ (x..(y-1)). Both limits x and y can be left blank (meaning the
335
+ beginning and end of the file, respectively).
336
+
337
+ -s <symbols>: Specify function or classes to load from python source.
338
+
339
+ -y : Don't ask confirmation for loading source above 200 000 characters.
340
+
341
+ -n : Include the user's namespace when searching for source code.
342
+
343
+ This magic command can either take a local filename, a URL, an history
344
+ range (see %history) or a macro as argument, it will prompt for
345
+ confirmation before loading source with more than 200 000 characters, unless
346
+ -y flag is passed or if the frontend does not support raw_input::
347
+
348
+ %load
349
+ %load myscript.py
350
+ %load 7-27
351
+ %load myMacro
352
+ %load http://www.example.com/myscript.py
353
+ %load -r 5-10 myscript.py
354
+ %load -r 10-20,30,40: foo.py
355
+ %load -s MyClass,wonder_function myscript.py
356
+ %load -n MyClass
357
+ %load -n my_module.wonder_function
358
+ """
359
+ opts,args = self.parse_options(arg_s,'yns:r:')
360
+ search_ns = 'n' in opts
361
+ contents = self.shell.find_user_code(args, search_ns=search_ns)
362
+
363
+ if 's' in opts:
364
+ try:
365
+ blocks, not_found = extract_symbols(contents, opts['s'])
366
+ except SyntaxError:
367
+ # non python code
368
+ error("Unable to parse the input as valid Python code")
369
+ return
370
+
371
+ if len(not_found) == 1:
372
+ warn('The symbol `%s` was not found' % not_found[0])
373
+ elif len(not_found) > 1:
374
+ warn('The symbols %s were not found' % get_text_list(not_found,
375
+ wrap_item_with='`')
376
+ )
377
+
378
+ contents = '\n'.join(blocks)
379
+
380
+ if 'r' in opts:
381
+ ranges = opts['r'].replace(',', ' ')
382
+ lines = contents.split('\n')
383
+ slices = extract_code_ranges(ranges)
384
+ contents = [lines[slice(*slc)] for slc in slices]
385
+ contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
386
+
387
+ l = len(contents)
388
+
389
+ # 200 000 is ~ 2500 full 80 character lines
390
+ # so in average, more than 5000 lines
391
+ if l > 200000 and 'y' not in opts:
392
+ try:
393
+ ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
394
+ " (%d characters). Continue (y/[N]) ?" % l), default='n' )
395
+ except StdinNotImplementedError:
396
+ #assume yes if raw input not implemented
397
+ ans = True
398
+
399
+ if ans is False :
400
+ print('Operation cancelled.')
401
+ return
402
+
403
+ contents = "# %load {}\n".format(arg_s) + contents
404
+
405
+ self.shell.set_next_input(contents, replace=True)
406
+
407
+ @staticmethod
408
+ def _find_edit_target(shell, args, opts, last_call):
409
+ """Utility method used by magic_edit to find what to edit."""
410
+
411
+ def make_filename(arg):
412
+ "Make a filename from the given args"
413
+ try:
414
+ filename = get_py_filename(arg)
415
+ except IOError:
416
+ # If it ends with .py but doesn't already exist, assume we want
417
+ # a new file.
418
+ if arg.endswith('.py'):
419
+ filename = arg
420
+ else:
421
+ filename = None
422
+ return filename
423
+
424
+ # Set a few locals from the options for convenience:
425
+ opts_prev = 'p' in opts
426
+ opts_raw = 'r' in opts
427
+
428
+ # custom exceptions
429
+ class DataIsObject(Exception): pass
430
+
431
+ # Default line number value
432
+ lineno = opts.get('n',None)
433
+
434
+ if opts_prev:
435
+ args = '_%s' % last_call[0]
436
+ if args not in shell.user_ns:
437
+ args = last_call[1]
438
+
439
+ # by default this is done with temp files, except when the given
440
+ # arg is a filename
441
+ use_temp = True
442
+
443
+ data = ''
444
+
445
+ # First, see if the arguments should be a filename.
446
+ filename = make_filename(args)
447
+ if filename:
448
+ use_temp = False
449
+ elif args:
450
+ # Mode where user specifies ranges of lines, like in %macro.
451
+ data = shell.extract_input_lines(args, opts_raw)
452
+ if not data:
453
+ try:
454
+ # Load the parameter given as a variable. If not a string,
455
+ # process it as an object instead (below)
456
+
457
+ # print('*** args',args,'type',type(args)) # dbg
458
+ data = eval(args, shell.user_ns)
459
+ if not isinstance(data, str):
460
+ raise DataIsObject
461
+
462
+ except (NameError,SyntaxError):
463
+ # given argument is not a variable, try as a filename
464
+ filename = make_filename(args)
465
+ if filename is None:
466
+ warn("Argument given (%s) can't be found as a variable "
467
+ "or as a filename." % args)
468
+ return (None, None, None)
469
+ use_temp = False
470
+
471
+ except DataIsObject as e:
472
+ # macros have a special edit function
473
+ if isinstance(data, Macro):
474
+ raise MacroToEdit(data) from e
475
+
476
+ # For objects, try to edit the file where they are defined
477
+ filename = find_file(data)
478
+ if filename:
479
+ if 'fakemodule' in filename.lower() and \
480
+ inspect.isclass(data):
481
+ # class created by %edit? Try to find source
482
+ # by looking for method definitions instead, the
483
+ # __module__ in those classes is FakeModule.
484
+ attrs = [getattr(data, aname) for aname in dir(data)]
485
+ for attr in attrs:
486
+ if not inspect.ismethod(attr):
487
+ continue
488
+ filename = find_file(attr)
489
+ if filename and \
490
+ 'fakemodule' not in filename.lower():
491
+ # change the attribute to be the edit
492
+ # target instead
493
+ data = attr
494
+ break
495
+
496
+ m = ipython_input_pat.match(os.path.basename(filename))
497
+ if m:
498
+ raise InteractivelyDefined(int(m.groups()[0])) from e
499
+
500
+ datafile = 1
501
+ if filename is None:
502
+ filename = make_filename(args)
503
+ datafile = 1
504
+ if filename is not None:
505
+ # only warn about this if we get a real name
506
+ warn('Could not find file where `%s` is defined.\n'
507
+ 'Opening a file named `%s`' % (args, filename))
508
+ # Now, make sure we can actually read the source (if it was
509
+ # in a temp file it's gone by now).
510
+ if datafile:
511
+ if lineno is None:
512
+ lineno = find_source_lines(data)
513
+ if lineno is None:
514
+ filename = make_filename(args)
515
+ if filename is None:
516
+ warn('The file where `%s` was defined '
517
+ 'cannot be read or found.' % data)
518
+ return (None, None, None)
519
+ use_temp = False
520
+
521
+ if use_temp:
522
+ filename = shell.mktempfile(data)
523
+ print('IPython will make a temporary file named:',filename)
524
+
525
+ # use last_call to remember the state of the previous call, but don't
526
+ # let it be clobbered by successive '-p' calls.
527
+ try:
528
+ last_call[0] = shell.displayhook.prompt_count
529
+ if not opts_prev:
530
+ last_call[1] = args
531
+ except:
532
+ pass
533
+
534
+
535
+ return filename, lineno, use_temp
536
+
537
+ def _edit_macro(self,mname,macro):
538
+ """open an editor with the macro data in a file"""
539
+ filename = self.shell.mktempfile(macro.value)
540
+ self.shell.hooks.editor(filename)
541
+
542
+ # and make a new macro object, to replace the old one
543
+ mvalue = Path(filename).read_text(encoding="utf-8")
544
+ self.shell.user_ns[mname] = Macro(mvalue)
545
+
546
+ @skip_doctest
547
+ @line_magic
548
+ def edit(self, parameter_s='',last_call=['','']):
549
+ """Bring up an editor and execute the resulting code.
550
+
551
+ Usage:
552
+ %edit [options] [args]
553
+
554
+ %edit runs IPython's editor hook. The default version of this hook is
555
+ set to call the editor specified by your $EDITOR environment variable.
556
+ If this isn't found, it will default to vi under Linux/Unix and to
557
+ notepad under Windows. See the end of this docstring for how to change
558
+ the editor hook.
559
+
560
+ You can also set the value of this editor via the
561
+ ``TerminalInteractiveShell.editor`` option in your configuration file.
562
+ This is useful if you wish to use a different editor from your typical
563
+ default with IPython (and for Windows users who typically don't set
564
+ environment variables).
565
+
566
+ This command allows you to conveniently edit multi-line code right in
567
+ your IPython session.
568
+
569
+ If called without arguments, %edit opens up an empty editor with a
570
+ temporary file and will execute the contents of this file when you
571
+ close it (don't forget to save it!).
572
+
573
+
574
+ Options:
575
+
576
+ -n <number>: open the editor at a specified line number. By default,
577
+ the IPython editor hook uses the unix syntax 'editor +N filename', but
578
+ you can configure this by providing your own modified hook if your
579
+ favorite editor supports line-number specifications with a different
580
+ syntax.
581
+
582
+ -p: this will call the editor with the same data as the previous time
583
+ it was used, regardless of how long ago (in your current session) it
584
+ was.
585
+
586
+ -r: use 'raw' input. This option only applies to input taken from the
587
+ user's history. By default, the 'processed' history is used, so that
588
+ magics are loaded in their transformed version to valid Python. If
589
+ this option is given, the raw input as typed as the command line is
590
+ used instead. When you exit the editor, it will be executed by
591
+ IPython's own processor.
592
+
593
+ -x: do not execute the edited code immediately upon exit. This is
594
+ mainly useful if you are editing programs which need to be called with
595
+ command line arguments, which you can then do using %run.
596
+
597
+
598
+ Arguments:
599
+
600
+ If arguments are given, the following possibilities exist:
601
+
602
+ - If the argument is a filename, IPython will load that into the
603
+ editor. It will execute its contents with execfile() when you exit,
604
+ loading any code in the file into your interactive namespace.
605
+
606
+ - The arguments are ranges of input history, e.g. "7 ~1/4-6".
607
+ The syntax is the same as in the %history magic.
608
+
609
+ - If the argument is a string variable, its contents are loaded
610
+ into the editor. You can thus edit any string which contains
611
+ python code (including the result of previous edits).
612
+
613
+ - If the argument is the name of an object (other than a string),
614
+ IPython will try to locate the file where it was defined and open the
615
+ editor at the point where it is defined. You can use `%edit function`
616
+ to load an editor exactly at the point where 'function' is defined,
617
+ edit it and have the file be executed automatically.
618
+
619
+ - If the object is a macro (see %macro for details), this opens up your
620
+ specified editor with a temporary file containing the macro's data.
621
+ Upon exit, the macro is reloaded with the contents of the file.
622
+
623
+ Note: opening at an exact line is only supported under Unix, and some
624
+ editors (like kedit and gedit up to Gnome 2.8) do not understand the
625
+ '+NUMBER' parameter necessary for this feature. Good editors like
626
+ (X)Emacs, vi, jed, pico and joe all do.
627
+
628
+ After executing your code, %edit will return as output the code you
629
+ typed in the editor (except when it was an existing file). This way
630
+ you can reload the code in further invocations of %edit as a variable,
631
+ via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
632
+ the output.
633
+
634
+ Note that %edit is also available through the alias %ed.
635
+
636
+ This is an example of creating a simple function inside the editor and
637
+ then modifying it. First, start up the editor::
638
+
639
+ In [1]: edit
640
+ Editing... done. Executing edited code...
641
+ Out[1]: 'def foo():\\n print("foo() was defined in an editing
642
+ session")\\n'
643
+
644
+ We can then call the function foo()::
645
+
646
+ In [2]: foo()
647
+ foo() was defined in an editing session
648
+
649
+ Now we edit foo. IPython automatically loads the editor with the
650
+ (temporary) file where foo() was previously defined::
651
+
652
+ In [3]: edit foo
653
+ Editing... done. Executing edited code...
654
+
655
+ And if we call foo() again we get the modified version::
656
+
657
+ In [4]: foo()
658
+ foo() has now been changed!
659
+
660
+ Here is an example of how to edit a code snippet successive
661
+ times. First we call the editor::
662
+
663
+ In [5]: edit
664
+ Editing... done. Executing edited code...
665
+ hello
666
+ Out[5]: "print('hello')\\n"
667
+
668
+ Now we call it again with the previous output (stored in _)::
669
+
670
+ In [6]: edit _
671
+ Editing... done. Executing edited code...
672
+ hello world
673
+ Out[6]: "print('hello world')\\n"
674
+
675
+ Now we call it with the output #8 (stored in _8, also as Out[8])::
676
+
677
+ In [7]: edit _8
678
+ Editing... done. Executing edited code...
679
+ hello again
680
+ Out[7]: "print('hello again')\\n"
681
+
682
+
683
+ Changing the default editor hook:
684
+
685
+ If you wish to write your own editor hook, you can put it in a
686
+ configuration file which you load at startup time. The default hook
687
+ is defined in the IPython.core.hooks module, and you can use that as a
688
+ starting example for further modifications. That file also has
689
+ general instructions on how to set a new hook for use once you've
690
+ defined it."""
691
+ opts,args = self.parse_options(parameter_s,'prxn:')
692
+
693
+ try:
694
+ filename, lineno, is_temp = self._find_edit_target(self.shell,
695
+ args, opts, last_call)
696
+ except MacroToEdit as e:
697
+ self._edit_macro(args, e.args[0])
698
+ return
699
+ except InteractivelyDefined as e:
700
+ print("Editing In[%i]" % e.index)
701
+ args = str(e.index)
702
+ filename, lineno, is_temp = self._find_edit_target(self.shell,
703
+ args, opts, last_call)
704
+ if filename is None:
705
+ # nothing was found, warnings have already been issued,
706
+ # just give up.
707
+ return
708
+
709
+ if is_temp:
710
+ self._knowntemps.add(filename)
711
+ elif (filename in self._knowntemps):
712
+ is_temp = True
713
+
714
+
715
+ # do actual editing here
716
+ print('Editing...', end=' ')
717
+ sys.stdout.flush()
718
+ filepath = Path(filename)
719
+ try:
720
+ # Quote filenames that may have spaces in them when opening
721
+ # the editor
722
+ quoted = filename = str(filepath.absolute())
723
+ if " " in quoted:
724
+ quoted = "'%s'" % quoted
725
+ self.shell.hooks.editor(quoted, lineno)
726
+ except TryNext:
727
+ warn('Could not open editor')
728
+ return
729
+
730
+ # XXX TODO: should this be generalized for all string vars?
731
+ # For now, this is special-cased to blocks created by cpaste
732
+ if args.strip() == "pasted_block":
733
+ self.shell.user_ns["pasted_block"] = filepath.read_text(encoding="utf-8")
734
+
735
+ if 'x' in opts: # -x prevents actual execution
736
+ print()
737
+ else:
738
+ print('done. Executing edited code...')
739
+ with preserve_keys(self.shell.user_ns, '__file__'):
740
+ if not is_temp:
741
+ self.shell.user_ns["__file__"] = filename
742
+ if "r" in opts: # Untranslated IPython code
743
+ source = filepath.read_text(encoding="utf-8")
744
+ self.shell.run_cell(source, store_history=False)
745
+ else:
746
+ self.shell.safe_execfile(filename, self.shell.user_ns,
747
+ self.shell.user_ns)
748
+
749
+ if is_temp:
750
+ try:
751
+ return filepath.read_text(encoding="utf-8")
752
+ except IOError as msg:
753
+ if Path(msg.filename) == filepath:
754
+ warn('File not found. Did you forget to save?')
755
+ return
756
+ else:
757
+ self.shell.showtraceback()
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/config.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of configuration-related magic functions.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ # Stdlib
16
+ import re
17
+
18
+ # Our own packages
19
+ from IPython.core.error import UsageError
20
+ from IPython.core.magic import Magics, magics_class, line_magic
21
+ from logging import error
22
+
23
+ #-----------------------------------------------------------------------------
24
+ # Magic implementation classes
25
+ #-----------------------------------------------------------------------------
26
+
27
+ reg = re.compile(r'^\w+\.\w+$')
28
+ @magics_class
29
+ class ConfigMagics(Magics):
30
+
31
+ def __init__(self, shell):
32
+ super(ConfigMagics, self).__init__(shell)
33
+ self.configurables = []
34
+
35
+ @line_magic
36
+ def config(self, s):
37
+ """configure IPython
38
+
39
+ %config Class[.trait=value]
40
+
41
+ This magic exposes most of the IPython config system. Any
42
+ Configurable class should be able to be configured with the simple
43
+ line::
44
+
45
+ %config Class.trait=value
46
+
47
+ Where `value` will be resolved in the user's namespace, if it is an
48
+ expression or variable name.
49
+
50
+ Examples
51
+ --------
52
+
53
+ To see what classes are available for config, pass no arguments::
54
+
55
+ In [1]: %config
56
+ Available objects for config:
57
+ AliasManager
58
+ DisplayFormatter
59
+ HistoryManager
60
+ IPCompleter
61
+ LoggingMagics
62
+ MagicsManager
63
+ OSMagics
64
+ PrefilterManager
65
+ ScriptMagics
66
+ TerminalInteractiveShell
67
+
68
+ To view what is configurable on a given class, just pass the class
69
+ name::
70
+
71
+ In [2]: %config LoggingMagics
72
+ LoggingMagics(Magics) options
73
+ ---------------------------
74
+ LoggingMagics.quiet=<Bool>
75
+ Suppress output of log state when logging is enabled
76
+ Current: False
77
+
78
+ but the real use is in setting values::
79
+
80
+ In [3]: %config LoggingMagics.quiet = True
81
+
82
+ and these values are read from the user_ns if they are variables::
83
+
84
+ In [4]: feeling_quiet=False
85
+
86
+ In [5]: %config LoggingMagics.quiet = feeling_quiet
87
+
88
+ """
89
+ from traitlets.config.loader import Config
90
+ # some IPython objects are Configurable, but do not yet have
91
+ # any configurable traits. Exclude them from the effects of
92
+ # this magic, as their presence is just noise:
93
+ configurables = sorted(set([ c for c in self.shell.configurables
94
+ if c.__class__.class_traits(config=True)
95
+ ]), key=lambda x: x.__class__.__name__)
96
+ classnames = [ c.__class__.__name__ for c in configurables ]
97
+
98
+ line = s.strip()
99
+ if not line:
100
+ # print available configurable names
101
+ print("Available objects for config:")
102
+ for name in classnames:
103
+ print(" ", name)
104
+ return
105
+ elif line in classnames:
106
+ # `%config TerminalInteractiveShell` will print trait info for
107
+ # TerminalInteractiveShell
108
+ c = configurables[classnames.index(line)]
109
+ cls = c.__class__
110
+ help = cls.class_get_help(c)
111
+ # strip leading '--' from cl-args:
112
+ help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
113
+ print(help)
114
+ return
115
+ elif reg.match(line):
116
+ cls, attr = line.split('.')
117
+ return getattr(configurables[classnames.index(cls)],attr)
118
+ elif '=' not in line:
119
+ msg = "Invalid config statement: %r, "\
120
+ "should be `Class.trait = value`."
121
+
122
+ ll = line.lower()
123
+ for classname in classnames:
124
+ if ll == classname.lower():
125
+ msg = msg + '\nDid you mean %s (note the case)?' % classname
126
+ break
127
+
128
+ raise UsageError( msg % line)
129
+
130
+ # otherwise, assume we are setting configurables.
131
+ # leave quotes on args when splitting, because we want
132
+ # unquoted args to eval in user_ns
133
+ cfg = Config()
134
+ exec("cfg."+line, self.shell.user_ns, locals())
135
+
136
+ for configurable in configurables:
137
+ try:
138
+ configurable.update_config(cfg)
139
+ except Exception as e:
140
+ error(e)
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/display.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Simple magics for display formats"""
2
+ #-----------------------------------------------------------------------------
3
+ # Copyright (c) 2012 The IPython Development Team.
4
+ #
5
+ # Distributed under the terms of the Modified BSD License.
6
+ #
7
+ # The full license is in the file COPYING.txt, distributed with this software.
8
+ #-----------------------------------------------------------------------------
9
+
10
+ #-----------------------------------------------------------------------------
11
+ # Imports
12
+ #-----------------------------------------------------------------------------
13
+
14
+ # Our own packages
15
+ from IPython.display import display, Javascript, Latex, SVG, HTML, Markdown
16
+ from IPython.core.magic import (
17
+ Magics, magics_class, cell_magic
18
+ )
19
+ from IPython.core import magic_arguments
20
+
21
+ #-----------------------------------------------------------------------------
22
+ # Magic implementation classes
23
+ #-----------------------------------------------------------------------------
24
+
25
+
26
+ @magics_class
27
+ class DisplayMagics(Magics):
28
+ """Magics for displaying various output types with literals
29
+
30
+ Defines javascript/latex/svg/html cell magics for writing
31
+ blocks in those languages, to be rendered in the frontend.
32
+ """
33
+
34
+ @cell_magic
35
+ def js(self, line, cell):
36
+ """Run the cell block of Javascript code
37
+
38
+ Alias of `%%javascript`
39
+
40
+ Starting with IPython 8.0 %%javascript is pending deprecation to be replaced
41
+ by a more flexible system
42
+
43
+ Please See https://github.com/ipython/ipython/issues/13376
44
+ """
45
+ self.javascript(line, cell)
46
+
47
+ @cell_magic
48
+ def javascript(self, line, cell):
49
+ """Run the cell block of Javascript code
50
+
51
+ Starting with IPython 8.0 %%javascript is pending deprecation to be replaced
52
+ by a more flexible system
53
+
54
+ Please See https://github.com/ipython/ipython/issues/13376
55
+ """
56
+ display(Javascript(cell))
57
+
58
+
59
+ @cell_magic
60
+ def latex(self, line, cell):
61
+ """Render the cell as a block of LaTeX
62
+
63
+ The subset of LaTeX which is supported depends on the implementation in
64
+ the client. In the Jupyter Notebook, this magic only renders the subset
65
+ of LaTeX defined by MathJax
66
+ [here](https://docs.mathjax.org/en/v2.5-latest/tex.html)."""
67
+ display(Latex(cell))
68
+
69
+ @cell_magic
70
+ def svg(self, line, cell):
71
+ """Render the cell as an SVG literal"""
72
+ display(SVG(cell))
73
+
74
+ @magic_arguments.magic_arguments()
75
+ @magic_arguments.argument(
76
+ '--isolated', action='store_true', default=False,
77
+ help="""Annotate the cell as 'isolated'.
78
+ Isolated cells are rendered inside their own <iframe> tag"""
79
+ )
80
+ @cell_magic
81
+ def html(self, line, cell):
82
+ """Render the cell as a block of HTML"""
83
+ args = magic_arguments.parse_argstring(self.html, line)
84
+ html = HTML(cell)
85
+ if args.isolated:
86
+ display(html, metadata={'text/html':{'isolated':True}})
87
+ else:
88
+ display(html)
89
+
90
+ @cell_magic
91
+ def markdown(self, line, cell):
92
+ """Render the cell as Markdown text block"""
93
+ display(Markdown(cell))
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/execution.py ADDED
@@ -0,0 +1,1624 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """Implementation of execution-related magic functions."""
3
+
4
+ # Copyright (c) IPython Development Team.
5
+ # Distributed under the terms of the Modified BSD License.
6
+
7
+
8
+ import ast
9
+ import bdb
10
+ import builtins as builtin_mod
11
+ import copy
12
+ import cProfile as profile
13
+ import gc
14
+ import itertools
15
+ import math
16
+ import os
17
+ import pstats
18
+ import re
19
+ import shlex
20
+ import sys
21
+ import time
22
+ import timeit
23
+ from typing import Dict, Any
24
+ from ast import (
25
+ Assign,
26
+ Call,
27
+ Expr,
28
+ Load,
29
+ Module,
30
+ Name,
31
+ NodeTransformer,
32
+ Store,
33
+ parse,
34
+ unparse,
35
+ )
36
+ from io import StringIO
37
+ from logging import error
38
+ from pathlib import Path
39
+ from pdb import Restart
40
+ from textwrap import dedent, indent
41
+ from warnings import warn
42
+
43
+ from IPython.core import magic_arguments, oinspect, page
44
+ from IPython.core.displayhook import DisplayHook
45
+ from IPython.core.error import UsageError
46
+ from IPython.core.macro import Macro
47
+ from IPython.core.magic import (
48
+ Magics,
49
+ cell_magic,
50
+ line_cell_magic,
51
+ line_magic,
52
+ magics_class,
53
+ needs_local_scope,
54
+ no_var_expand,
55
+ on_off,
56
+ output_can_be_silenced,
57
+ )
58
+ from IPython.testing.skipdoctest import skip_doctest
59
+ from IPython.utils.capture import capture_output
60
+ from IPython.utils.contexts import preserve_keys
61
+ from IPython.utils.ipstruct import Struct
62
+ from IPython.utils.module_paths import find_mod
63
+ from IPython.utils.path import get_py_filename, shellglob
64
+ from IPython.utils.timing import clock, clock2
65
+ from IPython.core.magics.ast_mod import ReplaceCodeTransformer
66
+
67
+ #-----------------------------------------------------------------------------
68
+ # Magic implementation classes
69
+ #-----------------------------------------------------------------------------
70
+
71
+
72
+ class TimeitResult(object):
73
+ """
74
+ Object returned by the timeit magic with info about the run.
75
+
76
+ Contains the following attributes :
77
+
78
+ loops: (int) number of loops done per measurement
79
+ repeat: (int) number of times the measurement has been repeated
80
+ best: (float) best execution time / number
81
+ all_runs: (list of float) execution time of each run (in s)
82
+ compile_time: (float) time of statement compilation (s)
83
+
84
+ """
85
+ def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision):
86
+ self.loops = loops
87
+ self.repeat = repeat
88
+ self.best = best
89
+ self.worst = worst
90
+ self.all_runs = all_runs
91
+ self.compile_time = compile_time
92
+ self._precision = precision
93
+ self.timings = [ dt / self.loops for dt in all_runs]
94
+
95
+ @property
96
+ def average(self):
97
+ return math.fsum(self.timings) / len(self.timings)
98
+
99
+ @property
100
+ def stdev(self):
101
+ mean = self.average
102
+ return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5
103
+
104
+ def __str__(self):
105
+ pm = '+-'
106
+ if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
107
+ try:
108
+ u'\xb1'.encode(sys.stdout.encoding)
109
+ pm = u'\xb1'
110
+ except:
111
+ pass
112
+ return "{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format(
113
+ pm=pm,
114
+ runs=self.repeat,
115
+ loops=self.loops,
116
+ loop_plural="" if self.loops == 1 else "s",
117
+ run_plural="" if self.repeat == 1 else "s",
118
+ mean=_format_time(self.average, self._precision),
119
+ std=_format_time(self.stdev, self._precision),
120
+ )
121
+
122
+ def _repr_pretty_(self, p , cycle):
123
+ unic = self.__str__()
124
+ p.text(u'<TimeitResult : '+unic+u'>')
125
+
126
+
127
+ class TimeitTemplateFiller(ast.NodeTransformer):
128
+ """Fill in the AST template for timing execution.
129
+
130
+ This is quite closely tied to the template definition, which is in
131
+ :meth:`ExecutionMagics.timeit`.
132
+ """
133
+ def __init__(self, ast_setup, ast_stmt):
134
+ self.ast_setup = ast_setup
135
+ self.ast_stmt = ast_stmt
136
+
137
+ def visit_FunctionDef(self, node):
138
+ "Fill in the setup statement"
139
+ self.generic_visit(node)
140
+ if node.name == "inner":
141
+ node.body[:1] = self.ast_setup.body
142
+
143
+ return node
144
+
145
+ def visit_For(self, node):
146
+ "Fill in the statement to be timed"
147
+ if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
148
+ node.body = self.ast_stmt.body
149
+ return node
150
+
151
+
152
+ class Timer(timeit.Timer):
153
+ """Timer class that explicitly uses self.inner
154
+
155
+ which is an undocumented implementation detail of CPython,
156
+ not shared by PyPy.
157
+ """
158
+ # Timer.timeit copied from CPython 3.4.2
159
+ def timeit(self, number=timeit.default_number):
160
+ """Time 'number' executions of the main statement.
161
+
162
+ To be precise, this executes the setup statement once, and
163
+ then returns the time it takes to execute the main statement
164
+ a number of times, as a float measured in seconds. The
165
+ argument is the number of times through the loop, defaulting
166
+ to one million. The main statement, the setup statement and
167
+ the timer function to be used are passed to the constructor.
168
+ """
169
+ it = itertools.repeat(None, number)
170
+ gcold = gc.isenabled()
171
+ gc.disable()
172
+ try:
173
+ timing = self.inner(it, self.timer)
174
+ finally:
175
+ if gcold:
176
+ gc.enable()
177
+ return timing
178
+
179
+
180
+ @magics_class
181
+ class ExecutionMagics(Magics):
182
+ """Magics related to code execution, debugging, profiling, etc."""
183
+
184
+ _transformers: Dict[str, Any] = {}
185
+
186
+ def __init__(self, shell):
187
+ super(ExecutionMagics, self).__init__(shell)
188
+ # Default execution function used to actually run user code.
189
+ self.default_runner = None
190
+
191
+ @skip_doctest
192
+ @no_var_expand
193
+ @line_cell_magic
194
+ def prun(self, parameter_s='', cell=None):
195
+
196
+ """Run a statement through the python code profiler.
197
+
198
+ **Usage, in line mode:**
199
+
200
+ %prun [options] statement
201
+
202
+ **Usage, in cell mode:**
203
+
204
+ %%prun [options] [statement]
205
+
206
+ code...
207
+
208
+ code...
209
+
210
+ In cell mode, the additional code lines are appended to the (possibly
211
+ empty) statement in the first line. Cell mode allows you to easily
212
+ profile multiline blocks without having to put them in a separate
213
+ function.
214
+
215
+ The given statement (which doesn't require quote marks) is run via the
216
+ python profiler in a manner similar to the profile.run() function.
217
+ Namespaces are internally managed to work correctly; profile.run
218
+ cannot be used in IPython because it makes certain assumptions about
219
+ namespaces which do not hold under IPython.
220
+
221
+ Options:
222
+
223
+ -l <limit>
224
+ you can place restrictions on what or how much of the
225
+ profile gets printed. The limit value can be:
226
+
227
+ * A string: only information for function names containing this string
228
+ is printed.
229
+
230
+ * An integer: only these many lines are printed.
231
+
232
+ * A float (between 0 and 1): this fraction of the report is printed
233
+ (for example, use a limit of 0.4 to see the topmost 40% only).
234
+
235
+ You can combine several limits with repeated use of the option. For
236
+ example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
237
+ information about class constructors.
238
+
239
+ -r
240
+ return the pstats.Stats object generated by the profiling. This
241
+ object has all the information about the profile in it, and you can
242
+ later use it for further analysis or in other functions.
243
+
244
+ -s <key>
245
+ sort profile by given key. You can provide more than one key
246
+ by using the option several times: '-s key1 -s key2 -s key3...'. The
247
+ default sorting key is 'time'.
248
+
249
+ The following is copied verbatim from the profile documentation
250
+ referenced below:
251
+
252
+ When more than one key is provided, additional keys are used as
253
+ secondary criteria when the there is equality in all keys selected
254
+ before them.
255
+
256
+ Abbreviations can be used for any key names, as long as the
257
+ abbreviation is unambiguous. The following are the keys currently
258
+ defined:
259
+
260
+ ============ =====================
261
+ Valid Arg Meaning
262
+ ============ =====================
263
+ "calls" call count
264
+ "cumulative" cumulative time
265
+ "file" file name
266
+ "module" file name
267
+ "pcalls" primitive call count
268
+ "line" line number
269
+ "name" function name
270
+ "nfl" name/file/line
271
+ "stdname" standard name
272
+ "time" internal time
273
+ ============ =====================
274
+
275
+ Note that all sorts on statistics are in descending order (placing
276
+ most time consuming items first), where as name, file, and line number
277
+ searches are in ascending order (i.e., alphabetical). The subtle
278
+ distinction between "nfl" and "stdname" is that the standard name is a
279
+ sort of the name as printed, which means that the embedded line
280
+ numbers get compared in an odd way. For example, lines 3, 20, and 40
281
+ would (if the file names were the same) appear in the string order
282
+ "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
283
+ line numbers. In fact, sort_stats("nfl") is the same as
284
+ sort_stats("name", "file", "line").
285
+
286
+ -T <filename>
287
+ save profile results as shown on screen to a text
288
+ file. The profile is still shown on screen.
289
+
290
+ -D <filename>
291
+ save (via dump_stats) profile statistics to given
292
+ filename. This data is in a format understood by the pstats module, and
293
+ is generated by a call to the dump_stats() method of profile
294
+ objects. The profile is still shown on screen.
295
+
296
+ -q
297
+ suppress output to the pager. Best used with -T and/or -D above.
298
+
299
+ If you want to run complete programs under the profiler's control, use
300
+ ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
301
+ contains profiler specific options as described here.
302
+
303
+ You can read the complete documentation for the profile module with::
304
+
305
+ In [1]: import profile; profile.help()
306
+
307
+ .. versionchanged:: 7.3
308
+ User variables are no longer expanded,
309
+ the magic line is always left unmodified.
310
+
311
+ """
312
+ opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
313
+ list_all=True, posix=False)
314
+ if cell is not None:
315
+ arg_str += '\n' + cell
316
+ arg_str = self.shell.transform_cell(arg_str)
317
+ return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
318
+
319
+ def _run_with_profiler(self, code, opts, namespace):
320
+ """
321
+ Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
322
+
323
+ Parameters
324
+ ----------
325
+ code : str
326
+ Code to be executed.
327
+ opts : Struct
328
+ Options parsed by `self.parse_options`.
329
+ namespace : dict
330
+ A dictionary for Python namespace (e.g., `self.shell.user_ns`).
331
+
332
+ """
333
+
334
+ # Fill default values for unspecified options:
335
+ opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
336
+
337
+ prof = profile.Profile()
338
+ try:
339
+ prof = prof.runctx(code, namespace, namespace)
340
+ sys_exit = ''
341
+ except SystemExit:
342
+ sys_exit = """*** SystemExit exception caught in code being profiled."""
343
+
344
+ stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
345
+
346
+ lims = opts.l
347
+ if lims:
348
+ lims = [] # rebuild lims with ints/floats/strings
349
+ for lim in opts.l:
350
+ try:
351
+ lims.append(int(lim))
352
+ except ValueError:
353
+ try:
354
+ lims.append(float(lim))
355
+ except ValueError:
356
+ lims.append(lim)
357
+
358
+ # Trap output.
359
+ stdout_trap = StringIO()
360
+ stats_stream = stats.stream
361
+ try:
362
+ stats.stream = stdout_trap
363
+ stats.print_stats(*lims)
364
+ finally:
365
+ stats.stream = stats_stream
366
+
367
+ output = stdout_trap.getvalue()
368
+ output = output.rstrip()
369
+
370
+ if 'q' not in opts:
371
+ page.page(output)
372
+ print(sys_exit, end=' ')
373
+
374
+ dump_file = opts.D[0]
375
+ text_file = opts.T[0]
376
+ if dump_file:
377
+ prof.dump_stats(dump_file)
378
+ print(
379
+ f"\n*** Profile stats marshalled to file {repr(dump_file)}.{sys_exit}"
380
+ )
381
+ if text_file:
382
+ pfile = Path(text_file)
383
+ pfile.touch(exist_ok=True)
384
+ pfile.write_text(output, encoding="utf-8")
385
+
386
+ print(
387
+ f"\n*** Profile printout saved to text file {repr(text_file)}.{sys_exit}"
388
+ )
389
+
390
+ if 'r' in opts:
391
+ return stats
392
+
393
+ return None
394
+
395
+ @line_magic
396
+ def pdb(self, parameter_s=''):
397
+ """Control the automatic calling of the pdb interactive debugger.
398
+
399
+ Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
400
+ argument it works as a toggle.
401
+
402
+ When an exception is triggered, IPython can optionally call the
403
+ interactive pdb debugger after the traceback printout. %pdb toggles
404
+ this feature on and off.
405
+
406
+ The initial state of this feature is set in your configuration
407
+ file (the option is ``InteractiveShell.pdb``).
408
+
409
+ If you want to just activate the debugger AFTER an exception has fired,
410
+ without having to type '%pdb on' and rerunning your code, you can use
411
+ the %debug magic."""
412
+
413
+ par = parameter_s.strip().lower()
414
+
415
+ if par:
416
+ try:
417
+ new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
418
+ except KeyError:
419
+ print ('Incorrect argument. Use on/1, off/0, '
420
+ 'or nothing for a toggle.')
421
+ return
422
+ else:
423
+ # toggle
424
+ new_pdb = not self.shell.call_pdb
425
+
426
+ # set on the shell
427
+ self.shell.call_pdb = new_pdb
428
+ print('Automatic pdb calling has been turned',on_off(new_pdb))
429
+
430
+ @magic_arguments.magic_arguments()
431
+ @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
432
+ help="""
433
+ Set break point at LINE in FILE.
434
+ """
435
+ )
436
+ @magic_arguments.argument('statement', nargs='*',
437
+ help="""
438
+ Code to run in debugger.
439
+ You can omit this in cell magic mode.
440
+ """
441
+ )
442
+ @no_var_expand
443
+ @line_cell_magic
444
+ @needs_local_scope
445
+ def debug(self, line="", cell=None, local_ns=None):
446
+ """Activate the interactive debugger.
447
+
448
+ This magic command support two ways of activating debugger.
449
+ One is to activate debugger before executing code. This way, you
450
+ can set a break point, to step through the code from the point.
451
+ You can use this mode by giving statements to execute and optionally
452
+ a breakpoint.
453
+
454
+ The other one is to activate debugger in post-mortem mode. You can
455
+ activate this mode simply running %debug without any argument.
456
+ If an exception has just occurred, this lets you inspect its stack
457
+ frames interactively. Note that this will always work only on the last
458
+ traceback that occurred, so you must call this quickly after an
459
+ exception that you wish to inspect has fired, because if another one
460
+ occurs, it clobbers the previous one.
461
+
462
+ If you want IPython to automatically do this on every exception, see
463
+ the %pdb magic for more details.
464
+
465
+ .. versionchanged:: 7.3
466
+ When running code, user variables are no longer expanded,
467
+ the magic line is always left unmodified.
468
+
469
+ """
470
+ args = magic_arguments.parse_argstring(self.debug, line)
471
+
472
+ if not (args.breakpoint or args.statement or cell):
473
+ self._debug_post_mortem()
474
+ elif not (args.breakpoint or cell):
475
+ # If there is no breakpoints, the line is just code to execute
476
+ self._debug_exec(line, None, local_ns)
477
+ else:
478
+ # Here we try to reconstruct the code from the output of
479
+ # parse_argstring. This might not work if the code has spaces
480
+ # For example this fails for `print("a b")`
481
+ code = "\n".join(args.statement)
482
+ if cell:
483
+ code += "\n" + cell
484
+ self._debug_exec(code, args.breakpoint, local_ns)
485
+
486
+ def _debug_post_mortem(self):
487
+ self.shell.debugger(force=True)
488
+
489
+ def _debug_exec(self, code, breakpoint, local_ns=None):
490
+ if breakpoint:
491
+ (filename, bp_line) = breakpoint.rsplit(':', 1)
492
+ bp_line = int(bp_line)
493
+ else:
494
+ (filename, bp_line) = (None, None)
495
+ self._run_with_debugger(
496
+ code, self.shell.user_ns, filename, bp_line, local_ns=local_ns
497
+ )
498
+
499
+ @line_magic
500
+ def tb(self, s):
501
+ """Print the last traceback.
502
+
503
+ Optionally, specify an exception reporting mode, tuning the
504
+ verbosity of the traceback. By default the currently-active exception
505
+ mode is used. See %xmode for changing exception reporting modes.
506
+
507
+ Valid modes: Plain, Context, Verbose, and Minimal.
508
+ """
509
+ interactive_tb = self.shell.InteractiveTB
510
+ if s:
511
+ # Switch exception reporting mode for this one call.
512
+ # Ensure it is switched back.
513
+ def xmode_switch_err(name):
514
+ warn('Error changing %s exception modes.\n%s' %
515
+ (name,sys.exc_info()[1]))
516
+
517
+ new_mode = s.strip().capitalize()
518
+ original_mode = interactive_tb.mode
519
+ try:
520
+ try:
521
+ interactive_tb.set_mode(mode=new_mode)
522
+ except Exception:
523
+ xmode_switch_err('user')
524
+ else:
525
+ self.shell.showtraceback()
526
+ finally:
527
+ interactive_tb.set_mode(mode=original_mode)
528
+ else:
529
+ self.shell.showtraceback()
530
+
531
+ @skip_doctest
532
+ @line_magic
533
+ def run(self, parameter_s='', runner=None,
534
+ file_finder=get_py_filename):
535
+ """Run the named file inside IPython as a program.
536
+
537
+ Usage::
538
+
539
+ %run [-n -i -e -G]
540
+ [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
541
+ ( -m mod | filename ) [args]
542
+
543
+ The filename argument should be either a pure Python script (with
544
+ extension ``.py``), or a file with custom IPython syntax (such as
545
+ magics). If the latter, the file can be either a script with ``.ipy``
546
+ extension, or a Jupyter notebook with ``.ipynb`` extension. When running
547
+ a Jupyter notebook, the output from print statements and other
548
+ displayed objects will appear in the terminal (even matplotlib figures
549
+ will open, if a terminal-compliant backend is being used). Note that,
550
+ at the system command line, the ``jupyter run`` command offers similar
551
+ functionality for executing notebooks (albeit currently with some
552
+ differences in supported options).
553
+
554
+ Parameters after the filename are passed as command-line arguments to
555
+ the program (put in sys.argv). Then, control returns to IPython's
556
+ prompt.
557
+
558
+ This is similar to running at a system prompt ``python file args``,
559
+ but with the advantage of giving you IPython's tracebacks, and of
560
+ loading all variables into your interactive namespace for further use
561
+ (unless -p is used, see below).
562
+
563
+ The file is executed in a namespace initially consisting only of
564
+ ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
565
+ sees its environment as if it were being run as a stand-alone program
566
+ (except for sharing global objects such as previously imported
567
+ modules). But after execution, the IPython interactive namespace gets
568
+ updated with all variables defined in the program (except for __name__
569
+ and sys.argv). This allows for very convenient loading of code for
570
+ interactive work, while giving each program a 'clean sheet' to run in.
571
+
572
+ Arguments are expanded using shell-like glob match. Patterns
573
+ '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
574
+ tilde '~' will be expanded into user's home directory. Unlike
575
+ real shells, quotation does not suppress expansions. Use
576
+ *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
577
+ To completely disable these expansions, you can use -G flag.
578
+
579
+ On Windows systems, the use of single quotes `'` when specifying
580
+ a file is not supported. Use double quotes `"`.
581
+
582
+ Options:
583
+
584
+ -n
585
+ __name__ is NOT set to '__main__', but to the running file's name
586
+ without extension (as python does under import). This allows running
587
+ scripts and reloading the definitions in them without calling code
588
+ protected by an ``if __name__ == "__main__"`` clause.
589
+
590
+ -i
591
+ run the file in IPython's namespace instead of an empty one. This
592
+ is useful if you are experimenting with code written in a text editor
593
+ which depends on variables defined interactively.
594
+
595
+ -e
596
+ ignore sys.exit() calls or SystemExit exceptions in the script
597
+ being run. This is particularly useful if IPython is being used to
598
+ run unittests, which always exit with a sys.exit() call. In such
599
+ cases you are interested in the output of the test results, not in
600
+ seeing a traceback of the unittest module.
601
+
602
+ -t
603
+ print timing information at the end of the run. IPython will give
604
+ you an estimated CPU time consumption for your script, which under
605
+ Unix uses the resource module to avoid the wraparound problems of
606
+ time.clock(). Under Unix, an estimate of time spent on system tasks
607
+ is also given (for Windows platforms this is reported as 0.0).
608
+
609
+ If -t is given, an additional ``-N<N>`` option can be given, where <N>
610
+ must be an integer indicating how many times you want the script to
611
+ run. The final timing report will include total and per run results.
612
+
613
+ For example (testing the script uniq_stable.py)::
614
+
615
+ In [1]: run -t uniq_stable
616
+
617
+ IPython CPU timings (estimated):
618
+ User : 0.19597 s.
619
+ System: 0.0 s.
620
+
621
+ In [2]: run -t -N5 uniq_stable
622
+
623
+ IPython CPU timings (estimated):
624
+ Total runs performed: 5
625
+ Times : Total Per run
626
+ User : 0.910862 s, 0.1821724 s.
627
+ System: 0.0 s, 0.0 s.
628
+
629
+ -d
630
+ run your program under the control of pdb, the Python debugger.
631
+ This allows you to execute your program step by step, watch variables,
632
+ etc. Internally, what IPython does is similar to calling::
633
+
634
+ pdb.run('execfile("YOURFILENAME")')
635
+
636
+ with a breakpoint set on line 1 of your file. You can change the line
637
+ number for this automatic breakpoint to be <N> by using the -bN option
638
+ (where N must be an integer). For example::
639
+
640
+ %run -d -b40 myscript
641
+
642
+ will set the first breakpoint at line 40 in myscript.py. Note that
643
+ the first breakpoint must be set on a line which actually does
644
+ something (not a comment or docstring) for it to stop execution.
645
+
646
+ Or you can specify a breakpoint in a different file::
647
+
648
+ %run -d -b myotherfile.py:20 myscript
649
+
650
+ When the pdb debugger starts, you will see a (Pdb) prompt. You must
651
+ first enter 'c' (without quotes) to start execution up to the first
652
+ breakpoint.
653
+
654
+ Entering 'help' gives information about the use of the debugger. You
655
+ can easily see pdb's full documentation with "import pdb;pdb.help()"
656
+ at a prompt.
657
+
658
+ -p
659
+ run program under the control of the Python profiler module (which
660
+ prints a detailed report of execution times, function calls, etc).
661
+
662
+ You can pass other options after -p which affect the behavior of the
663
+ profiler itself. See the docs for %prun for details.
664
+
665
+ In this mode, the program's variables do NOT propagate back to the
666
+ IPython interactive namespace (because they remain in the namespace
667
+ where the profiler executes them).
668
+
669
+ Internally this triggers a call to %prun, see its documentation for
670
+ details on the options available specifically for profiling.
671
+
672
+ There is one special usage for which the text above doesn't apply:
673
+ if the filename ends with .ipy[nb], the file is run as ipython script,
674
+ just as if the commands were written on IPython prompt.
675
+
676
+ -m
677
+ specify module name to load instead of script path. Similar to
678
+ the -m option for the python interpreter. Use this option last if you
679
+ want to combine with other %run options. Unlike the python interpreter
680
+ only source modules are allowed no .pyc or .pyo files.
681
+ For example::
682
+
683
+ %run -m example
684
+
685
+ will run the example module.
686
+
687
+ -G
688
+ disable shell-like glob expansion of arguments.
689
+
690
+ """
691
+
692
+ # Logic to handle issue #3664
693
+ # Add '--' after '-m <module_name>' to ignore additional args passed to a module.
694
+ if '-m' in parameter_s and '--' not in parameter_s:
695
+ argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
696
+ for idx, arg in enumerate(argv):
697
+ if arg and arg.startswith('-') and arg != '-':
698
+ if arg == '-m':
699
+ argv.insert(idx + 2, '--')
700
+ break
701
+ else:
702
+ # Positional arg, break
703
+ break
704
+ parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
705
+
706
+ # get arguments and set sys.argv for program to be run.
707
+ opts, arg_lst = self.parse_options(parameter_s,
708
+ 'nidtN:b:pD:l:rs:T:em:G',
709
+ mode='list', list_all=1)
710
+ if "m" in opts:
711
+ modulename = opts["m"][0]
712
+ modpath = find_mod(modulename)
713
+ if modpath is None:
714
+ msg = '%r is not a valid modulename on sys.path'%modulename
715
+ raise Exception(msg)
716
+ arg_lst = [modpath] + arg_lst
717
+ try:
718
+ fpath = None # initialize to make sure fpath is in scope later
719
+ fpath = arg_lst[0]
720
+ filename = file_finder(fpath)
721
+ except IndexError as e:
722
+ msg = 'you must provide at least a filename.'
723
+ raise Exception(msg) from e
724
+ except IOError as e:
725
+ try:
726
+ msg = str(e)
727
+ except UnicodeError:
728
+ msg = e.message
729
+ if os.name == 'nt' and re.match(r"^'.*'$",fpath):
730
+ warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"')
731
+ raise Exception(msg) from e
732
+ except TypeError:
733
+ if fpath in sys.meta_path:
734
+ filename = ""
735
+ else:
736
+ raise
737
+
738
+ if filename.lower().endswith(('.ipy', '.ipynb')):
739
+ with preserve_keys(self.shell.user_ns, '__file__'):
740
+ self.shell.user_ns['__file__'] = filename
741
+ self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
742
+ return
743
+
744
+ # Control the response to exit() calls made by the script being run
745
+ exit_ignore = 'e' in opts
746
+
747
+ # Make sure that the running script gets a proper sys.argv as if it
748
+ # were run from a system shell.
749
+ save_argv = sys.argv # save it for later restoring
750
+
751
+ if 'G' in opts:
752
+ args = arg_lst[1:]
753
+ else:
754
+ # tilde and glob expansion
755
+ args = shellglob(map(os.path.expanduser, arg_lst[1:]))
756
+
757
+ sys.argv = [filename] + args # put in the proper filename
758
+
759
+ if 'n' in opts:
760
+ name = Path(filename).stem
761
+ else:
762
+ name = '__main__'
763
+
764
+ if 'i' in opts:
765
+ # Run in user's interactive namespace
766
+ prog_ns = self.shell.user_ns
767
+ __name__save = self.shell.user_ns['__name__']
768
+ prog_ns['__name__'] = name
769
+ main_mod = self.shell.user_module
770
+
771
+ # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
772
+ # set the __file__ global in the script's namespace
773
+ # TK: Is this necessary in interactive mode?
774
+ prog_ns['__file__'] = filename
775
+ else:
776
+ # Run in a fresh, empty namespace
777
+
778
+ # The shell MUST hold a reference to prog_ns so after %run
779
+ # exits, the python deletion mechanism doesn't zero it out
780
+ # (leaving dangling references). See interactiveshell for details
781
+ main_mod = self.shell.new_main_mod(filename, name)
782
+ prog_ns = main_mod.__dict__
783
+
784
+ # pickle fix. See interactiveshell for an explanation. But we need to
785
+ # make sure that, if we overwrite __main__, we replace it at the end
786
+ main_mod_name = prog_ns['__name__']
787
+
788
+ if main_mod_name == '__main__':
789
+ restore_main = sys.modules['__main__']
790
+ else:
791
+ restore_main = False
792
+
793
+ # This needs to be undone at the end to prevent holding references to
794
+ # every single object ever created.
795
+ sys.modules[main_mod_name] = main_mod
796
+
797
+ if 'p' in opts or 'd' in opts:
798
+ if 'm' in opts:
799
+ code = 'run_module(modulename, prog_ns)'
800
+ code_ns = {
801
+ 'run_module': self.shell.safe_run_module,
802
+ 'prog_ns': prog_ns,
803
+ 'modulename': modulename,
804
+ }
805
+ else:
806
+ if 'd' in opts:
807
+ # allow exceptions to raise in debug mode
808
+ code = 'execfile(filename, prog_ns, raise_exceptions=True)'
809
+ else:
810
+ code = 'execfile(filename, prog_ns)'
811
+ code_ns = {
812
+ 'execfile': self.shell.safe_execfile,
813
+ 'prog_ns': prog_ns,
814
+ 'filename': get_py_filename(filename),
815
+ }
816
+
817
+ try:
818
+ stats = None
819
+ if 'p' in opts:
820
+ stats = self._run_with_profiler(code, opts, code_ns)
821
+ else:
822
+ if 'd' in opts:
823
+ bp_file, bp_line = parse_breakpoint(
824
+ opts.get('b', ['1'])[0], filename)
825
+ self._run_with_debugger(
826
+ code, code_ns, filename, bp_line, bp_file)
827
+ else:
828
+ if 'm' in opts:
829
+ def run():
830
+ self.shell.safe_run_module(modulename, prog_ns)
831
+ else:
832
+ if runner is None:
833
+ runner = self.default_runner
834
+ if runner is None:
835
+ runner = self.shell.safe_execfile
836
+
837
+ def run():
838
+ runner(filename, prog_ns, prog_ns,
839
+ exit_ignore=exit_ignore)
840
+
841
+ if 't' in opts:
842
+ # timed execution
843
+ try:
844
+ nruns = int(opts['N'][0])
845
+ if nruns < 1:
846
+ error('Number of runs must be >=1')
847
+ return
848
+ except (KeyError):
849
+ nruns = 1
850
+ self._run_with_timing(run, nruns)
851
+ else:
852
+ # regular execution
853
+ run()
854
+
855
+ if 'i' in opts:
856
+ self.shell.user_ns['__name__'] = __name__save
857
+ else:
858
+ # update IPython interactive namespace
859
+
860
+ # Some forms of read errors on the file may mean the
861
+ # __name__ key was never set; using pop we don't have to
862
+ # worry about a possible KeyError.
863
+ prog_ns.pop('__name__', None)
864
+
865
+ with preserve_keys(self.shell.user_ns, '__file__'):
866
+ self.shell.user_ns.update(prog_ns)
867
+ finally:
868
+ # It's a bit of a mystery why, but __builtins__ can change from
869
+ # being a module to becoming a dict missing some key data after
870
+ # %run. As best I can see, this is NOT something IPython is doing
871
+ # at all, and similar problems have been reported before:
872
+ # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
873
+ # Since this seems to be done by the interpreter itself, the best
874
+ # we can do is to at least restore __builtins__ for the user on
875
+ # exit.
876
+ self.shell.user_ns['__builtins__'] = builtin_mod
877
+
878
+ # Ensure key global structures are restored
879
+ sys.argv = save_argv
880
+ if restore_main:
881
+ sys.modules['__main__'] = restore_main
882
+ if '__mp_main__' in sys.modules:
883
+ sys.modules['__mp_main__'] = restore_main
884
+ else:
885
+ # Remove from sys.modules the reference to main_mod we'd
886
+ # added. Otherwise it will trap references to objects
887
+ # contained therein.
888
+ del sys.modules[main_mod_name]
889
+
890
+ return stats
891
+
892
+ def _run_with_debugger(
893
+ self, code, code_ns, filename=None, bp_line=None, bp_file=None, local_ns=None
894
+ ):
895
+ """
896
+ Run `code` in debugger with a break point.
897
+
898
+ Parameters
899
+ ----------
900
+ code : str
901
+ Code to execute.
902
+ code_ns : dict
903
+ A namespace in which `code` is executed.
904
+ filename : str
905
+ `code` is ran as if it is in `filename`.
906
+ bp_line : int, optional
907
+ Line number of the break point.
908
+ bp_file : str, optional
909
+ Path to the file in which break point is specified.
910
+ `filename` is used if not given.
911
+ local_ns : dict, optional
912
+ A local namespace in which `code` is executed.
913
+
914
+ Raises
915
+ ------
916
+ UsageError
917
+ If the break point given by `bp_line` is not valid.
918
+
919
+ """
920
+ deb = self.shell.InteractiveTB.pdb
921
+ if not deb:
922
+ self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls()
923
+ deb = self.shell.InteractiveTB.pdb
924
+
925
+ # deb.checkline() fails if deb.curframe exists but is None; it can
926
+ # handle it not existing. https://github.com/ipython/ipython/issues/10028
927
+ if hasattr(deb, 'curframe'):
928
+ del deb.curframe
929
+
930
+ # reset Breakpoint state, which is moronically kept
931
+ # in a class
932
+ bdb.Breakpoint.next = 1
933
+ bdb.Breakpoint.bplist = {}
934
+ bdb.Breakpoint.bpbynumber = [None]
935
+ deb.clear_all_breaks()
936
+ if bp_line is not None:
937
+ # Set an initial breakpoint to stop execution
938
+ maxtries = 10
939
+ bp_file = bp_file or filename
940
+ checkline = deb.checkline(bp_file, bp_line)
941
+ if not checkline:
942
+ for bp in range(bp_line + 1, bp_line + maxtries + 1):
943
+ if deb.checkline(bp_file, bp):
944
+ break
945
+ else:
946
+ msg = ("\nI failed to find a valid line to set "
947
+ "a breakpoint\n"
948
+ "after trying up to line: %s.\n"
949
+ "Please set a valid breakpoint manually "
950
+ "with the -b option." % bp)
951
+ raise UsageError(msg)
952
+ # if we find a good linenumber, set the breakpoint
953
+ deb.do_break('%s:%s' % (bp_file, bp_line))
954
+
955
+ if filename:
956
+ # Mimic Pdb._runscript(...)
957
+ deb._wait_for_mainpyfile = True
958
+ deb.mainpyfile = deb.canonic(filename)
959
+
960
+ # Start file run
961
+ print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
962
+ try:
963
+ if filename:
964
+ # save filename so it can be used by methods on the deb object
965
+ deb._exec_filename = filename
966
+ while True:
967
+ try:
968
+ trace = sys.gettrace()
969
+ deb.run(code, code_ns, local_ns)
970
+ except Restart:
971
+ print("Restarting")
972
+ if filename:
973
+ deb._wait_for_mainpyfile = True
974
+ deb.mainpyfile = deb.canonic(filename)
975
+ continue
976
+ else:
977
+ break
978
+ finally:
979
+ sys.settrace(trace)
980
+
981
+
982
+ except:
983
+ etype, value, tb = sys.exc_info()
984
+ # Skip three frames in the traceback: the %run one,
985
+ # one inside bdb.py, and the command-line typed by the
986
+ # user (run by exec in pdb itself).
987
+ self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
988
+
989
+ @staticmethod
990
+ def _run_with_timing(run, nruns):
991
+ """
992
+ Run function `run` and print timing information.
993
+
994
+ Parameters
995
+ ----------
996
+ run : callable
997
+ Any callable object which takes no argument.
998
+ nruns : int
999
+ Number of times to execute `run`.
1000
+
1001
+ """
1002
+ twall0 = time.perf_counter()
1003
+ if nruns == 1:
1004
+ t0 = clock2()
1005
+ run()
1006
+ t1 = clock2()
1007
+ t_usr = t1[0] - t0[0]
1008
+ t_sys = t1[1] - t0[1]
1009
+ print("\nIPython CPU timings (estimated):")
1010
+ print(" User : %10.2f s." % t_usr)
1011
+ print(" System : %10.2f s." % t_sys)
1012
+ else:
1013
+ runs = range(nruns)
1014
+ t0 = clock2()
1015
+ for nr in runs:
1016
+ run()
1017
+ t1 = clock2()
1018
+ t_usr = t1[0] - t0[0]
1019
+ t_sys = t1[1] - t0[1]
1020
+ print("\nIPython CPU timings (estimated):")
1021
+ print("Total runs performed:", nruns)
1022
+ print(" Times : %10s %10s" % ('Total', 'Per run'))
1023
+ print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
1024
+ print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
1025
+ twall1 = time.perf_counter()
1026
+ print("Wall time: %10.2f s." % (twall1 - twall0))
1027
+
1028
+ @skip_doctest
1029
+ @no_var_expand
1030
+ @line_cell_magic
1031
+ @needs_local_scope
1032
+ def timeit(self, line='', cell=None, local_ns=None):
1033
+ """Time execution of a Python statement or expression
1034
+
1035
+ **Usage, in line mode:**
1036
+
1037
+ %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
1038
+
1039
+ **or in cell mode:**
1040
+
1041
+ %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
1042
+
1043
+ code
1044
+
1045
+ code...
1046
+
1047
+ Time execution of a Python statement or expression using the timeit
1048
+ module. This function can be used both as a line and cell magic:
1049
+
1050
+ - In line mode you can time a single-line statement (though multiple
1051
+ ones can be chained with using semicolons).
1052
+
1053
+ - In cell mode, the statement in the first line is used as setup code
1054
+ (executed but not timed) and the body of the cell is timed. The cell
1055
+ body has access to any variables created in the setup code.
1056
+
1057
+ Options:
1058
+
1059
+ -n<N>: execute the given statement <N> times in a loop. If <N> is not
1060
+ provided, <N> is determined so as to get sufficient accuracy.
1061
+
1062
+ -r<R>: number of repeats <R>, each consisting of <N> loops, and take the
1063
+ average result.
1064
+ Default: 7
1065
+
1066
+ -t: use time.time to measure the time, which is the default on Unix.
1067
+ This function measures wall time.
1068
+
1069
+ -c: use time.clock to measure the time, which is the default on
1070
+ Windows and measures wall time. On Unix, resource.getrusage is used
1071
+ instead and returns the CPU user time.
1072
+
1073
+ -p<P>: use a precision of <P> digits to display the timing result.
1074
+ Default: 3
1075
+
1076
+ -q: Quiet, do not print result.
1077
+
1078
+ -o: return a TimeitResult that can be stored in a variable to inspect
1079
+ the result in more details.
1080
+
1081
+ .. versionchanged:: 7.3
1082
+ User variables are no longer expanded,
1083
+ the magic line is always left unmodified.
1084
+
1085
+ Examples
1086
+ --------
1087
+ ::
1088
+
1089
+ In [1]: %timeit pass
1090
+ 8.26 ns ± 0.12 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
1091
+
1092
+ In [2]: u = None
1093
+
1094
+ In [3]: %timeit u is None
1095
+ 29.9 ns ± 0.643 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
1096
+
1097
+ In [4]: %timeit -r 4 u == None
1098
+
1099
+ In [5]: import time
1100
+
1101
+ In [6]: %timeit -n1 time.sleep(2)
1102
+
1103
+ The times reported by %timeit will be slightly higher than those
1104
+ reported by the timeit.py script when variables are accessed. This is
1105
+ due to the fact that %timeit executes the statement in the namespace
1106
+ of the shell, compared with timeit.py, which uses a single setup
1107
+ statement to import function or create variables. Generally, the bias
1108
+ does not matter as long as results from timeit.py are not mixed with
1109
+ those from %timeit."""
1110
+
1111
+ opts, stmt = self.parse_options(
1112
+ line, "n:r:tcp:qo", posix=False, strict=False, preserve_non_opts=True
1113
+ )
1114
+ if stmt == "" and cell is None:
1115
+ return
1116
+
1117
+ timefunc = timeit.default_timer
1118
+ number = int(getattr(opts, "n", 0))
1119
+ default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
1120
+ repeat = int(getattr(opts, "r", default_repeat))
1121
+ precision = int(getattr(opts, "p", 3))
1122
+ quiet = 'q' in opts
1123
+ return_result = 'o' in opts
1124
+ if hasattr(opts, "t"):
1125
+ timefunc = time.time
1126
+ if hasattr(opts, "c"):
1127
+ timefunc = clock
1128
+
1129
+ timer = Timer(timer=timefunc)
1130
+ # this code has tight coupling to the inner workings of timeit.Timer,
1131
+ # but is there a better way to achieve that the code stmt has access
1132
+ # to the shell namespace?
1133
+ transform = self.shell.transform_cell
1134
+
1135
+ if cell is None:
1136
+ # called as line magic
1137
+ ast_setup = self.shell.compile.ast_parse("pass")
1138
+ ast_stmt = self.shell.compile.ast_parse(transform(stmt))
1139
+ else:
1140
+ ast_setup = self.shell.compile.ast_parse(transform(stmt))
1141
+ ast_stmt = self.shell.compile.ast_parse(transform(cell))
1142
+
1143
+ ast_setup = self.shell.transform_ast(ast_setup)
1144
+ ast_stmt = self.shell.transform_ast(ast_stmt)
1145
+
1146
+ # Check that these compile to valid Python code *outside* the timer func
1147
+ # Invalid code may become valid when put inside the function & loop,
1148
+ # which messes up error messages.
1149
+ # https://github.com/ipython/ipython/issues/10636
1150
+ self.shell.compile(ast_setup, "<magic-timeit-setup>", "exec")
1151
+ self.shell.compile(ast_stmt, "<magic-timeit-stmt>", "exec")
1152
+
1153
+ # This codestring is taken from timeit.template - we fill it in as an
1154
+ # AST, so that we can apply our AST transformations to the user code
1155
+ # without affecting the timing code.
1156
+ timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
1157
+ ' setup\n'
1158
+ ' _t0 = _timer()\n'
1159
+ ' for _i in _it:\n'
1160
+ ' stmt\n'
1161
+ ' _t1 = _timer()\n'
1162
+ ' return _t1 - _t0\n')
1163
+
1164
+ timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
1165
+ timeit_ast = ast.fix_missing_locations(timeit_ast)
1166
+
1167
+ # Track compilation time so it can be reported if too long
1168
+ # Minimum time above which compilation time will be reported
1169
+ tc_min = 0.1
1170
+
1171
+ t0 = clock()
1172
+ code = self.shell.compile(timeit_ast, "<magic-timeit>", "exec")
1173
+ tc = clock()-t0
1174
+
1175
+ ns = {}
1176
+ glob = self.shell.user_ns
1177
+ # handles global vars with same name as local vars. We store them in conflict_globs.
1178
+ conflict_globs = {}
1179
+ if local_ns and cell is None:
1180
+ for var_name, var_val in glob.items():
1181
+ if var_name in local_ns:
1182
+ conflict_globs[var_name] = var_val
1183
+ glob.update(local_ns)
1184
+
1185
+ exec(code, glob, ns)
1186
+ timer.inner = ns["inner"]
1187
+
1188
+ # This is used to check if there is a huge difference between the
1189
+ # best and worst timings.
1190
+ # Issue: https://github.com/ipython/ipython/issues/6471
1191
+ if number == 0:
1192
+ # determine number so that 0.2 <= total time < 2.0
1193
+ for index in range(0, 10):
1194
+ number = 10 ** index
1195
+ time_number = timer.timeit(number)
1196
+ if time_number >= 0.2:
1197
+ break
1198
+
1199
+ all_runs = timer.repeat(repeat, number)
1200
+ best = min(all_runs) / number
1201
+ worst = max(all_runs) / number
1202
+ timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision)
1203
+
1204
+ # Restore global vars from conflict_globs
1205
+ if conflict_globs:
1206
+ glob.update(conflict_globs)
1207
+
1208
+ if not quiet :
1209
+ # Check best timing is greater than zero to avoid a
1210
+ # ZeroDivisionError.
1211
+ # In cases where the slowest timing is lesser than a microsecond
1212
+ # we assume that it does not really matter if the fastest
1213
+ # timing is 4 times faster than the slowest timing or not.
1214
+ if worst > 4 * best and best > 0 and worst > 1e-6:
1215
+ print("The slowest run took %0.2f times longer than the "
1216
+ "fastest. This could mean that an intermediate result "
1217
+ "is being cached." % (worst / best))
1218
+
1219
+ print( timeit_result )
1220
+
1221
+ if tc > tc_min:
1222
+ print("Compiler time: %.2f s" % tc)
1223
+ if return_result:
1224
+ return timeit_result
1225
+
1226
+ @skip_doctest
1227
+ @no_var_expand
1228
+ @needs_local_scope
1229
+ @line_cell_magic
1230
+ @output_can_be_silenced
1231
+ def time(self,line='', cell=None, local_ns=None):
1232
+ """Time execution of a Python statement or expression.
1233
+
1234
+ The CPU and wall clock times are printed, and the value of the
1235
+ expression (if any) is returned. Note that under Win32, system time
1236
+ is always reported as 0, since it can not be measured.
1237
+
1238
+ This function can be used both as a line and cell magic:
1239
+
1240
+ - In line mode you can time a single-line statement (though multiple
1241
+ ones can be chained with using semicolons).
1242
+
1243
+ - In cell mode, you can time the cell body (a directly
1244
+ following statement raises an error).
1245
+
1246
+ This function provides very basic timing functionality. Use the timeit
1247
+ magic for more control over the measurement.
1248
+
1249
+ .. versionchanged:: 7.3
1250
+ User variables are no longer expanded,
1251
+ the magic line is always left unmodified.
1252
+
1253
+ Examples
1254
+ --------
1255
+ ::
1256
+
1257
+ In [1]: %time 2**128
1258
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1259
+ Wall time: 0.00
1260
+ Out[1]: 340282366920938463463374607431768211456L
1261
+
1262
+ In [2]: n = 1000000
1263
+
1264
+ In [3]: %time sum(range(n))
1265
+ CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1266
+ Wall time: 1.37
1267
+ Out[3]: 499999500000L
1268
+
1269
+ In [4]: %time print('hello world')
1270
+ hello world
1271
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1272
+ Wall time: 0.00
1273
+
1274
+ .. note::
1275
+ The time needed by Python to compile the given expression will be
1276
+ reported if it is more than 0.1s.
1277
+
1278
+ In the example below, the actual exponentiation is done by Python
1279
+ at compilation time, so while the expression can take a noticeable
1280
+ amount of time to compute, that time is purely due to the
1281
+ compilation::
1282
+
1283
+ In [5]: %time 3**9999;
1284
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1285
+ Wall time: 0.00 s
1286
+
1287
+ In [6]: %time 3**999999;
1288
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1289
+ Wall time: 0.00 s
1290
+ Compiler : 0.78 s
1291
+ """
1292
+ # fail immediately if the given expression can't be compiled
1293
+
1294
+ if line and cell:
1295
+ raise UsageError("Can't use statement directly after '%%time'!")
1296
+
1297
+ if cell:
1298
+ expr = self.shell.transform_cell(cell)
1299
+ else:
1300
+ expr = self.shell.transform_cell(line)
1301
+
1302
+ # Minimum time above which parse time will be reported
1303
+ tp_min = 0.1
1304
+
1305
+ t0 = clock()
1306
+ expr_ast = self.shell.compile.ast_parse(expr)
1307
+ tp = clock()-t0
1308
+
1309
+ # Apply AST transformations
1310
+ expr_ast = self.shell.transform_ast(expr_ast)
1311
+
1312
+ # Minimum time above which compilation time will be reported
1313
+ tc_min = 0.1
1314
+
1315
+ expr_val=None
1316
+ if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1317
+ mode = 'eval'
1318
+ source = '<timed eval>'
1319
+ expr_ast = ast.Expression(expr_ast.body[0].value)
1320
+ else:
1321
+ mode = 'exec'
1322
+ source = '<timed exec>'
1323
+ # multi-line %%time case
1324
+ if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
1325
+ expr_val= expr_ast.body[-1]
1326
+ expr_ast = expr_ast.body[:-1]
1327
+ expr_ast = Module(expr_ast, [])
1328
+ expr_val = ast.Expression(expr_val.value)
1329
+
1330
+ t0 = clock()
1331
+ code = self.shell.compile(expr_ast, source, mode)
1332
+ tc = clock()-t0
1333
+
1334
+ # skew measurement as little as possible
1335
+ glob = self.shell.user_ns
1336
+ wtime = time.time
1337
+ # time execution
1338
+ wall_st = wtime()
1339
+ if mode=='eval':
1340
+ st = clock2()
1341
+ try:
1342
+ out = eval(code, glob, local_ns)
1343
+ except:
1344
+ self.shell.showtraceback()
1345
+ return
1346
+ end = clock2()
1347
+ else:
1348
+ st = clock2()
1349
+ try:
1350
+ exec(code, glob, local_ns)
1351
+ out=None
1352
+ # multi-line %%time case
1353
+ if expr_val is not None:
1354
+ code_2 = self.shell.compile(expr_val, source, 'eval')
1355
+ out = eval(code_2, glob, local_ns)
1356
+ except:
1357
+ self.shell.showtraceback()
1358
+ return
1359
+ end = clock2()
1360
+
1361
+ wall_end = wtime()
1362
+ # Compute actual times and report
1363
+ wall_time = wall_end - wall_st
1364
+ cpu_user = end[0] - st[0]
1365
+ cpu_sys = end[1] - st[1]
1366
+ cpu_tot = cpu_user + cpu_sys
1367
+ # On windows cpu_sys is always zero, so only total is displayed
1368
+ if sys.platform != "win32":
1369
+ print(
1370
+ f"CPU times: user {_format_time(cpu_user)}, sys: {_format_time(cpu_sys)}, total: {_format_time(cpu_tot)}"
1371
+ )
1372
+ else:
1373
+ print(f"CPU times: total: {_format_time(cpu_tot)}")
1374
+ print(f"Wall time: {_format_time(wall_time)}")
1375
+ if tc > tc_min:
1376
+ print(f"Compiler : {_format_time(tc)}")
1377
+ if tp > tp_min:
1378
+ print(f"Parser : {_format_time(tp)}")
1379
+ return out
1380
+
1381
+ @skip_doctest
1382
+ @line_magic
1383
+ def macro(self, parameter_s=''):
1384
+ """Define a macro for future re-execution. It accepts ranges of history,
1385
+ filenames or string objects.
1386
+
1387
+ Usage:\\
1388
+ %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1389
+
1390
+ Options:
1391
+
1392
+ -r: use 'raw' input. By default, the 'processed' history is used,
1393
+ so that magics are loaded in their transformed version to valid
1394
+ Python. If this option is given, the raw input as typed at the
1395
+ command line is used instead.
1396
+
1397
+ -q: quiet macro definition. By default, a tag line is printed
1398
+ to indicate the macro has been created, and then the contents of
1399
+ the macro are printed. If this option is given, then no printout
1400
+ is produced once the macro is created.
1401
+
1402
+ This will define a global variable called `name` which is a string
1403
+ made of joining the slices and lines you specify (n1,n2,... numbers
1404
+ above) from your input history into a single string. This variable
1405
+ acts like an automatic function which re-executes those lines as if
1406
+ you had typed them. You just type 'name' at the prompt and the code
1407
+ executes.
1408
+
1409
+ The syntax for indicating input ranges is described in %history.
1410
+
1411
+ Note: as a 'hidden' feature, you can also use traditional python slice
1412
+ notation, where N:M means numbers N through M-1.
1413
+
1414
+ For example, if your history contains (print using %hist -n )::
1415
+
1416
+ 44: x=1
1417
+ 45: y=3
1418
+ 46: z=x+y
1419
+ 47: print(x)
1420
+ 48: a=5
1421
+ 49: print('x',x,'y',y)
1422
+
1423
+ you can create a macro with lines 44 through 47 (included) and line 49
1424
+ called my_macro with::
1425
+
1426
+ In [55]: %macro my_macro 44-47 49
1427
+
1428
+ Now, typing `my_macro` (without quotes) will re-execute all this code
1429
+ in one pass.
1430
+
1431
+ You don't need to give the line-numbers in order, and any given line
1432
+ number can appear multiple times. You can assemble macros with any
1433
+ lines from your input history in any order.
1434
+
1435
+ The macro is a simple object which holds its value in an attribute,
1436
+ but IPython's display system checks for macros and executes them as
1437
+ code instead of printing them when you type their name.
1438
+
1439
+ You can view a macro's contents by explicitly printing it with::
1440
+
1441
+ print(macro_name)
1442
+
1443
+ """
1444
+ opts,args = self.parse_options(parameter_s,'rq',mode='list')
1445
+ if not args: # List existing macros
1446
+ return sorted(k for k,v in self.shell.user_ns.items() if isinstance(v, Macro))
1447
+ if len(args) == 1:
1448
+ raise UsageError(
1449
+ "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1450
+ name, codefrom = args[0], " ".join(args[1:])
1451
+
1452
+ # print('rng',ranges) # dbg
1453
+ try:
1454
+ lines = self.shell.find_user_code(codefrom, 'r' in opts)
1455
+ except (ValueError, TypeError) as e:
1456
+ print(e.args[0])
1457
+ return
1458
+ macro = Macro(lines)
1459
+ self.shell.define_macro(name, macro)
1460
+ if not ( 'q' in opts) :
1461
+ print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1462
+ print('=== Macro contents: ===')
1463
+ print(macro, end=' ')
1464
+
1465
+ @magic_arguments.magic_arguments()
1466
+ @magic_arguments.argument('output', type=str, default='', nargs='?',
1467
+ help="""The name of the variable in which to store output.
1468
+ This is a utils.io.CapturedIO object with stdout/err attributes
1469
+ for the text of the captured output.
1470
+
1471
+ CapturedOutput also has a show() method for displaying the output,
1472
+ and __call__ as well, so you can use that to quickly display the
1473
+ output.
1474
+
1475
+ If unspecified, captured output is discarded.
1476
+ """
1477
+ )
1478
+ @magic_arguments.argument('--no-stderr', action="store_true",
1479
+ help="""Don't capture stderr."""
1480
+ )
1481
+ @magic_arguments.argument('--no-stdout', action="store_true",
1482
+ help="""Don't capture stdout."""
1483
+ )
1484
+ @magic_arguments.argument('--no-display', action="store_true",
1485
+ help="""Don't capture IPython's rich display."""
1486
+ )
1487
+ @cell_magic
1488
+ def capture(self, line, cell):
1489
+ """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1490
+ args = magic_arguments.parse_argstring(self.capture, line)
1491
+ out = not args.no_stdout
1492
+ err = not args.no_stderr
1493
+ disp = not args.no_display
1494
+ with capture_output(out, err, disp) as io:
1495
+ self.shell.run_cell(cell)
1496
+ if DisplayHook.semicolon_at_end_of_expression(cell):
1497
+ if args.output in self.shell.user_ns:
1498
+ del self.shell.user_ns[args.output]
1499
+ elif args.output:
1500
+ self.shell.user_ns[args.output] = io
1501
+
1502
+ @skip_doctest
1503
+ @magic_arguments.magic_arguments()
1504
+ @magic_arguments.argument("name", type=str, default="default", nargs="?")
1505
+ @magic_arguments.argument(
1506
+ "--remove", action="store_true", help="remove the current transformer"
1507
+ )
1508
+ @magic_arguments.argument(
1509
+ "--list", action="store_true", help="list existing transformers name"
1510
+ )
1511
+ @magic_arguments.argument(
1512
+ "--list-all",
1513
+ action="store_true",
1514
+ help="list existing transformers name and code template",
1515
+ )
1516
+ @line_cell_magic
1517
+ def code_wrap(self, line, cell=None):
1518
+ """
1519
+ Simple magic to quickly define a code transformer for all IPython's future input.
1520
+
1521
+ ``__code__`` and ``__ret__`` are special variable that represent the code to run
1522
+ and the value of the last expression of ``__code__`` respectively.
1523
+
1524
+ Examples
1525
+ --------
1526
+
1527
+ .. ipython::
1528
+
1529
+ In [1]: %%code_wrap before_after
1530
+ ...: print('before')
1531
+ ...: __code__
1532
+ ...: print('after')
1533
+ ...: __ret__
1534
+
1535
+
1536
+ In [2]: 1
1537
+ before
1538
+ after
1539
+ Out[2]: 1
1540
+
1541
+ In [3]: %code_wrap --list
1542
+ before_after
1543
+
1544
+ In [4]: %code_wrap --list-all
1545
+ before_after :
1546
+ print('before')
1547
+ __code__
1548
+ print('after')
1549
+ __ret__
1550
+
1551
+ In [5]: %code_wrap --remove before_after
1552
+
1553
+ """
1554
+ args = magic_arguments.parse_argstring(self.code_wrap, line)
1555
+
1556
+ if args.list:
1557
+ for name in self._transformers.keys():
1558
+ print(name)
1559
+ return
1560
+ if args.list_all:
1561
+ for name, _t in self._transformers.items():
1562
+ print(name, ":")
1563
+ print(indent(ast.unparse(_t.template), " "))
1564
+ print()
1565
+ return
1566
+
1567
+ to_remove = self._transformers.pop(args.name, None)
1568
+ if to_remove in self.shell.ast_transformers:
1569
+ self.shell.ast_transformers.remove(to_remove)
1570
+ if cell is None or args.remove:
1571
+ return
1572
+
1573
+ _trs = ReplaceCodeTransformer(ast.parse(cell))
1574
+
1575
+ self._transformers[args.name] = _trs
1576
+ self.shell.ast_transformers.append(_trs)
1577
+
1578
+
1579
+ def parse_breakpoint(text, current_file):
1580
+ '''Returns (file, line) for file:line and (current_file, line) for line'''
1581
+ colon = text.find(':')
1582
+ if colon == -1:
1583
+ return current_file, int(text)
1584
+ else:
1585
+ return text[:colon], int(text[colon+1:])
1586
+
1587
+ def _format_time(timespan, precision=3):
1588
+ """Formats the timespan in a human readable form"""
1589
+
1590
+ if timespan >= 60.0:
1591
+ # we have more than a minute, format that in a human readable form
1592
+ # Idea from http://snipplr.com/view/5713/
1593
+ parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1594
+ time = []
1595
+ leftover = timespan
1596
+ for suffix, length in parts:
1597
+ value = int(leftover / length)
1598
+ if value > 0:
1599
+ leftover = leftover % length
1600
+ time.append(u'%s%s' % (str(value), suffix))
1601
+ if leftover < 1:
1602
+ break
1603
+ return " ".join(time)
1604
+
1605
+
1606
+ # Unfortunately characters outside of range(128) can cause problems in
1607
+ # certain terminals.
1608
+ # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1609
+ # Try to prevent crashes by being more secure than it needs to
1610
+ # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
1611
+ units = ["s", "ms", "us", "ns"] # the safe value
1612
+ if hasattr(sys.stdout, "encoding") and sys.stdout.encoding:
1613
+ try:
1614
+ "μ".encode(sys.stdout.encoding)
1615
+ units = ["s", "ms", "μs", "ns"]
1616
+ except:
1617
+ pass
1618
+ scaling = [1, 1e3, 1e6, 1e9]
1619
+
1620
+ if timespan > 0.0:
1621
+ order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1622
+ else:
1623
+ order = 3
1624
+ return "%.*g %s" % (precision, timespan * scaling[order], units[order])