Skip to content

Commit 95e6237

Browse files
committed
Use Hatch instead of Tox
- Removes the old setup.[py,cfg] in favour of a modern pyproject.toml - Remove Tox in favour of Hatch - Add tests!
1 parent 986181a commit 95e6237

File tree

17 files changed

+308
-142
lines changed

17 files changed

+308
-142
lines changed

.github/workflows/tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
python-version: [3.7, 3.8, 3.9]
12+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
1313

1414
steps:
1515
- uses: actions/checkout@v3
@@ -22,9 +22,9 @@ jobs:
2222
- name: Install dependencies
2323
run: |
2424
python -m pip install --upgrade pip
25-
pip install tox
25+
pip install hatch
2626
27-
- name: Run Tox
27+
- name: Run tests
2828
run: |
29-
tox
29+
hatch run ci
3030

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
.tox/
1+
.hatch/
2+
.stestr/
23
db_testtools.egg-info/
34
__pycache__/
45
*.pyc
6+
dbtesttools/_version.py
7+
dist/

.vscode/settings.json

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
{
2-
"python.pythonPath": "${workspaceFolder}/.tox/py3/bin/python3",
3-
"python.formatting.provider": "black",
4-
"python.formatting.blackArgs": [
2+
"[python]": {
3+
"editor.formatOnSave": true,
4+
"editor.defaultFormatter": "ms-python.black-formatter",
5+
"editor.codeActionsOnSave": {
6+
"source.organizeImports": "explicit"
7+
}
8+
},
9+
"black-formatter.args": [
510
"--line-length",
611
"79"
712
],
8-
"python.linting.flake8Enabled": true,
9-
"python.linting.enabled": true,
1013
"python.testing.pytestEnabled": false,
11-
"python.testing.nosetestsEnabled": false,
1214
"python.testing.unittestEnabled": true,
1315
"files.watcherExclude": {
1416
"**/.coverage/**": true,
1517
"**/.eggs": true,
1618
"**/.stestr/**": true,
1719
"**/.testrepository/**": true,
18-
"**/.tox/**": true
20+
"${workspaceFolder}/build/**": true,
21+
"**/.hatch/**": true
1922
},
2023
"git.allowForcePush": true,
2124
"editor.wordWrapColumn": 79,
2225
"vim.textwidth": 79,
26+
"githubPullRequests.defaultMergeMethod": "rebase"
2327
}
28+

ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGES
22
=======
33

4+
2024.07.21
5+
----------
6+
* Use Hatch to test and build the project
7+
* Replace Black with Ruff for formatting and checking
8+
* Allow overriding of the PG server IP address
9+
410
2023.01.27
511
----------
612

README.rst

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ after each test completes.
1414
Requirements
1515
------------
1616

17-
Python 3.7 and beyond should work.
17+
Python 3.8 and beyond should work.
1818

1919
Quickstart
2020
----------
@@ -76,7 +76,8 @@ dropped and re-instated on every test.
7676

7777
The PostgresContainerFixture starts its own Postgres instance in a local
7878
Docker container. Therefore you must have Docker installed before using
79-
this fixture.
79+
this fixture. The Postgres image used by default is 16.3-alpine, but this
80+
fixture is known to work all the way back to v11.
8081

8182
If you are already running inside Docker you will need to start the
8283
container with `--network-"host"` so that 127.0.0.1 routes to the started
@@ -90,16 +91,12 @@ PG containers. You will need to do up to two extra things:
9091
can set the DBTESTTOOLS_PG_IP_ADDR environment variable.
9192

9293

93-
Help needed!
94-
------------
95-
This fixture suite is currently not tested itself and would benefit from
96-
anyone willing to contribute some unit tests. However, it has been in
97-
use daily on a large project at Cisco for a few years now, and is very
98-
stable.
94+
This code has been in use daily on a large project at Cisco for a few years
95+
now, and is very stable.
9996

10097

10198
Copyright
10299
---------
103100

104-
db-testtools is copyright (c) 2021-2023 Cisco Systems, Inc. and its affiliates
101+
db-testtools is copyright (c) 2021-2024 Cisco Systems, Inc. and its affiliates
105102
All rights reserved.

RELEASING.txt

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,11 @@ To release a new version of db-testtools:
33
1. Tag the current revision with the required release number, e.g.
44
`git tag 2021.09.29`
55
2. Build the package:
6-
`tox -e build-python-package`
7-
3. This will generate a new ChangeLog file. It needs to be committed as
8-
a new revision.
9-
4. After committing, move the tag: `git tag -f 2021.09.29`
10-
5. Build the package again because PBR.
11-
6. Upload the package to testpyi first to make sure it is ok:
12-
`tox -e testpypi dist/*2021.9.29*`
13-
7. If that looks ok, upload to the real pypi:
14-
`tox -e pypi dist/*2021.9.29*`
15-
8. Push the new tag to Github:
6+
`hatch build`
7+
3. Upload the package to testpyi first to make sure it is ok:
8+
`hatch run testpypi dist/*2021.9.29*`
9+
4. If that looks ok, upload to the real pypi:
10+
`hatch run pypi dist/*2021.9.29*`
11+
5. Push the new tag to Github:
1612
`git push origin 2021.09.29`
13+
6. Make a Github release

dbtesttools/engines/postgres.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
LC_CTYPE = 'en_US.utf8';
2222
CREATE USER testing WITH ENCRYPTED PASSWORD 'testing';
2323
GRANT ALL PRIVILEGES ON DATABASE testing TO testing;
24+
GRANT ALL ON SCHEMA public TO testing;
25+
ALTER DATABASE testing OWNER TO testing;
2426
"""
2527

2628
NEXT_ID = count(1)
@@ -53,10 +55,10 @@ def __init__(
5355
# Using the larger non-alpine image causes sort-order errors
5456
# because of locale collation differences.
5557
# image='postgres:11.4',
56-
image='postgres:11.11-alpine',
57-
name='testdb',
58+
image="postgres:16.3-alpine",
59+
name="testdb",
5860
init_sql=None,
59-
pg_data='/tmp/pgdata', # noqa: S108
61+
pg_data="/tmp/pgdata", # noqa: S108
6062
isolation=None,
6163
future=False,
6264
ip_address=None,
@@ -71,7 +73,7 @@ def __init__(
7173
self.isolation = isolation
7274
self.future = future
7375
self.ip_address = ip_address or os.getenv(
74-
'DBTESTTOOLS_PG_IP_ADDR', '127.0.0.1'
76+
"DBTESTTOOLS_PG_IP_ADDR", "127.0.0.1"
7577
)
7678

7779
def connect(self):
@@ -95,7 +97,7 @@ def setUp(self):
9597
self.wait_for_pg_start()
9698
self.set_up_test_database()
9799
self.engine = sa.create_engine(
98-
'postgresql://testing:testing@{ip}:{port}/testing'.format(
100+
"postgresql://testing:testing@{ip}:{port}/testing".format(
99101
ip=self.ip_address, port=self.local_port
100102
),
101103
isolation_level=self.isolation,
@@ -111,18 +113,18 @@ def pull_image(self):
111113
self.client.images.pull(self.image)
112114

113115
def start_container(self):
114-
env = dict(POSTGRES_PASSWORD='postgres', PGDATA=self.pg_data) # noqa: S106
115-
ports = {'5432': self.local_port}
116+
env = dict(POSTGRES_PASSWORD="postgres", PGDATA=self.pg_data) # noqa: S106
117+
ports = {"5432": self.local_port}
116118
print("Starting Postgres container ...", file=sys.stderr)
117119
# Uniq-ify the name as threaded tests will create multiple containers.
118-
name = '{}-{}.{}'.format(self.name, os.getpid(), next(NEXT_ID))
120+
name = "{}-{}.{}".format(self.name, os.getpid(), next(NEXT_ID))
119121
self.container = self.client.containers.run(
120122
self.image,
121123
detach=True,
122124
auto_remove=True,
123125
environment=env,
124126
name=name,
125-
network_mode='bridge',
127+
network_mode="bridge",
126128
ports=ports,
127129
remove=True,
128130
)
@@ -133,7 +135,7 @@ def find_free_port(self):
133135
# real free port. We close the socket after determnining which port
134136
# that was.
135137
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
136-
s.bind(('localhost', 0))
138+
s.bind(("localhost", 0))
137139
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
138140
self.local_port = s.getsockname()[1]
139141
print("Using port {}".format(self.local_port), file=sys.stderr)
@@ -148,7 +150,7 @@ def set_up_test_database(self):
148150
)
149151
c.autocommit = True
150152
cur = c.cursor()
151-
for stmt in self.init_sql.split(';'):
153+
for stmt in self.init_sql.split(";"):
152154
if stmt.strip():
153155
cur.execute(stmt)
154156
cur.close()

dbtesttools/fixtures.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def __init__(
7070
ModelBase,
7171
models_module, # NOSONAR
7272
patch_query_property=False,
73-
engine_fixture_name='SqliteMemoryFixture',
73+
engine_fixture_name="SqliteMemoryFixture",
7474
sessionmaker_class=None,
7575
engine_fixture_kwargs=None,
7676
future=False,
@@ -83,7 +83,7 @@ def __init__(
8383
self.sessionmaker_class = sessionmaker_class
8484
self.engine_fixture_kwargs = engine_fixture_kwargs or {}
8585
self.future = future
86-
self.engine_fixture_kwargs['future'] = self.future
86+
self.engine_fixture_kwargs["future"] = self.future
8787

8888
def make(self, dep_resources):
8989
print("Creating new database resource...", file=sys.stderr)
@@ -101,22 +101,21 @@ def has_savepoint(self):
101101

102102
def clean(self, resource):
103103
print("Cleaning up database resource...", file=sys.stderr)
104-
self.drop_tables(self.engine)
105104
self.db.cleanUp()
106105

107106
def pick_engine_fixture(self):
108-
env_name = os.environ.get('TEST_ENGINE_FIXTURE', None)
107+
env_name = os.environ.get("TEST_ENGINE_FIXTURE", None)
109108
if env_name is not None:
110109
self.engine_fixture_name = env_name
111110
import dbtesttools.engines
112111

113112
for _, module, _ in pkgutil.iter_modules(dbtesttools.engines.__path__):
114-
mod = importlib.import_module(f'dbtesttools.engines.{module}')
113+
mod = importlib.import_module(f"dbtesttools.engines.{module}")
115114

116115
for name, obj in mod.__dict__.items():
117116
if name == self.engine_fixture_name:
118117
return obj(**self.engine_fixture_kwargs)
119-
raise AttributeError(f'{self.engine_fixture_name} not found')
118+
raise AttributeError(f"{self.engine_fixture_name} not found")
120119

121120
def initialize_engine(self):
122121
self.db = self.pick_engine_fixture()
@@ -177,10 +176,6 @@ def create_tables(self, engine):
177176
metadata = self.ModelBase.metadata
178177
metadata.create_all(bind=engine)
179178

180-
def drop_tables(self, engine):
181-
metadata = self.ModelBase.metadata
182-
metadata.drop_all(bind=engine)
183-
184179
def rollback_transaction(self, txn):
185180
"""Roll back an in-progress transaction.
186181

dbtesttools/tests/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import os
2+
3+
import testresources
4+
from testscenarios import generate_scenarios
5+
6+
7+
def load_tests(loader, tests, pattern):
8+
this_dir = os.path.dirname(__file__)
9+
mytests = loader.discover(start_dir=this_dir, pattern=pattern)
10+
result = testresources.OptimisingTestSuite()
11+
result.addTests(generate_scenarios(mytests))
12+
result.addTests(generate_scenarios(tests))
13+
return result

dbtesttools/tests/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import sqlalchemy as sa
2+
from sqlalchemy.orm import declarative_base
3+
4+
ModelBase = declarative_base()
5+
6+
7+
class TestModel(ModelBase):
8+
__tablename__ = "test_model"
9+
id = sa.Column(sa.Integer, primary_key=True)
10+
name = sa.Column(sa.String)
11+
value = sa.Column(sa.Integer)

0 commit comments

Comments
 (0)