sqlalchemyseed 2.0.0__tar.gz → 2.2.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.
Files changed (35) hide show
  1. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/PKG-INFO +61 -21
  2. sqlalchemyseed-2.0.0/src/sqlalchemyseed.egg-info/PKG-INFO → sqlalchemyseed-2.2.0/README.md +48 -33
  3. sqlalchemyseed-2.2.0/pyproject.toml +57 -0
  4. sqlalchemyseed-2.2.0/setup.cfg +4 -0
  5. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/__init__.py +1 -1
  6. sqlalchemyseed-2.2.0/src/sqlalchemyseed/__main__.py +6 -0
  7. sqlalchemyseed-2.2.0/src/sqlalchemyseed/cli.py +169 -0
  8. sqlalchemyseed-2.2.0/src/sqlalchemyseed.egg-info/PKG-INFO +177 -0
  9. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed.egg-info/SOURCES.txt +4 -2
  10. sqlalchemyseed-2.2.0/src/sqlalchemyseed.egg-info/entry_points.txt +2 -0
  11. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed.egg-info/requires.txt +1 -1
  12. sqlalchemyseed-2.2.0/tests/test_cli.py +133 -0
  13. sqlalchemyseed-2.0.0/README.md +0 -114
  14. sqlalchemyseed-2.0.0/pyproject.toml +0 -6
  15. sqlalchemyseed-2.0.0/setup.cfg +0 -44
  16. sqlalchemyseed-2.0.0/setup.py +0 -4
  17. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/LICENSE +0 -0
  18. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/_future/__init__.py +0 -0
  19. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/_future/seeder.py +0 -0
  20. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/attribute.py +0 -0
  21. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/constants.py +0 -0
  22. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/dynamic_seeder.py +0 -0
  23. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/errors.py +0 -0
  24. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/json.py +0 -0
  25. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/loader.py +0 -0
  26. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/seeder.py +0 -0
  27. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/util.py +0 -0
  28. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed/validator.py +0 -0
  29. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed.egg-info/dependency_links.txt +0 -0
  30. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/src/sqlalchemyseed.egg-info/top_level.txt +0 -0
  31. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/tests/test_json.py +0 -0
  32. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/tests/test_loader.py +0 -0
  33. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/tests/test_seeder.py +0 -0
  34. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/tests/test_temp_seeder.py +0 -0
  35. {sqlalchemyseed-2.0.0 → sqlalchemyseed-2.2.0}/tests/test_validator.py +0 -0
@@ -1,25 +1,27 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: sqlalchemyseed
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: SQLAlchemy Seeder
5
- Home-page: https://github.com/jedymatt/sqlalchemyseed
6
- Author: Jedy Matt Tabasco
7
- Author-email: jedymatt@gmail.com
8
- License: MIT
5
+ Author-email: Jedy Matt Tabasco <hello@jedymatt.dev>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/jedymatt/sqlalchemyseed
9
8
  Project-URL: Documentation, https://sqlalchemyseed.readthedocs.io/
10
9
  Project-URL: Source, https://github.com/jedymatt/sqlalchemyseed
11
10
  Project-URL: Tracker, https://github.com/jedymatt/sqlalchemyseed/issues
12
11
  Keywords: sqlalchemy,orm,seed,seeder,json,yaml
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3.7
15
- Classifier: Programming Language :: Python :: 3.8
16
12
  Classifier: Programming Language :: Python :: 3.9
17
13
  Classifier: Programming Language :: Python :: 3.10
18
14
  Classifier: Programming Language :: Python :: 3.11
19
- Requires-Python: >=3.7
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Requires-Python: >=3.9
20
19
  Description-Content-Type: text/markdown
21
- Provides-Extra: yaml
22
20
  License-File: LICENSE
21
+ Requires-Dist: SQLAlchemy>=2.0
22
+ Provides-Extra: yaml
23
+ Requires-Dist: PyYAML>=6.0; extra == "yaml"
24
+ Dynamic: license-file
23
25
 
24
26
  # sqlalchemyseed
25
27
 
@@ -87,6 +89,40 @@ data.json
87
89
  }
88
90
  ```
89
91
 
92
+ ## Command-line usage
93
+
94
+ Seed a database directly from data files without writing Python:
95
+
96
+ ```shell
97
+ sqlalchemyseed data.json --url sqlite:///app.db
98
+ ```
99
+
100
+ The command accepts one or more files and/or directories (a directory seeds
101
+ every `.json`/`.yaml`/`.yml` file inside it, in sorted order):
102
+
103
+ ```shell
104
+ sqlalchemyseed seeds/ --url "$DATABASE_URL"
105
+ sqlalchemyseed a.json b.yaml --url sqlite:///app.db
106
+ ```
107
+
108
+ The database URL may be passed with `--url` or the `DATABASE_URL` environment
109
+ variable. Model paths in the data files (e.g. `models.Person`) are resolved
110
+ against the current working directory, so run the command from your project
111
+ root.
112
+
113
+ Options:
114
+
115
+ - `--dry-run` — seed inside a transaction, then roll back (validate without writing)
116
+ - `--seeder hybrid` — use `HybridSeeder` instead of the default `Seeder`
117
+ - `--model models.Person` — required for CSV inputs, which are not self-describing
118
+ - `--ref-prefix` — override the relationship reference prefix (default `!`)
119
+
120
+ The same command is available as a module:
121
+
122
+ ```shell
123
+ python -m sqlalchemyseed data.json --url sqlite:///app.db
124
+ ```
125
+
90
126
  ## Documentation
91
127
 
92
128
  <https://sqlalchemyseed.readthedocs.io/>
@@ -100,34 +136,38 @@ Report here in this link:
100
136
 
101
137
  First, Clone this [repository](https://github.com/jedymatt/sqlalchemyseed).
102
138
 
139
+ This project uses [uv](https://docs.astral.sh/uv/) for dependency management and running tasks.
140
+
103
141
  ### Install dev dependencies
104
142
 
105
- Inside the folder, paste this in the terminal to install necessary dependencies:
143
+ Inside the folder, sync the environment (uv creates the virtualenv and installs the project plus dev dependencies):
106
144
 
107
145
  ```shell
108
- pip install -r requirements.txt -r docs/requirements.txt
146
+ uv sync
109
147
  ```
110
148
 
111
- Note: make sure you have the virtual environment and enabled, or if you are using vs code and docker then you can simply re-open this as container.
112
-
113
149
  ### Run tests
114
150
 
115
- Before running tests, make sure that the package is installed as editable:
151
+ ```shell
152
+ uv run pytest
153
+ ```
154
+
155
+ Run the tests against a specific Python version (uv downloads it if needed):
116
156
 
117
157
  ```shell
118
- python setup.py develop --user
158
+ uv run --python 3.14 pytest
119
159
  ```
120
160
 
121
- Then run the test:
161
+ Run the tests against the lowest supported dependencies (e.g. SQLAlchemy 2.0):
122
162
 
123
163
  ```shell
124
- pytest tests
164
+ uv run --resolution lowest-direct pytest
125
165
  ```
126
166
 
127
- Run test with coverage
167
+ Run tests with coverage:
128
168
 
129
169
  ```shell
130
- coverage run -m pytest
170
+ uv run coverage run -m pytest
131
171
  ```
132
172
 
133
173
  Autobuild documentation
@@ -1,26 +1,3 @@
1
- Metadata-Version: 2.1
2
- Name: sqlalchemyseed
3
- Version: 2.0.0
4
- Summary: SQLAlchemy Seeder
5
- Home-page: https://github.com/jedymatt/sqlalchemyseed
6
- Author: Jedy Matt Tabasco
7
- Author-email: jedymatt@gmail.com
8
- License: MIT
9
- Project-URL: Documentation, https://sqlalchemyseed.readthedocs.io/
10
- Project-URL: Source, https://github.com/jedymatt/sqlalchemyseed
11
- Project-URL: Tracker, https://github.com/jedymatt/sqlalchemyseed/issues
12
- Keywords: sqlalchemy,orm,seed,seeder,json,yaml
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3.7
15
- Classifier: Programming Language :: Python :: 3.8
16
- Classifier: Programming Language :: Python :: 3.9
17
- Classifier: Programming Language :: Python :: 3.10
18
- Classifier: Programming Language :: Python :: 3.11
19
- Requires-Python: >=3.7
20
- Description-Content-Type: text/markdown
21
- Provides-Extra: yaml
22
- License-File: LICENSE
23
-
24
1
  # sqlalchemyseed
25
2
 
26
3
  [![PyPI](https://img.shields.io/pypi/v/sqlalchemyseed)](https://pypi.org/project/sqlalchemyseed)
@@ -87,6 +64,40 @@ data.json
87
64
  }
88
65
  ```
89
66
 
67
+ ## Command-line usage
68
+
69
+ Seed a database directly from data files without writing Python:
70
+
71
+ ```shell
72
+ sqlalchemyseed data.json --url sqlite:///app.db
73
+ ```
74
+
75
+ The command accepts one or more files and/or directories (a directory seeds
76
+ every `.json`/`.yaml`/`.yml` file inside it, in sorted order):
77
+
78
+ ```shell
79
+ sqlalchemyseed seeds/ --url "$DATABASE_URL"
80
+ sqlalchemyseed a.json b.yaml --url sqlite:///app.db
81
+ ```
82
+
83
+ The database URL may be passed with `--url` or the `DATABASE_URL` environment
84
+ variable. Model paths in the data files (e.g. `models.Person`) are resolved
85
+ against the current working directory, so run the command from your project
86
+ root.
87
+
88
+ Options:
89
+
90
+ - `--dry-run` — seed inside a transaction, then roll back (validate without writing)
91
+ - `--seeder hybrid` — use `HybridSeeder` instead of the default `Seeder`
92
+ - `--model models.Person` — required for CSV inputs, which are not self-describing
93
+ - `--ref-prefix` — override the relationship reference prefix (default `!`)
94
+
95
+ The same command is available as a module:
96
+
97
+ ```shell
98
+ python -m sqlalchemyseed data.json --url sqlite:///app.db
99
+ ```
100
+
90
101
  ## Documentation
91
102
 
92
103
  <https://sqlalchemyseed.readthedocs.io/>
@@ -100,34 +111,38 @@ Report here in this link:
100
111
 
101
112
  First, Clone this [repository](https://github.com/jedymatt/sqlalchemyseed).
102
113
 
114
+ This project uses [uv](https://docs.astral.sh/uv/) for dependency management and running tasks.
115
+
103
116
  ### Install dev dependencies
104
117
 
105
- Inside the folder, paste this in the terminal to install necessary dependencies:
118
+ Inside the folder, sync the environment (uv creates the virtualenv and installs the project plus dev dependencies):
106
119
 
107
120
  ```shell
108
- pip install -r requirements.txt -r docs/requirements.txt
121
+ uv sync
109
122
  ```
110
123
 
111
- Note: make sure you have the virtual environment and enabled, or if you are using vs code and docker then you can simply re-open this as container.
112
-
113
124
  ### Run tests
114
125
 
115
- Before running tests, make sure that the package is installed as editable:
126
+ ```shell
127
+ uv run pytest
128
+ ```
129
+
130
+ Run the tests against a specific Python version (uv downloads it if needed):
116
131
 
117
132
  ```shell
118
- python setup.py develop --user
133
+ uv run --python 3.14 pytest
119
134
  ```
120
135
 
121
- Then run the test:
136
+ Run the tests against the lowest supported dependencies (e.g. SQLAlchemy 2.0):
122
137
 
123
138
  ```shell
124
- pytest tests
139
+ uv run --resolution lowest-direct pytest
125
140
  ```
126
141
 
127
- Run test with coverage
142
+ Run tests with coverage:
128
143
 
129
144
  ```shell
130
- coverage run -m pytest
145
+ uv run coverage run -m pytest
131
146
  ```
132
147
 
133
148
  Autobuild documentation
@@ -0,0 +1,57 @@
1
+ [project]
2
+ name = "sqlalchemyseed"
3
+ description = "SQLAlchemy Seeder"
4
+ readme = "README.md"
5
+ requires-python = ">=3.9"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [
9
+ { name = "Jedy Matt Tabasco", email = "hello@jedymatt.dev" },
10
+ ]
11
+ keywords = ["sqlalchemy", "orm", "seed", "seeder", "json", "yaml"]
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3.9",
14
+ "Programming Language :: Python :: 3.10",
15
+ "Programming Language :: Python :: 3.11",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Programming Language :: Python :: 3.14",
19
+ ]
20
+ dependencies = [
21
+ "SQLAlchemy>=2.0",
22
+ ]
23
+ dynamic = ["version"]
24
+
25
+ [project.optional-dependencies]
26
+ yaml = [
27
+ "PyYAML>=6.0",
28
+ ]
29
+
30
+ [project.scripts]
31
+ sqlalchemyseed = "sqlalchemyseed.cli:main"
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/jedymatt/sqlalchemyseed"
35
+ Documentation = "https://sqlalchemyseed.readthedocs.io/"
36
+ Source = "https://github.com/jedymatt/sqlalchemyseed"
37
+ Tracker = "https://github.com/jedymatt/sqlalchemyseed/issues"
38
+
39
+ [dependency-groups]
40
+ dev = [
41
+ "pytest>=7.0",
42
+ "coverage>=6.2",
43
+ "PyYAML>=6.0",
44
+ ]
45
+
46
+ [build-system]
47
+ requires = ["setuptools>=77"]
48
+ build-backend = "setuptools.build_meta"
49
+
50
+ [tool.setuptools.dynamic]
51
+ version = { attr = "sqlalchemyseed.__version__" }
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["src"]
55
+
56
+ [tool.uv]
57
+ default-groups = ["dev"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -11,7 +11,7 @@ from . import util
11
11
  from . import attribute
12
12
 
13
13
 
14
- __version__ = "2.0.0"
14
+ __version__ = "2.2.0"
15
15
 
16
16
  if __name__ == '__main__':
17
17
  pass
@@ -0,0 +1,6 @@
1
+ """Enable ``python -m sqlalchemyseed``."""
2
+
3
+ from .cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -0,0 +1,169 @@
1
+ """Command-line interface for seeding a database from data files."""
2
+
3
+ import argparse
4
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ import sqlalchemy
9
+ from sqlalchemy.orm import Session
10
+
11
+ from . import loader
12
+ from .seeder import HybridSeeder, Seeder
13
+
14
+ _JSON_EXTENSIONS = {".json"}
15
+ _YAML_EXTENSIONS = {".yaml", ".yml"}
16
+ _CSV_EXTENSIONS = {".csv"}
17
+ # Only self-describing formats are auto-discovered inside a directory. CSV
18
+ # needs an explicit --model, so a CSV must be named as an individual file.
19
+ _DISCOVERABLE_EXTENSIONS = _JSON_EXTENSIONS | _YAML_EXTENSIONS
20
+
21
+
22
+ def build_parser() -> argparse.ArgumentParser:
23
+ """Build the argument parser for the ``sqlalchemyseed`` command."""
24
+ parser = argparse.ArgumentParser(
25
+ prog="sqlalchemyseed",
26
+ description="Seed a database from JSON, YAML, or CSV data files.",
27
+ )
28
+ parser.add_argument(
29
+ "paths",
30
+ nargs="+",
31
+ metavar="PATH",
32
+ help="data files or directories to seed from",
33
+ )
34
+ parser.add_argument(
35
+ "--url",
36
+ help="SQLAlchemy database URL (defaults to the DATABASE_URL env var)",
37
+ )
38
+ parser.add_argument(
39
+ "--seeder",
40
+ choices=("basic", "hybrid"),
41
+ default="basic",
42
+ help="seeder to use (default: basic)",
43
+ )
44
+ parser.add_argument(
45
+ "--model",
46
+ help="model class path (e.g. models.Person) required for CSV inputs",
47
+ )
48
+ parser.add_argument(
49
+ "--ref-prefix",
50
+ default="!",
51
+ help="prefix marking relationship references (default: !)",
52
+ )
53
+ parser.add_argument(
54
+ "--dry-run",
55
+ action="store_true",
56
+ help="seed within a transaction but roll back instead of committing",
57
+ )
58
+ return parser
59
+
60
+
61
+ def collect_files(paths) -> list:
62
+ """Expand each path into data files, walking directories in sorted order."""
63
+ files = []
64
+ for raw_path in paths:
65
+ files.extend(_files_in(Path(raw_path)))
66
+ return files
67
+
68
+
69
+ def _files_in(path: Path) -> list:
70
+ """Return the data files contributed by a single path argument."""
71
+ if path.is_dir():
72
+ return _discover_directory(path)
73
+ if path.is_file():
74
+ return [path]
75
+ raise FileNotFoundError(f"path does not exist: {path}")
76
+
77
+
78
+ def _discover_directory(directory: Path) -> list:
79
+ """Return the JSON/YAML files inside a directory, sorted by name."""
80
+ discovered = sorted(
81
+ child for child in directory.iterdir()
82
+ if child.suffix.lower() in _DISCOVERABLE_EXTENSIONS
83
+ )
84
+ if not discovered:
85
+ raise FileNotFoundError(
86
+ f"no JSON or YAML seed files found in directory: {directory}"
87
+ )
88
+ return discovered
89
+
90
+
91
+ def load_file(path: Path, model=None) -> dict:
92
+ """Load entities from a single data file, dispatching on its extension."""
93
+ suffix = path.suffix.lower()
94
+ if suffix in _JSON_EXTENSIONS:
95
+ return loader.load_entities_from_json(str(path))
96
+ if suffix in _YAML_EXTENSIONS:
97
+ return loader.load_entities_from_yaml(str(path))
98
+ if suffix in _CSV_EXTENSIONS:
99
+ return _load_csv(path, model)
100
+ raise ValueError(f"unsupported file type: {path}")
101
+
102
+
103
+ def _load_csv(path: Path, model) -> dict:
104
+ """Load entities from a CSV file, which requires an explicit model."""
105
+ if model is None:
106
+ raise ValueError(f"CSV input requires --model to name the target class: {path}")
107
+ return loader.load_entities_from_csv(str(path), model)
108
+
109
+
110
+ def _make_seeder(name, session, ref_prefix):
111
+ """Return the seeder implementation selected on the command line."""
112
+ if name == "hybrid":
113
+ return HybridSeeder(session, ref_prefix=ref_prefix)
114
+ return Seeder(session, ref_prefix=ref_prefix)
115
+
116
+
117
+ def _seed_all(seeder, files, model) -> int:
118
+ """Seed every file through the seeder and return the entity count."""
119
+ seeded = 0
120
+ for path in files:
121
+ seeder.seed(load_file(path, model))
122
+ seeded += len(seeder.instances)
123
+ return seeded
124
+
125
+
126
+ def main(argv=None) -> int:
127
+ """Entry point for the ``sqlalchemyseed`` command."""
128
+ parser = build_parser()
129
+ args = parser.parse_args(argv)
130
+
131
+ url = args.url or os.environ.get("DATABASE_URL")
132
+ if not url:
133
+ parser.error("a database URL is required via --url or the DATABASE_URL env var")
134
+
135
+ # Make the caller's project importable so model paths like "models.Person"
136
+ # resolve against the current working directory.
137
+ sys.path.insert(0, os.getcwd())
138
+
139
+ try:
140
+ files = collect_files(args.paths)
141
+ except FileNotFoundError as error:
142
+ parser.error(str(error))
143
+
144
+ engine = sqlalchemy.create_engine(url)
145
+ with Session(engine) as session:
146
+ seeder = _make_seeder(args.seeder, session, args.ref_prefix)
147
+ try:
148
+ seeded = _seed_all(seeder, files, args.model)
149
+ except Exception as error: # noqa: BLE001 - report any seeding failure as a clean exit
150
+ session.rollback()
151
+ print(f"error: {error}", file=sys.stderr)
152
+ return 1
153
+
154
+ return _finish(session, seeded, len(files), args.dry_run)
155
+
156
+
157
+ def _finish(session, seeded, file_count, dry_run) -> int:
158
+ """Commit or roll back the seeded session and print a summary."""
159
+ if dry_run:
160
+ session.rollback()
161
+ print(f"Dry run: would seed {seeded} entities from {file_count} file(s) (rolled back).")
162
+ return 0
163
+ session.commit()
164
+ print(f"Seeded {seeded} entities from {file_count} file(s).")
165
+ return 0
166
+
167
+
168
+ if __name__ == "__main__": # pragma: no cover
169
+ raise SystemExit(main())
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlalchemyseed
3
+ Version: 2.2.0
4
+ Summary: SQLAlchemy Seeder
5
+ Author-email: Jedy Matt Tabasco <hello@jedymatt.dev>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/jedymatt/sqlalchemyseed
8
+ Project-URL: Documentation, https://sqlalchemyseed.readthedocs.io/
9
+ Project-URL: Source, https://github.com/jedymatt/sqlalchemyseed
10
+ Project-URL: Tracker, https://github.com/jedymatt/sqlalchemyseed/issues
11
+ Keywords: sqlalchemy,orm,seed,seeder,json,yaml
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: SQLAlchemy>=2.0
22
+ Provides-Extra: yaml
23
+ Requires-Dist: PyYAML>=6.0; extra == "yaml"
24
+ Dynamic: license-file
25
+
26
+ # sqlalchemyseed
27
+
28
+ [![PyPI](https://img.shields.io/pypi/v/sqlalchemyseed)](https://pypi.org/project/sqlalchemyseed)
29
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sqlalchemyseed)](https://pypi.org/project/sqlalchemyseed)
30
+ [![PyPI - License](https://img.shields.io/pypi/l/sqlalchemyseed)](https://github.com/jedymatt/sqlalchemyseed/blob/main/LICENSE)
31
+ [![Python package](https://github.com/jedymatt/sqlalchemyseed/actions/workflows/python-package.yml/badge.svg)](https://github.com/jedymatt/sqlalchemyseed/actions/workflows/python-package.yml)
32
+ [![Maintainability](https://api.codeclimate.com/v1/badges/2ca97c98929b614658ea/maintainability)](https://codeclimate.com/github/jedymatt/sqlalchemyseed/maintainability)
33
+ [![codecov](https://codecov.io/gh/jedymatt/sqlalchemyseed/branch/main/graph/badge.svg?token=W03MFZ2FAG)](https://codecov.io/gh/jedymatt/sqlalchemyseed)
34
+ [![Documentation Status](https://readthedocs.org/projects/sqlalchemyseed/badge/?version=latest)](https://sqlalchemyseed.readthedocs.io/en/latest/?badge=latest)
35
+
36
+ Sqlalchemy seeder that supports nested relationships.
37
+
38
+ Supported file types
39
+
40
+ - json
41
+ - yaml
42
+ - csv
43
+
44
+ ## Installation
45
+
46
+ Default installation
47
+
48
+ ```shell
49
+ pip install sqlalchemyseed
50
+ ```
51
+
52
+ ## Quickstart
53
+
54
+ main.py
55
+
56
+ ```python
57
+ from sqlalchemyseed import load_entities_from_json
58
+ from sqlalchemyseed import Seeder
59
+ from db import session
60
+
61
+ # load entities
62
+ entities = load_entities_from_json('data.json')
63
+
64
+ # Initializing Seeder
65
+ seeder = Seeder(session)
66
+
67
+ # Seeding
68
+ seeder.seed(entities)
69
+
70
+ # Committing
71
+ session.commit() # or seeder.session.commit()
72
+ ```
73
+
74
+ data.json
75
+
76
+ ```json
77
+ {
78
+ "model": "models.Person",
79
+ "data": [
80
+ {
81
+ "name": "John March",
82
+ "age": 23
83
+ },
84
+ {
85
+ "name": "Juan Dela Cruz",
86
+ "age": 21
87
+ }
88
+ ]
89
+ }
90
+ ```
91
+
92
+ ## Command-line usage
93
+
94
+ Seed a database directly from data files without writing Python:
95
+
96
+ ```shell
97
+ sqlalchemyseed data.json --url sqlite:///app.db
98
+ ```
99
+
100
+ The command accepts one or more files and/or directories (a directory seeds
101
+ every `.json`/`.yaml`/`.yml` file inside it, in sorted order):
102
+
103
+ ```shell
104
+ sqlalchemyseed seeds/ --url "$DATABASE_URL"
105
+ sqlalchemyseed a.json b.yaml --url sqlite:///app.db
106
+ ```
107
+
108
+ The database URL may be passed with `--url` or the `DATABASE_URL` environment
109
+ variable. Model paths in the data files (e.g. `models.Person`) are resolved
110
+ against the current working directory, so run the command from your project
111
+ root.
112
+
113
+ Options:
114
+
115
+ - `--dry-run` — seed inside a transaction, then roll back (validate without writing)
116
+ - `--seeder hybrid` — use `HybridSeeder` instead of the default `Seeder`
117
+ - `--model models.Person` — required for CSV inputs, which are not self-describing
118
+ - `--ref-prefix` — override the relationship reference prefix (default `!`)
119
+
120
+ The same command is available as a module:
121
+
122
+ ```shell
123
+ python -m sqlalchemyseed data.json --url sqlite:///app.db
124
+ ```
125
+
126
+ ## Documentation
127
+
128
+ <https://sqlalchemyseed.readthedocs.io/>
129
+
130
+ ## Found Bug?
131
+
132
+ Report here in this link:
133
+ <https://github.com/jedymatt/sqlalchemyseed/issues>
134
+
135
+ ## Want to contribute?
136
+
137
+ First, Clone this [repository](https://github.com/jedymatt/sqlalchemyseed).
138
+
139
+ This project uses [uv](https://docs.astral.sh/uv/) for dependency management and running tasks.
140
+
141
+ ### Install dev dependencies
142
+
143
+ Inside the folder, sync the environment (uv creates the virtualenv and installs the project plus dev dependencies):
144
+
145
+ ```shell
146
+ uv sync
147
+ ```
148
+
149
+ ### Run tests
150
+
151
+ ```shell
152
+ uv run pytest
153
+ ```
154
+
155
+ Run the tests against a specific Python version (uv downloads it if needed):
156
+
157
+ ```shell
158
+ uv run --python 3.14 pytest
159
+ ```
160
+
161
+ Run the tests against the lowest supported dependencies (e.g. SQLAlchemy 2.0):
162
+
163
+ ```shell
164
+ uv run --resolution lowest-direct pytest
165
+ ```
166
+
167
+ Run tests with coverage:
168
+
169
+ ```shell
170
+ uv run coverage run -m pytest
171
+ ```
172
+
173
+ Autobuild documentation
174
+
175
+ ```shell
176
+ sphinx-autobuild docs docs/_build/html
177
+ ```
@@ -1,10 +1,10 @@
1
1
  LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
- setup.cfg
5
- setup.py
6
4
  src/sqlalchemyseed/__init__.py
5
+ src/sqlalchemyseed/__main__.py
7
6
  src/sqlalchemyseed/attribute.py
7
+ src/sqlalchemyseed/cli.py
8
8
  src/sqlalchemyseed/constants.py
9
9
  src/sqlalchemyseed/dynamic_seeder.py
10
10
  src/sqlalchemyseed/errors.py
@@ -16,10 +16,12 @@ src/sqlalchemyseed/validator.py
16
16
  src/sqlalchemyseed.egg-info/PKG-INFO
17
17
  src/sqlalchemyseed.egg-info/SOURCES.txt
18
18
  src/sqlalchemyseed.egg-info/dependency_links.txt
19
+ src/sqlalchemyseed.egg-info/entry_points.txt
19
20
  src/sqlalchemyseed.egg-info/requires.txt
20
21
  src/sqlalchemyseed.egg-info/top_level.txt
21
22
  src/sqlalchemyseed/_future/__init__.py
22
23
  src/sqlalchemyseed/_future/seeder.py
24
+ tests/test_cli.py
23
25
  tests/test_json.py
24
26
  tests/test_loader.py
25
27
  tests/test_seeder.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sqlalchemyseed = sqlalchemyseed.cli:main
@@ -1,4 +1,4 @@
1
1
  SQLAlchemy>=2.0
2
2
 
3
3
  [yaml]
4
- PyYAML>=5.4
4
+ PyYAML>=6.0
@@ -0,0 +1,133 @@
1
+ """Tests for the sqlalchemyseed command-line interface."""
2
+
3
+ import json
4
+
5
+ import pytest
6
+ from sqlalchemy import create_engine
7
+ from sqlalchemy.orm import Session
8
+
9
+ from sqlalchemyseed import cli
10
+ from tests.models import Base, Person
11
+
12
+
13
+ @pytest.fixture
14
+ def db_url(tmp_path):
15
+ """A file-backed SQLite URL with the test schema already created."""
16
+ url = f"sqlite:///{tmp_path / 'seed.db'}"
17
+ engine = create_engine(url)
18
+ Base.metadata.create_all(engine)
19
+ engine.dispose()
20
+ return url
21
+
22
+
23
+ def count_persons(url):
24
+ with Session(create_engine(url)) as session:
25
+ return session.query(Person).count()
26
+
27
+
28
+ def write_json(path, entities):
29
+ path.write_text(json.dumps(entities), encoding="utf-8")
30
+ return path
31
+
32
+
33
+ def person_entities(*names):
34
+ return {"model": "tests.models.Person", "data": [{"name": name} for name in names]}
35
+
36
+
37
+ def test_seed_json_file(tmp_path, db_url):
38
+ data_file = write_json(tmp_path / "people.json", person_entities("Alice", "Bob"))
39
+
40
+ assert cli.main([str(data_file), "--url", db_url]) == 0
41
+ assert count_persons(db_url) == 2
42
+
43
+
44
+ def test_seed_yaml_file(tmp_path, db_url):
45
+ yaml_file = tmp_path / "people.yaml"
46
+ yaml_file.write_text(
47
+ "model: tests.models.Person\ndata:\n - name: Carol\n", encoding="utf-8"
48
+ )
49
+
50
+ assert cli.main([str(yaml_file), "--url", db_url]) == 0
51
+ assert count_persons(db_url) == 1
52
+
53
+
54
+ def test_seed_csv_file_requires_model(tmp_path, db_url):
55
+ csv_file = tmp_path / "people.csv"
56
+ csv_file.write_text("name\nDave\nErin\n", encoding="utf-8")
57
+
58
+ exit_code = cli.main(
59
+ [str(csv_file), "--url", db_url, "--model", "tests.models.Person"]
60
+ )
61
+
62
+ assert exit_code == 0
63
+ assert count_persons(db_url) == 2
64
+
65
+
66
+ def test_csv_without_model_fails(tmp_path, db_url, capsys):
67
+ csv_file = tmp_path / "people.csv"
68
+ csv_file.write_text("name\nDave\n", encoding="utf-8")
69
+
70
+ assert cli.main([str(csv_file), "--url", db_url]) == 1
71
+ assert "requires --model" in capsys.readouterr().err
72
+ assert count_persons(db_url) == 0
73
+
74
+
75
+ def test_seed_directory(tmp_path, db_url):
76
+ seeds = tmp_path / "seeds"
77
+ seeds.mkdir()
78
+ write_json(seeds / "01_first.json", person_entities("Alice"))
79
+ write_json(seeds / "02_second.json", person_entities("Bob", "Carol"))
80
+
81
+ assert cli.main([str(seeds), "--url", db_url]) == 0
82
+ assert count_persons(db_url) == 3
83
+
84
+
85
+ def test_multiple_paths(tmp_path, db_url):
86
+ first = write_json(tmp_path / "a.json", person_entities("Alice"))
87
+ second = write_json(tmp_path / "b.json", person_entities("Bob"))
88
+
89
+ assert cli.main([str(first), str(second), "--url", db_url]) == 0
90
+ assert count_persons(db_url) == 2
91
+
92
+
93
+ def test_dry_run_rolls_back(tmp_path, db_url, capsys):
94
+ data_file = write_json(tmp_path / "people.json", person_entities("Alice", "Bob"))
95
+
96
+ assert cli.main([str(data_file), "--url", db_url, "--dry-run"]) == 0
97
+ assert "Dry run" in capsys.readouterr().out
98
+ assert count_persons(db_url) == 0
99
+
100
+
101
+ def test_hybrid_seeder(tmp_path, db_url):
102
+ data_file = write_json(tmp_path / "people.json", person_entities("Alice"))
103
+
104
+ assert cli.main([str(data_file), "--url", db_url, "--seeder", "hybrid"]) == 0
105
+ assert count_persons(db_url) == 1
106
+
107
+
108
+ def test_url_from_environment(tmp_path, db_url, monkeypatch):
109
+ monkeypatch.setenv("DATABASE_URL", db_url)
110
+ data_file = write_json(tmp_path / "people.json", person_entities("Alice"))
111
+
112
+ assert cli.main([str(data_file)]) == 0
113
+ assert count_persons(db_url) == 1
114
+
115
+
116
+ def test_missing_url_errors(tmp_path, monkeypatch):
117
+ monkeypatch.delenv("DATABASE_URL", raising=False)
118
+ data_file = write_json(tmp_path / "people.json", person_entities("Alice"))
119
+
120
+ with pytest.raises(SystemExit):
121
+ cli.main([str(data_file)])
122
+
123
+
124
+ def test_nonexistent_path_errors(db_url):
125
+ with pytest.raises(SystemExit):
126
+ cli.main(["does_not_exist.json", "--url", db_url])
127
+
128
+
129
+ def test_unsupported_file_type(tmp_path, db_url):
130
+ bad_file = tmp_path / "people.txt"
131
+ bad_file.write_text("nope", encoding="utf-8")
132
+
133
+ assert cli.main([str(bad_file), "--url", db_url]) == 1
@@ -1,114 +0,0 @@
1
- # sqlalchemyseed
2
-
3
- [![PyPI](https://img.shields.io/pypi/v/sqlalchemyseed)](https://pypi.org/project/sqlalchemyseed)
4
- [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sqlalchemyseed)](https://pypi.org/project/sqlalchemyseed)
5
- [![PyPI - License](https://img.shields.io/pypi/l/sqlalchemyseed)](https://github.com/jedymatt/sqlalchemyseed/blob/main/LICENSE)
6
- [![Python package](https://github.com/jedymatt/sqlalchemyseed/actions/workflows/python-package.yml/badge.svg)](https://github.com/jedymatt/sqlalchemyseed/actions/workflows/python-package.yml)
7
- [![Maintainability](https://api.codeclimate.com/v1/badges/2ca97c98929b614658ea/maintainability)](https://codeclimate.com/github/jedymatt/sqlalchemyseed/maintainability)
8
- [![codecov](https://codecov.io/gh/jedymatt/sqlalchemyseed/branch/main/graph/badge.svg?token=W03MFZ2FAG)](https://codecov.io/gh/jedymatt/sqlalchemyseed)
9
- [![Documentation Status](https://readthedocs.org/projects/sqlalchemyseed/badge/?version=latest)](https://sqlalchemyseed.readthedocs.io/en/latest/?badge=latest)
10
-
11
- Sqlalchemy seeder that supports nested relationships.
12
-
13
- Supported file types
14
-
15
- - json
16
- - yaml
17
- - csv
18
-
19
- ## Installation
20
-
21
- Default installation
22
-
23
- ```shell
24
- pip install sqlalchemyseed
25
- ```
26
-
27
- ## Quickstart
28
-
29
- main.py
30
-
31
- ```python
32
- from sqlalchemyseed import load_entities_from_json
33
- from sqlalchemyseed import Seeder
34
- from db import session
35
-
36
- # load entities
37
- entities = load_entities_from_json('data.json')
38
-
39
- # Initializing Seeder
40
- seeder = Seeder(session)
41
-
42
- # Seeding
43
- seeder.seed(entities)
44
-
45
- # Committing
46
- session.commit() # or seeder.session.commit()
47
- ```
48
-
49
- data.json
50
-
51
- ```json
52
- {
53
- "model": "models.Person",
54
- "data": [
55
- {
56
- "name": "John March",
57
- "age": 23
58
- },
59
- {
60
- "name": "Juan Dela Cruz",
61
- "age": 21
62
- }
63
- ]
64
- }
65
- ```
66
-
67
- ## Documentation
68
-
69
- <https://sqlalchemyseed.readthedocs.io/>
70
-
71
- ## Found Bug?
72
-
73
- Report here in this link:
74
- <https://github.com/jedymatt/sqlalchemyseed/issues>
75
-
76
- ## Want to contribute?
77
-
78
- First, Clone this [repository](https://github.com/jedymatt/sqlalchemyseed).
79
-
80
- ### Install dev dependencies
81
-
82
- Inside the folder, paste this in the terminal to install necessary dependencies:
83
-
84
- ```shell
85
- pip install -r requirements.txt -r docs/requirements.txt
86
- ```
87
-
88
- Note: make sure you have the virtual environment and enabled, or if you are using vs code and docker then you can simply re-open this as container.
89
-
90
- ### Run tests
91
-
92
- Before running tests, make sure that the package is installed as editable:
93
-
94
- ```shell
95
- python setup.py develop --user
96
- ```
97
-
98
- Then run the test:
99
-
100
- ```shell
101
- pytest tests
102
- ```
103
-
104
- Run test with coverage
105
-
106
- ```shell
107
- coverage run -m pytest
108
- ```
109
-
110
- Autobuild documentation
111
-
112
- ```shell
113
- sphinx-autobuild docs docs/_build/html
114
- ```
@@ -1,6 +0,0 @@
1
- [build-system]
2
- requires = [
3
- "setuptools>=42",
4
- "wheel"
5
- ]
6
- build-backend = "setuptools.build_meta"
@@ -1,44 +0,0 @@
1
- [metadata]
2
- name = sqlalchemyseed
3
- version = attr: sqlalchemyseed.__version__
4
- description = SQLAlchemy Seeder
5
- long_description = file: README.md
6
- long_description_content_type = text/markdown
7
- url = https://github.com/jedymatt/sqlalchemyseed
8
- author = Jedy Matt Tabasco
9
- author_email = jedymatt@gmail.com
10
- license = MIT
11
- license_files =
12
- LICENSE
13
- classifiers =
14
- License :: OSI Approved :: MIT License
15
- Programming Language :: Python :: 3.7
16
- Programming Language :: Python :: 3.8
17
- Programming Language :: Python :: 3.9
18
- Programming Language :: Python :: 3.10
19
- Programming Language :: Python :: 3.11
20
- project_urls =
21
- Documentation = https://sqlalchemyseed.readthedocs.io/
22
- Source = https://github.com/jedymatt/sqlalchemyseed
23
- Tracker = https://github.com/jedymatt/sqlalchemyseed/issues
24
- keywords = sqlalchemy, orm, seed, seeder, json, yaml
25
-
26
- [options]
27
- packages = find:
28
- package_dir =
29
- =src
30
- install_requires =
31
- SQLAlchemy>=2.0
32
- python_requires = >=3.7
33
-
34
- [options.packages.find]
35
- where = src
36
-
37
- [options.extras_require]
38
- yaml =
39
- PyYAML>=5.4
40
-
41
- [egg_info]
42
- tag_build =
43
- tag_date = 0
44
-
@@ -1,4 +0,0 @@
1
- from setuptools import setup
2
-
3
-
4
- setup()
File without changes