Polish: clearer errors, corrected docstrings, setuptools pin

- insert/upsert into a name that is actually a view now shows a
  clean error instead of a traceback
- db.view() on a name that is a table now says so in its error
- Database.__getitem__ docstring documents that views are returned
  for view names; hash_id docstring corrected (it is a column name,
  not a boolean)
- Registering two migrations with the same name in one set now
  raises ValueError at registration time instead of executing both
  and failing with IntegrityError at apply time
- build-system requires setuptools>=77, needed for the PEP 639
  license expression

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UnLnhsH25Nnv7LHhekUfPd
This commit is contained in:
Claude 2026-07-04 19:13:15 +00:00
commit 397cdcc491
No known key found for this signature in database
7 changed files with 58 additions and 7 deletions

View file

@ -1155,6 +1155,8 @@ def insert_upsert_implementation(
db.table(table).insert_all(
docs, pk=pk, batch_size=batch_size, alter=alter, **extra_kwargs
)
except NoTable as e:
raise click.ClickException(str(e))
except Exception as e:
if (
isinstance(e, OperationalError)

View file

@ -499,10 +499,12 @@ class Database:
def __getitem__(self, table_name: str) -> Union["Table", "View"]:
"""
``db[table_name]`` returns a :class:`.Table` object for the table with the specified name.
If the table does not exist yet it will be created the first time data is inserted into it.
``db[name]`` returns a :class:`.Table` object for the table with the specified name,
or a :class:`.View` object if the name matches an existing SQL view.
If neither exists yet, a table is assumed - it will be created the first
time data is inserted into it.
:param table_name: The name of the table
:param table_name: The name of the table or view
"""
if table_name in self.view_names():
return self.view(table_name)
@ -672,6 +674,12 @@ class Database:
:param view_name: Name of the view
"""
if view_name not in self.view_names():
if view_name in self.table_names():
raise NoView(
"View {name} does not exist - {name} is a table".format(
name=view_name
)
)
raise NoView("View {} does not exist".format(view_name))
return View(self, view_name)
@ -1618,7 +1626,8 @@ class Table(Queryable):
:param not_null: List of columns that cannot be null
:param defaults: Dictionary of column names and default values
:param batch_size: Integer number of rows to insert at a time
:param hash_id: If True, use a hash of the row values as the primary key
:param hash_id: Name of a column to create and use as a primary key, where the
value of that primary key is derived from a hash of the row values
:param hash_id_columns: List of columns to use for the hash_id
:param alter: If True, automatically alter the table if it doesn't match the schema
:param ignore: If True, ignore rows that already exist when inserting

View file

@ -44,8 +44,15 @@ class Migrations:
"""
def inner(func: Callable) -> Callable:
migration_name = name or getattr(func, "__name__")
if any(m.name == migration_name for m in self._migrations):
raise ValueError(
"Migration '{}' is already registered in set '{}'".format(
migration_name, self.name
)
)
self._migrations.append(
self._Migration(name or getattr(func, "__name__"), func, transactional)
self._Migration(migration_name, func, transactional)
)
return func