diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e4336dc..6cb55a3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: files: ^src/|^scripts/|^migrant/ - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 + rev: v3.8.0 hooks: - id: pyupgrade args: ["--py39-plus"] @@ -28,3 +28,8 @@ repos: hooks: - id: isort args: ["--profile", "black", "--line-length", "88", "--trailing-comma"] + + - repo: https://github.com/pycqa/flake8 + rev: 6.0.0 + hooks: + - id: flake8 diff --git a/CHANGES.rst b/CHANGES.rst index 7be5863..3a4b4d7 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,7 +6,7 @@ CHANGELOG 4.2.4 (unreleased) ------------------ -- Nothing changed yet. +- Updates to moto and boto. 4.2.3 (2023-06-26) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..66eb35c --- /dev/null +++ b/setup.cfg @@ -0,0 +1,61 @@ +[flake8] +ignore= + # These are ignored by default[*]: + # [*] http://pep8.readthedocs.org/en/latest/intro.html#error-codes + # E123 closing bracket does not match indentation of opening bracket's + # line + # E133 closing bracket is missing indentation + # E226 missing whitespace around arithmetic operator + E123,E133,E226, + # These are minor/inconvenient to fix: + # E125: continuation line does not distinguish itself from next logical + # line + # E126: continuation line over-indented for hanging indent + # W391: blank line at end of file + # E128: continuation line under-indented for visual indent + # E124: closing bracket does not match visual indentation + # E127: continuation line over-indented for visual indent + # E301: expected 1 blank line, found 0 + E125,E126,W391,E128,E124,E127,E301, + # E203: whitespace before ':' + # Conflicts with black formatting + E203, + # This is misguided: we use '##' to indicate temporarily commented out code + # E265: block comment should start with '# ' + # This appears to be a false positive: + # E131: continuation line unaligned for hanging indent + # E122: continuation line missing indentation or outdented + E265,E131,E122, + # E402 is ignored since we use future.standard_library.install_aliases(). + # Once we no longer need Python 2 compatibility we can unignore it. + # Python 3 #BBB + E402, + # Pydocstyle codes ignored by default + D203,D212,D213,D404, + # Missing docstrings: we don't care yet + D100,D101,D102,D103,D104,D105,D106,D107, + # Only false positives: + # D402: First line should not be the function's "signature" + D402, + # Codes that assume valid ReST with sections in docstrings + D214,D215, + D405,D406,D407,D408,D409,D410,D411,D412,D413,D414 + # Pydocstyle codes we silence until our code is fully clean on them. + # See http://www.pydocstyle.org/en/2.1.1/error_codes.html + D205,D208, + D400,D401,D403, + # W503 contradicts current pep8 as can be seen here: + # https://bugs.python.org/issue26763 + W503,W504, + +# in doctests _ is a perfectly valid pre-defined variable name that holds +# the value of the previous statement +builtins=_ +doctests=true +max-line-length=88 + +[pycodestyle] +max-line-length=88 + +[isort] +known_first_party=shoobx diff --git a/setup.py b/setup.py index 3fd6260..5ca320d 100644 --- a/setup.py +++ b/setup.py @@ -17,6 +17,7 @@ def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() + setup( name="shoobx.mocks3", version='4.2.4.dev0', diff --git a/src/shoobx/mocks3/models.py b/src/shoobx/mocks3/models.py index 06aace4..14bc29e 100644 --- a/src/shoobx/mocks3/models.py +++ b/src/shoobx/mocks3/models.py @@ -99,7 +99,6 @@ def __set__(self, inst, value): class Key(models.FakeKey): - _last_modified = _InfoProperty("last_modified") storage_class = _InfoProperty("storage_class") metadata = _InfoProperty("metadata") @@ -141,9 +140,7 @@ def __init__( self.lock_until = lock_until self._tick = 0 self.disposed = None - self.checksum_value = checksum_value - self.checksum_algorithm = None - + self.checksum_algorithm = "md5" def __getstate__(self): return self.__dict__.copy() @@ -182,6 +179,15 @@ def etag(self): self._etag = file_hash.hexdigest() return f'"{self._etag}"' + @property + def checksum_value(self): + return self._etag + + @checksum_value.setter + def checksum_value(self, value): + # self.etag already generates an md5 hash if needed. + self.etag + @property def last_modified(self): return datetime.datetime.strptime(self._last_modified, "%Y-%m-%dT%H:%M:%S.%fZ") @@ -331,7 +337,6 @@ def iterlists(self): class Part: - _last_modified = _InfoProperty("last_modified") etag = _InfoProperty("etag") @@ -401,7 +406,6 @@ def delete(self): class Multipart: - key_name = _InfoProperty("key_name") metadata = _InfoProperty("metadata") tags = _InfoProperty("tags") @@ -519,7 +523,6 @@ def __len__(self): class Bucket(models.FakeBucket): - policy = _InfoProperty("policy") versioning_status = _InfoProperty("versioning_status") acl = _AclProperty("acl") @@ -579,6 +582,15 @@ def rules(self): for rule in raw_rules: exp = rule.get("Expiration") tran = rule.get("Transition") + tranisitions = [] + if tran: + tranisitions.append( + models.LifecycleTransition( + date=tran.get("Date") or None, + days=tran["Days"], + storage_class=tran["StorageClass"], + ) + ) rules.append( models.LifecycleRule( rule_id=rule.get("ID"), @@ -586,9 +598,8 @@ def rules(self): status=rule["Status"], expiration_days=exp.get("Days") if exp else None, expiration_date=exp.get("Date") if exp else None, - transition_days=tran.get("Days") if tran else None, - transition_date=tran.get("Date") if tran else None, - storage_class=tran["StorageClass"] if tran else None, + transitions=tranisitions, + noncurrent_version_transitions=[], ) ) return rules @@ -778,8 +789,9 @@ def complete_multipart_upload(self, bucket_name, multipart_id, body): return multipart, value, etag def reset(self): - # For every key and multipart, Moto opens a TemporaryFile to write the value of those keys - # Ensure that these TemporaryFile-objects are closed, and leave no filehandles open + # For every key and multipart, Moto opens a TemporaryFile to write the value of + # those keys. Ensure that these TemporaryFile-objects are closed, and leave no + # filehandles open for bucket in self.buckets.values(): for key in bucket.keys.values(): if isinstance(key, Key): diff --git a/src/shoobx/mocks3/tests/test_config.py b/src/shoobx/mocks3/tests/test_config.py index 3652004..6151ff9 100644 --- a/src/shoobx/mocks3/tests/test_config.py +++ b/src/shoobx/mocks3/tests/test_config.py @@ -5,11 +5,11 @@ ############################################################################### """Shoobx S3 Config Test """ -import mock import os import shutil import tempfile import unittest +from unittest import mock from shoobx.mocks3 import config @@ -43,4 +43,4 @@ def test_configure_dupe_env_key(self): with open(config_path, "w") as file: file.write(TEST_CONFIG % self._dir) # Ensure loading does not fail. - app = config.configure(config_path) + config.configure(config_path) diff --git a/src/shoobx/mocks3/tests/test_s3_boto3.py b/src/shoobx/mocks3/tests/test_s3_boto3.py index f087b64..afcb551 100644 --- a/src/shoobx/mocks3/tests/test_s3_boto3.py +++ b/src/shoobx/mocks3/tests/test_s3_boto3.py @@ -906,5 +906,8 @@ def test_bucket_lifecycle_rules(self): } ] } - self.bucket.LifecycleConfiguration().put(LifecycleConfiguration=cfg) + + self.assertTrue( + self.bucket.LifecycleConfiguration().put(LifecycleConfiguration=cfg) + ) self.assertEqual(cfg["Rules"], self.bucket.LifecycleConfiguration().rules)