From 0b4e8abb87fb702c10c23195fae41b0f0997f426 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 10:49:34 +0100 Subject: [PATCH 01/16] Updated test workflow to update the code coverage file --- .github/workflows/test.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7a3ca31..87eab11 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,3 +39,12 @@ jobs: run: | export TOXENV=$(echo "py${{ matrix.python-version }}" | sed 's/\.//g') tox -- -p no:warnings + - name: Generate coverage report + run: coverage xml + if: ${{ success() }} + - name: Upload coverage data + uses: actions/upload-artifact@v3 + with: + name: coverage-data + path: "coverage.xml" + if-no-files-found: ignore From e7a8eb4d7dea0815bf7e49b3281e6afffd91a50d Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 10:55:01 +0100 Subject: [PATCH 02/16] Added step to upload the coverage --- .github/workflows/test.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 87eab11..047e0a9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,5 +46,29 @@ jobs: uses: actions/upload-artifact@v3 with: name: coverage-data - path: "coverage.xml" + path: 'coverage.xml' if-no-files-found: ignore + coverage: + name: Combine & check coverage. + runs-on: ubuntu-latest + needs: tests + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - run: python -m pip install --upgrade coverage[toml] + - name: Download coverage data. + uses: actions/download-artifact@v3 + with: + name: coverage-data + - name: Combine coverage + run: | + python -m coverage combine + python -m coverage html --skip-covered --skip-empty + - name: Upload HTML report if check failed. + uses: actions/upload-artifact@v3 + with: + name: html-report + path: htmlcov + if: ${{ failure() }} From 5451d00eb04c6d4f52b9c76e8985e281ad18baa3 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 11:18:52 +0100 Subject: [PATCH 03/16] Added step to upload the coverage --- .github/workflows/test.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 047e0a9..e774074 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -57,15 +57,14 @@ jobs: - uses: actions/setup-python@v4 with: python-version: '3.10' - - run: python -m pip install --upgrade coverage[toml] + - run: python -m pip install "coverage<5" - name: Download coverage data. uses: actions/download-artifact@v3 with: name: coverage-data - name: Combine coverage run: | - python -m coverage combine - python -m coverage html --skip-covered --skip-empty + python -m coverage html - name: Upload HTML report if check failed. uses: actions/upload-artifact@v3 with: From f613fcf56b287e13c8afc5ca308ef812c850a3ba Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 11:24:32 +0100 Subject: [PATCH 04/16] Added step to upload the coverage --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e774074..287b438 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,8 +46,10 @@ jobs: uses: actions/upload-artifact@v3 with: name: coverage-data - path: 'coverage.xml' + files: 'coverage.xml' + verbose: true if-no-files-found: ignore + if: ${{ success() }} coverage: name: Combine & check coverage. runs-on: ubuntu-latest From 160b2e6368d7b566d2cc7ce95b076fa51623c382 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 11:26:30 +0100 Subject: [PATCH 05/16] Added step to upload the coverage --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 287b438..32d2fb1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,12 +46,12 @@ jobs: uses: actions/upload-artifact@v3 with: name: coverage-data - files: 'coverage.xml' + path: 'coverage.xml' verbose: true if-no-files-found: ignore if: ${{ success() }} coverage: - name: Combine & check coverage. + name: coverage runs-on: ubuntu-latest needs: tests steps: From c1ee05c3c23ff9405607f80c86a1f5fe7803f771 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 11:31:55 +0100 Subject: [PATCH 06/16] Added step to upload the coverage --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 32d2fb1..3a6b2f1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -47,7 +47,6 @@ jobs: with: name: coverage-data path: 'coverage.xml' - verbose: true if-no-files-found: ignore if: ${{ success() }} coverage: From 948a445291da408ebe20a09efd8a1a8f2ac3ac90 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 11:36:01 +0100 Subject: [PATCH 07/16] Added step to upload the coverage --- .github/workflows/test.yml | 5 ++--- pytest.ini | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3a6b2f1..124f6c5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,9 +63,8 @@ jobs: uses: actions/download-artifact@v3 with: name: coverage-data - - name: Combine coverage - run: | - python -m coverage html + - name: Create HTML report + run: coverage html - name: Upload HTML report if check failed. uses: actions/upload-artifact@v3 with: diff --git a/pytest.ini b/pytest.ini index 58f54ac..d49f4c0 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,4 @@ [pytest] -addopts = --cov=pganonymize --cov-report term-missing --cov-config setup.cfg +addopts = --cov=pganonymize --cov-append --cov-report term-missing --cov-config setup.cfg testpaths = tests pganonymize python_paths = pganonymize From 1e956c8e086d1b08b2135b44e578e3421bb51259 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 12:09:24 +0100 Subject: [PATCH 08/16] Unzip the coverage artifact before creating the HTML report --- .github/workflows/test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 124f6c5..707380c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,12 +59,14 @@ jobs: with: python-version: '3.10' - run: python -m pip install "coverage<5" - - name: Download coverage data. + - name: Download coverage data uses: actions/download-artifact@v3 with: name: coverage-data - name: Create HTML report - run: coverage html + run: | + unzip coverage-data + coverage html - name: Upload HTML report if check failed. uses: actions/upload-artifact@v3 with: From c92172822d547c92a2b856777725db07d00f2959 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 12:58:32 +0100 Subject: [PATCH 09/16] Define the download path for the artifact file --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 707380c..6a98b41 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -61,11 +61,12 @@ jobs: - run: python -m pip install "coverage<5" - name: Download coverage data uses: actions/download-artifact@v3 + id: download with: name: coverage-data - name: Create HTML report run: | - unzip coverage-data + unzip ${{ steps.download.outputs.download-path }} coverage html - name: Upload HTML report if check failed. uses: actions/upload-artifact@v3 From df7bf7f56fabc51d24fd138e40349f6982fea2fa Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 13:05:15 +0100 Subject: [PATCH 10/16] Fixed the artifact file --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6a98b41..cef7708 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -66,7 +66,7 @@ jobs: name: coverage-data - name: Create HTML report run: | - unzip ${{ steps.download.outputs.download-path }} + unzip ${{ steps.download.outputs.download-path }}/coverage-data coverage html - name: Upload HTML report if check failed. uses: actions/upload-artifact@v3 From 48826337dc92158577512c75f7d013ccc3e630b5 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 13:28:30 +0100 Subject: [PATCH 11/16] Try to finde the coverage artifact --- .github/workflows/test.yml | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cef7708..d29fabc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,7 +34,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install tox "coverage<5" + pip install --use-pep517 tox "coverage<5" - name: Run tests run: | export TOXENV=$(echo "py${{ matrix.python-version }}" | sed 's/\.//g') @@ -45,8 +45,8 @@ jobs: - name: Upload coverage data uses: actions/upload-artifact@v3 with: - name: coverage-data - path: 'coverage.xml' + name: coverage + path: coverage.xml if-no-files-found: ignore if: ${{ success() }} coverage: @@ -58,19 +58,20 @@ jobs: - uses: actions/setup-python@v4 with: python-version: '3.10' - - run: python -m pip install "coverage<5" - - name: Download coverage data + - run: | + python -m pip install --upgrade pip + pip install --use-pep517 "coverage<5" + - name: Download coverage uses: actions/download-artifact@v3 - id: download with: - name: coverage-data + name: coverage + - run: ls -lh . - name: Create HTML report - run: | - unzip ${{ steps.download.outputs.download-path }}/coverage-data - coverage html - - name: Upload HTML report if check failed. + run: coverage html + - name: Upload HTML report uses: actions/upload-artifact@v3 with: name: html-report path: htmlcov - if: ${{ failure() }} + if-no-files-found: ignore + if: ${{ success() }} From 27592da53d02f9fe02ca51e6edc0ac8ea8ae8a82 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 13:33:13 +0100 Subject: [PATCH 12/16] Try to finde the coverage artifact --- .github/workflows/test.yml | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d29fabc..ce09afd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,38 +40,12 @@ jobs: export TOXENV=$(echo "py${{ matrix.python-version }}" | sed 's/\.//g') tox -- -p no:warnings - name: Generate coverage report - run: coverage xml + run: coverage html if: ${{ success() }} - name: Upload coverage data uses: actions/upload-artifact@v3 with: name: coverage - path: coverage.xml + path: hmtlcov if-no-files-found: ignore if: ${{ success() }} - coverage: - name: coverage - runs-on: ubuntu-latest - needs: tests - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - run: | - python -m pip install --upgrade pip - pip install --use-pep517 "coverage<5" - - name: Download coverage - uses: actions/download-artifact@v3 - with: - name: coverage - - run: ls -lh . - - name: Create HTML report - run: coverage html - - name: Upload HTML report - uses: actions/upload-artifact@v3 - with: - name: html-report - path: htmlcov - if-no-files-found: ignore - if: ${{ success() }} From 2554ce69d923a7c012668ae8967711cb666bce37 Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Fri, 2 Dec 2022 13:35:15 +0100 Subject: [PATCH 13/16] Fixed the html coverage path --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ce09afd..001aeba 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,6 +46,6 @@ jobs: uses: actions/upload-artifact@v3 with: name: coverage - path: hmtlcov + path: htmlcov if-no-files-found: ignore if: ${{ success() }} From dae03174ff3f6ffb92b25ff2221de1213bf3b47b Mon Sep 17 00:00:00 2001 From: bobslee Date: Tue, 27 Feb 2024 20:41:55 +0100 Subject: [PATCH 14/16] Add update_json provider This provider will replace json and jsonb data values with a specified provider configuration per data type. Also improve the json.dumps() in the escape_str_value() function with default to str output for objects which can't be serialized. --- docs/schema.rst | 31 ++++++++++++++ pganonymize/providers.py | 29 +++++++++++++ pganonymize/utils.py | 2 +- tests/test_providers.py | 89 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) diff --git a/docs/schema.rst b/docs/schema.rst index b8a99b3..c81eba9 100644 --- a/docs/schema.rst +++ b/docs/schema.rst @@ -423,6 +423,37 @@ This provider will replace values with a unique UUID4. provider: name: uuid4 +``update_json`` +~~~~~~~~~~~~~~~ + +**Arguments:** + +* ``update_values_type`` + +This provider will replace json and jsonb data values with a specified provider configuration per data type. + + +**Example usage**: + +.. code-block:: yaml + + tables: + - payment_transaction: + fields: + - data: + provider: + name: update_json + update_values_type: + str: + provider: + name: uuid + int: + provider: + name: fake.pyint + float: + provider: + name: fake.pyfloat + .. _Faker: https://github.com/joke2k/faker .. _Faker documentation: http://faker.rtfd.org/ .. _native UUIDs: https://www.postgresql.org/docs/current/datatype-uuid.html diff --git a/pganonymize/providers.py b/pganonymize/providers.py index cbc4c86..30d6fe6 100644 --- a/pganonymize/providers.py +++ b/pganonymize/providers.py @@ -246,3 +246,32 @@ class UUID4Provider(Provider): @classmethod def alter_value(cls, original_value, **kwargs): return uuid4() + + +@register('update_json') +class UpdateJSONProvider(Provider): + """Provider to update JSON data (currently values) by + providers.""" + + @classmethod + def alter_value(cls, original_value, **kwargs): + def update_dict(input_dict, update_values_type={}): + """Update dictionary with recursion (nested dictionaries).""" + if not update_values_type: + return + for key, val in input_dict.items(): + if isinstance(val, dict): + update_dict(val, update_values_type=update_values_type) + else: + val_type = type(val).__name__ + val_update = update_values_type.get(val_type) + if val_update: + if val_update.get('provider'): + provider_config = val_update.get('provider') + provider_class = provider_registry.get_provider(provider_config['name']) + provider_value = provider_class.alter_value(val, **provider_config) + input_dict[key] = provider_value + else: + input_dict[key] = val_update + update_dict(original_value, update_values_type=kwargs.get('update_values_type', {})) + return original_value diff --git a/pganonymize/utils.py b/pganonymize/utils.py index b756551..11be694 100644 --- a/pganonymize/utils.py +++ b/pganonymize/utils.py @@ -323,7 +323,7 @@ def escape_str_replace(value): :return: Escaped value """ if isinstance(value, dict): - return json.dumps(value).encode() + return json.dumps(value, default=str).encode() return value diff --git a/tests/test_providers.py b/tests/test_providers.py index 45233e2..01f096c 100644 --- a/tests/test_providers.py +++ b/tests/test_providers.py @@ -211,3 +211,92 @@ class TestUUID4Provider(object): @pytest.mark.parametrize('value, expected', [(None, uuid.UUID), ('Foo', uuid.UUID)]) def test_alter_value(self, value, expected): assert type(providers.UUID4Provider.alter_value(value)) == expected + + +class TestUpdateJSONProvider(object): + + @pytest.mark.parametrize('value, update_values_type, expected', [ + ({'foo': 'bar'}, {'str': {'provider': {'name': 'set', 'value': 'foobar'}}}, {'foo': 'foobar'}), + ({'chef': 'cuisine'}, {'str': {'provider': {'name': 'uuid4'}}}, {'chef': uuid.UUID}) + ]) + def test_str_type(self, value, update_values_type, expected): + res = providers.UpdateJSONProvider.alter_value(value, update_values_type=update_values_type) + if res.get('foo'): + assert res['foo'] == expected['foo'] + if res.get('chef'): + assert type(res['chef']) is expected['chef'] + + def test_int_type(self): + test_dict = {'foo': 123} + + update_values_type = {'int': {'provider': {'name': 'set', 'value': 999}}} + res = providers.UpdateJSONProvider.alter_value(test_dict, update_values_type=update_values_type) + assert res['foo'] == 999 + + update_values_type = {'int': {'provider': {'name': 'clear'}}} + res = providers.UpdateJSONProvider.alter_value(test_dict, update_values_type=update_values_type) + assert res['foo'] is None + + def test_float_type(self): + test_dict = {'foo': 123.45, 'bar': 234.77} + + update_values_type = {'float': {'provider': {'name': 'set', 'value': 999.99}}} + res = providers.UpdateJSONProvider.alter_value(test_dict, update_values_type=update_values_type) + assert res['foo'] == 999.99 + assert res['bar'] == 999.99 + + update_values_type = {'float': {'provider': {'name': 'clear'}}} + res = providers.UpdateJSONProvider.alter_value(test_dict, update_values_type=update_values_type) + assert res['foo'] is None + + def test_multi_types(self): + test_dict = { + 'fooInt': 123, + 'fooFloat': 123.45, + 'fooStr': 'some foo', + 'barStr': 'some bar' + } + update_values_type = { + 'int': {'provider': {'name': 'set', 'value': 999}}, + 'float': {'provider': {'name': 'set', 'value': 999.99}}, + 'str': {'provider': {'name': 'set', 'value': 'foobar'}}, + } + res = providers.UpdateJSONProvider.alter_value(test_dict, update_values_type=update_values_type) + assert res['fooInt'] == 999 + assert res['fooFloat'] == 999.99 + assert res['fooStr'] == 'foobar' + assert res['barStr'] == 'foobar' + + def test_nested_json(self): + test_dict = { + 'fooInt': 123, + 'fooFloat': 123.45, + 'fooStr': 'some foo', + 'barStr': 'some bar', + 'nested': { + 'fooInt': 444, + 'fooFloat': 50.9, + 'fooStr': 'abc', + 'anotherNested': { + 'fooInt': 555, + 'fooFloat': 6000.123, + 'fooStr': 'xyz', + } + } + } + update_values_type = { + 'int': {'provider': {'name': 'set', 'value': 999}}, + 'float': {'provider': {'name': 'set', 'value': 999.99}}, + 'str': {'provider': {'name': 'set', 'value': 'foobar'}}, + } + res = providers.UpdateJSONProvider.alter_value(test_dict, update_values_type=update_values_type) + assert res['fooInt'] == 999 + assert res['fooFloat'] == 999.99 + assert res['fooStr'] == 'foobar' + assert res['barStr'] == 'foobar' + assert res['nested']['fooInt'] == 999 + assert res['nested']['fooFloat'] == 999.99 + assert res['nested']['fooStr'] == 'foobar' + assert res['nested']['anotherNested']['fooInt'] == 999 + assert res['nested']['anotherNested']['fooFloat'] == 999.99 + assert res['nested']['anotherNested']['fooStr'] == 'foobar' From 11206ba12630e5b8a6fda62fe693d2b15cff0b4a Mon Sep 17 00:00:00 2001 From: bobslee Date: Wed, 28 Feb 2024 20:03:45 +0100 Subject: [PATCH 15/16] Improvements for the update_json provider - schema.rst file: Fix typo concerning the uuid4 provider. - Format docstring in UpdateJSONProvider. - Add test: test_type_not_specified - Don't replace the value if there's no data type (provider) specified in the schema - covered by test: test_type_not_specified. --- docs/schema.rst | 2 +- pganonymize/providers.py | 5 +---- tests/test_providers.py | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/schema.rst b/docs/schema.rst index c81eba9..866a44e 100644 --- a/docs/schema.rst +++ b/docs/schema.rst @@ -446,7 +446,7 @@ This provider will replace json and jsonb data values with a specified provider update_values_type: str: provider: - name: uuid + name: uuid4 int: provider: name: fake.pyint diff --git a/pganonymize/providers.py b/pganonymize/providers.py index 30d6fe6..d25d53c 100644 --- a/pganonymize/providers.py +++ b/pganonymize/providers.py @@ -250,8 +250,7 @@ def alter_value(cls, original_value, **kwargs): @register('update_json') class UpdateJSONProvider(Provider): - """Provider to update JSON data (currently values) by - providers.""" + """Provider to update JSON data (currently values) by providers.""" @classmethod def alter_value(cls, original_value, **kwargs): @@ -271,7 +270,5 @@ def update_dict(input_dict, update_values_type={}): provider_class = provider_registry.get_provider(provider_config['name']) provider_value = provider_class.alter_value(val, **provider_config) input_dict[key] = provider_value - else: - input_dict[key] = val_update update_dict(original_value, update_values_type=kwargs.get('update_values_type', {})) return original_value diff --git a/tests/test_providers.py b/tests/test_providers.py index 01f096c..4484316 100644 --- a/tests/test_providers.py +++ b/tests/test_providers.py @@ -267,6 +267,22 @@ def test_multi_types(self): assert res['fooStr'] == 'foobar' assert res['barStr'] == 'foobar' + def test_type_not_specified(self): + test_dict = { + 'fooInt': 123, + 'fooFloat': 123.45, + 'fooStr': 'some foo', + 'barStr': 'some bar' + } + update_values_type = { + 'int': {'provider': {'name': 'set', 'value': 999}}, + } + res = providers.UpdateJSONProvider.alter_value(test_dict, update_values_type=update_values_type) + assert res['fooInt'] == 999 + assert res['fooFloat'] == 123.45 + assert res['fooStr'] == 'some foo' + assert res['barStr'] == 'some bar' + def test_nested_json(self): test_dict = { 'fooInt': 123, From 66d4133b13e5678e1b75ff018fc3ae637d66044e Mon Sep 17 00:00:00 2001 From: Henning Kage Date: Thu, 29 Feb 2024 07:48:09 +0100 Subject: [PATCH 16/16] Release 0.11.0 --- CHANGELOG.rst | 5 +++++ pganonymize/version.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 057454f..7f73dc5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,11 @@ Changelog Development ----------- +0.11.0 (2024-02-29) +------------------- + +* `#52 `_: Add update_json provider (`bobslee `_) + 0.10.0 (2022-11-29) ------------------- diff --git a/pganonymize/version.py b/pganonymize/version.py index a8cad44..4cad2e2 100644 --- a/pganonymize/version.py +++ b/pganonymize/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -__version__ = '0.10.0' +__version__ = '0.11.0'