kaggle-prep 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: kaggle-prep
3
+ Version: 0.1.0
4
+ Summary: One-command Kaggle dataset preparation & analysis tool
5
+ Author-email: Sumit Gavali <sumitrg0007@gmail.com>
6
+ License: MIT
7
+ Keywords: kaggle,data-science,cli,automation
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: pandas>=1.3.0
19
+ Requires-Dist: kaggle>=1.5.0
20
+ Requires-Dist: matplotlib>=3.4.0
21
+ Requires-Dist: seaborn>=0.11.0
22
+ Requires-Dist: numpy>=1.21.0
23
+ Dynamic: license-file
24
+
25
+ # Kaggle Prep
26
+
27
+ > **One command to download, profile, visualize, and prepare any Kaggle dataset!**
28
+
29
+ ## Features
30
+
31
+ - Download any Kaggle dataset
32
+ - Profile your data instantly
33
+ - Generate beautiful HTML reports
34
+ - Create 10+ EDA visualizations
35
+ - Auto-generate preprocessing code
36
+ - Create starter Jupyter notebooks
37
+
38
+ ## Quick Start
39
+
40
+ ```bash
41
+ # Install
42
+ pip install kaggle-prep
43
+
44
+ # Setup credentials
45
+ kaggle-prep --setup
46
+
47
+ # Download a dataset
48
+ kaggle-prep uciml/iris
49
+
50
+ # Full analysis
51
+ kaggle-prep uciml/iris --profile --report --visualize --preprocess --notebook
@@ -0,0 +1,27 @@
1
+ # Kaggle Prep
2
+
3
+ > **One command to download, profile, visualize, and prepare any Kaggle dataset!**
4
+
5
+ ## Features
6
+
7
+ - Download any Kaggle dataset
8
+ - Profile your data instantly
9
+ - Generate beautiful HTML reports
10
+ - Create 10+ EDA visualizations
11
+ - Auto-generate preprocessing code
12
+ - Create starter Jupyter notebooks
13
+
14
+ ## Quick Start
15
+
16
+ ```bash
17
+ # Install
18
+ pip install kaggle-prep
19
+
20
+ # Setup credentials
21
+ kaggle-prep --setup
22
+
23
+ # Download a dataset
24
+ kaggle-prep uciml/iris
25
+
26
+ # Full analysis
27
+ kaggle-prep uciml/iris --profile --report --visualize --preprocess --notebook
@@ -0,0 +1,18 @@
1
+ __version__="0.1.0"
2
+ __author__="Sumit Gavali"
3
+ __email__="Sumitrg0007@gmail.com"
4
+
5
+ from .cli import main
6
+ from .profiler import DataProfiler
7
+ from .report import generate_standalone_report
8
+ from .visualizer import generate_eda_plots
9
+ from .notebook import generate_notebook
10
+
11
+ __version__ = "0.1.0"
12
+ __all__ = [
13
+ 'main',
14
+ 'DataProfiler',
15
+ 'generate_standalone_report',
16
+ 'generate_eda_plots',
17
+ 'generate_notebook'
18
+ ]
@@ -0,0 +1,451 @@
1
+ import argparse
2
+ from pathlib import Path
3
+ import os
4
+ import profile
5
+ import time
6
+ import pandas as pd
7
+ from kaggle.api.kaggle_api_extended import KaggleApi
8
+ from .notebook import generate_notebook
9
+ from .visualizer import generate_eda_plots, generate_preprocessing_code
10
+
11
+ # Import our custom profiler and report generator
12
+ from .profiler import DataProfiler, save_profile_json, print_profile_summary
13
+ from .report import generate_standalone_report
14
+
15
+
16
+ # ============================================================
17
+ # FUNCTION 1: Parse Arguments
18
+ # ============================================================
19
+ def parse_arguments():
20
+ """Parse and return command line arguments"""
21
+ parser = argparse.ArgumentParser(
22
+ description="Prepare Kaggle datasets for data analysis."
23
+ )
24
+
25
+ parser.add_argument(
26
+ "dataset",
27
+ help="Kaggle dataset identifier, e.g. adyen/dabstep-benchmark"
28
+ )
29
+
30
+ parser.add_argument(
31
+ "--output-dir",
32
+ default="data",
33
+ help="Directory to save downloaded data (default: data)"
34
+ )
35
+ parser.add_argument(
36
+ "--notebook",
37
+ action="store_true",
38
+ help="Generate a Jupyter notebook with EDA and preprocessing code"
39
+ )
40
+ parser.add_argument(
41
+ "--verbose",
42
+ action="store_true",
43
+ help="Enable verbose output for debugging"
44
+ )
45
+ parser.add_argument(
46
+ "--local",
47
+ action="store_true",
48
+ help="Use existing data - works with --profile, --report, etc"
49
+ )
50
+
51
+
52
+ parser.add_argument(
53
+ "--competition",
54
+ action="store_true",
55
+ help="Download from competition instead of dataset"
56
+ )
57
+
58
+ parser.add_argument(
59
+ "--profile",
60
+ action="store_true",
61
+ help="Generate data profile after download"
62
+ )
63
+
64
+ parser.add_argument(
65
+ "--report",
66
+ action="store_true",
67
+ help="Generate a standalone HTML report after download"
68
+ )
69
+ parser.add_argument(
70
+ "--visualize",
71
+ action="store_true",
72
+ help="generate EDA visualization (plots)"
73
+ )
74
+ parser.add_argument(
75
+ "--preprocess",
76
+ action="store_true",
77
+ help="generate preprocessing code"
78
+ )
79
+
80
+ return parser.parse_args()
81
+
82
+
83
+ # ============================================================
84
+ # FUNCTION 2: Display Initial Info
85
+ # ============================================================
86
+ def display_startup_info(args):
87
+ """Display startup information"""
88
+ if args.verbose:
89
+ print(f"šŸ“¦ Dataset: {args.dataset}")
90
+ print(f"šŸ“ Output directory: {args.output_dir}")
91
+ if args.competition:
92
+ print(f"šŸ† Competition mode enabled")
93
+
94
+
95
+ # ============================================================
96
+ # FUNCTION 3: Check Credentials
97
+ # ============================================================
98
+ def check_credentials(verbose=False):
99
+ """Check if Kaggle credentials exist"""
100
+ kaggle_dir = Path.home() / ".kaggle"
101
+ kaggle_json = kaggle_dir / "kaggle.json"
102
+
103
+ if not kaggle_json.exists():
104
+ print(f"āŒ Kaggle credentials not found at: {kaggle_json}")
105
+ print("\nšŸ“ To get credentials:")
106
+ print(" 1. Go to https://www.kaggle.com/settings/api")
107
+ print(" 2. Click 'Create New Token'")
108
+ print(f" 3. Save kaggle.json to: {kaggle_dir}")
109
+ return None
110
+
111
+ if verbose:
112
+ print(f"āœ… Found Kaggle credentials at: {kaggle_json}")
113
+
114
+ return kaggle_dir
115
+
116
+
117
+ # ============================================================
118
+ # FUNCTION 4: Authenticate
119
+ # ============================================================
120
+ def authenticate_kaggle(kaggle_dir, verbose=False):
121
+ """Authenticate with Kaggle API"""
122
+ print(f"šŸ”„ Authenticating with Kaggle API...")
123
+
124
+ try:
125
+ os.environ['KAGGLE_CONFIG_DIR'] = str(kaggle_dir)
126
+ api = KaggleApi()
127
+ api.authenticate()
128
+
129
+ if verbose:
130
+ print(f"āœ… Authentication successful!")
131
+
132
+ return api
133
+
134
+ except Exception as e:
135
+ print(f"āŒ Authentication error: {e}")
136
+ print("\nšŸ” Troubleshooting:")
137
+ print(" 1. Make sure kaggle.json is not empty")
138
+ print(" 2. Try re-downloading from Kaggle settings")
139
+ print(" 3. Check your internet connection")
140
+ return None
141
+
142
+
143
+ # ============================================================
144
+ # FUNCTION 5: Create Output Directory
145
+ # ============================================================
146
+ def create_output_directory(output_dir):
147
+ """Create output directory if it doesn't exist"""
148
+ output_path = Path(output_dir)
149
+ output_path.mkdir(parents=True, exist_ok=True)
150
+ return output_path
151
+
152
+
153
+ # ============================================================
154
+ # FUNCTION 6: Format File Size
155
+ # ============================================================
156
+ def format_file_size(size_bytes):
157
+ """Convert bytes to human-readable format"""
158
+ if size_bytes > 1024 * 1024 * 1024: # GB
159
+ return f"{size_bytes/(1024*1024*1024):.2f} GB"
160
+ elif size_bytes > 1024 * 1024: # MB
161
+ return f"{size_bytes/(1024*1024):.1f} MB"
162
+ elif size_bytes > 1024: # KB
163
+ return f"{size_bytes/1024:.1f} KB"
164
+ else:
165
+ return f"{size_bytes} bytes"
166
+
167
+
168
+ # ============================================================
169
+ # FUNCTION 7: List Files
170
+ # ============================================================
171
+ def list_downloaded_files(output_path):
172
+ """List all downloaded files with sizes"""
173
+ print("\nšŸ“„ Downloaded files:")
174
+
175
+ files = list(output_path.rglob("*"))
176
+ if not files:
177
+ print(" No files found!")
178
+ return
179
+
180
+ for file in files:
181
+ if file.is_file():
182
+ size = file.stat().st_size
183
+ size_str = format_file_size(size)
184
+ print(f" - {file.name} ({size_str})")
185
+
186
+
187
+ # ============================================================
188
+ # FUNCTION 8: Load First CSV
189
+ # ============================================================
190
+ def load_first_csv(data_path):
191
+ """Load the first CSV file found in the directory"""
192
+ csv_files = list(Path(data_path).rglob("*.csv"))
193
+
194
+ if not csv_files:
195
+ print("āŒ No CSV files found to profile!")
196
+ return None
197
+
198
+ try:
199
+ df = pd.read_csv(csv_files[0])
200
+ print(f"šŸ“„ Loaded: {csv_files[0].name} ({len(df):,} rows, {len(df.columns)} columns)")
201
+ return df
202
+ except Exception as e:
203
+ print(f"āŒ Error loading CSV: {e}")
204
+ return None
205
+
206
+
207
+ # ============================================================
208
+ # FUNCTION 9: Download Dataset
209
+ # ============================================================
210
+ def download_dataset(api, dataset_name, output_path, verbose=False):
211
+ """Download a dataset from Kaggle"""
212
+ print(f"ā¬‡ļø Downloading {dataset_name}...")
213
+
214
+ try:
215
+ api.dataset_download_files(
216
+ dataset_name,
217
+ path=str(output_path),
218
+ unzip=True
219
+ )
220
+
221
+ print(f"āœ… Download complete! Files saved to: {output_path}")
222
+
223
+ if verbose:
224
+ list_downloaded_files(output_path)
225
+
226
+ return True
227
+
228
+ except Exception as e:
229
+ handle_download_error(e, dataset_name)
230
+ return False
231
+
232
+
233
+ # ============================================================
234
+ # FUNCTION 10: Download Competition
235
+ # ============================================================
236
+ def download_competition(api, competition_name, output_path, verbose=False):
237
+ """Download competition files from Kaggle"""
238
+ print(f"ā¬‡ļø Downloading competition: {competition_name}...")
239
+
240
+ try:
241
+ api.competition_download_files(
242
+ competition_name,
243
+ path=str(output_path)
244
+ )
245
+
246
+ print(f"āœ… Download complete! Files saved to: {output_path}")
247
+
248
+ if verbose:
249
+ list_downloaded_files(output_path)
250
+
251
+ return True
252
+
253
+ except Exception as e:
254
+ handle_download_error(e, competition_name)
255
+ return False
256
+
257
+
258
+ # ============================================================
259
+ # FUNCTION 11: Handle Download Errors
260
+ # ============================================================
261
+ def handle_download_error(error, dataset_name):
262
+ """Handle and explain download errors"""
263
+ print(f"āŒ Error downloading: {error}")
264
+ error_msg = str(error)
265
+
266
+ if "403" in error_msg:
267
+ print("\nšŸ” Troubleshooting 403 Forbidden error:")
268
+ print("This usually means the dataset requires accepting terms or is restricted.")
269
+ print(f"1. Visit: https://www.kaggle.com/datasets/{dataset_name}")
270
+ print("2. Click 'Download' and accept any terms")
271
+ print("3. Wait a moment, then try again")
272
+ print("\nšŸ“ Or try --competition flag if it's a competition:")
273
+ print(f" python kaggle_prep/cli.py {dataset_name} --competition --verbose")
274
+
275
+ elif "404" in error_msg:
276
+ print(f"\nšŸ” Dataset '{dataset_name}' not found!")
277
+ print("Check the spelling or try searching on Kaggle")
278
+ print("\nšŸ“ Examples:")
279
+ print(" python kaggle_prep/cli.py uciml/iris --verbose")
280
+ print(" python kaggle_prep/cli.py debayank2024/netflix-movies-and-series --verbose")
281
+
282
+ elif "429" in error_msg:
283
+ print("\nāš ļø Rate limit reached!")
284
+ print("Kaggle limits how many requests you can make.")
285
+ print("Wait 1 hour and try again.")
286
+
287
+ else:
288
+ print(f"\nšŸ” Unexpected error: {error}")
289
+
290
+
291
+ # ============================================================
292
+ # FUNCTION 12: Profile Downloaded Data
293
+ # ============================================================
294
+ def profile_downloaded_data(output_path, dataset_name, generate_report=False):
295
+ """Run profiling on downloaded data"""
296
+
297
+ print("\nšŸ“Š Generating data profile...")
298
+
299
+ # Load the data
300
+ df = load_first_csv(Path(output_path))
301
+ if df is None:
302
+ return
303
+
304
+ # Create profile using our custom profiler
305
+ profiler = DataProfiler(df, dataset_name)
306
+ profile = profiler.profile()
307
+
308
+ # Save JSON profile
309
+ json_path = save_profile_json(profile)
310
+
311
+ # Print summary to console
312
+ print_profile_summary(profile)
313
+
314
+ # Generate HTML report if requested
315
+ if generate_report:
316
+ generate_standalone_report(profile)
317
+
318
+ def generate_starter_notebook(output_path, dataset_name, df=None, profile=None):
319
+ print("Generating starter notebook...")
320
+ if df is None:
321
+ df=load_first_csv(output_path)
322
+
323
+ notebook_path = generate_notebook(
324
+ dataset_name=dataset_name,
325
+ df=df,
326
+ profile=profile,
327
+ output_dir="notebooks"
328
+ )
329
+ print(f" Starter notebook saved to: {notebook_path}")
330
+
331
+ #===============================================================
332
+ def generate_visualizations(output_path, dataset_name,df):
333
+ print("Generating EDA visualizations..")
334
+
335
+ vis_dir =f"eda_plots_{dataset_name.replace('/','_')}"
336
+
337
+ plot_path = generate_eda_plots(
338
+ df=df,
339
+ output_dir=vis_dir,
340
+ max_cols=10,
341
+ fig_dpi=150
342
+ )
343
+
344
+ print(f" Visualizations saved to: {plot_path}")
345
+ return plot_path
346
+ ##==============================================
347
+ def save_preprocessing_code(output_path, dataset_name, df):
348
+ """Generate and save preprocessing code"""
349
+
350
+ print("\n Generating preprocessing code...")
351
+
352
+ # Generate code
353
+ code = generate_preprocessing_code(df)
354
+
355
+ # Save to file
356
+ safe_name = dataset_name.replace('/', '_')
357
+ code_path = Path(output_path) / f"{safe_name}_preprocess.py"
358
+
359
+ with open(code_path, 'w', encoding='utf-8') as f:
360
+ f.write(code)
361
+
362
+ print(f" Preprocessing code saved to: {code_path}")
363
+ return code_path
364
+
365
+ # ============================================================
366
+ # MAIN FUNCTION
367
+ # ============================================================
368
+ def main():
369
+ """Main entry point for the CLI tool"""
370
+
371
+ # Step 1: Get user input
372
+ args = parse_arguments()
373
+
374
+ # Step 2: Show startup info
375
+ display_startup_info(args)
376
+ output_path = Path(args.output_dir)
377
+ data_exists = any(output_path.glob("*.csv")) or any(output_path.glob("*.xlsx")) or any(output_path.glob("*.json"))
378
+
379
+ if args.local and data_exists:
380
+ print("šŸ“ Using existing data (--local flag detected)")
381
+ print(f" Data found in: {output_path}")
382
+ else:
383
+ # Only download if:
384
+ # 1. --local is NOT used, OR
385
+ # 2. Data doesn't exist
386
+ if not data_exists:
387
+ print("šŸ“‚ No existing data found. Downloading...")
388
+ else:
389
+ print("šŸ“„ Downloading data (use --local to skip download next time)")
390
+
391
+
392
+ # Step 3: Check credentials
393
+ kaggle_dir = check_credentials(args.verbose)
394
+ if not kaggle_dir:
395
+ return
396
+
397
+ # Step 4: Authenticate
398
+ api = authenticate_kaggle(kaggle_dir, args.verbose)
399
+ if not api:
400
+ return
401
+
402
+ # Step 5: Create output directory
403
+ output_path = create_output_directory(args.output_dir)
404
+
405
+ # Step 6: Download
406
+ if args.competition:
407
+ download_competition(api, args.dataset, output_path, args.verbose)
408
+ else:
409
+ download_dataset(api, args.dataset, output_path, args.verbose)
410
+
411
+ df=None
412
+ profile=None
413
+ if args.profile or args.report or args.visualize or args.preprocess or args.notebook:
414
+ df = load_first_csv(Path(args.output_dir))
415
+
416
+ # If data loaded successfully
417
+ if df is not None:
418
+ # Generate profile if requested
419
+ if args.profile or args.report:
420
+ profiler = DataProfiler(df, args.dataset)
421
+ profile = profiler.profile()
422
+
423
+ if args.profile:
424
+ json_path = save_profile_json(profile)
425
+
426
+ if args.report:
427
+ generate_standalone_report(profile)
428
+
429
+ # Step 7: Profile if requested
430
+ if args.visualize:
431
+ generate_visualizations(output_path, args.dataset, df)
432
+
433
+ # Generate preprocessing code if requested
434
+ if args.preprocess:
435
+ save_preprocessing_code(output_path, args.dataset, df)
436
+
437
+ # Generate notebook if requested
438
+ if args.notebook:
439
+ generate_starter_notebook(args.dataset, df, profile)
440
+
441
+ # Step 8: Done!
442
+ print("\n All done! Happy data science! ")
443
+
444
+
445
+
446
+
447
+ # ============================================================
448
+ # ENTRY POINT
449
+ # ============================================================
450
+ if __name__ == "__main__":
451
+ main()