Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

acstore

Package Overview
Dependencies
Maintainers
2
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

acstore - npm Package Compare versions

Comparing version
20230519
to
20240128
+17
.readthedocs.yaml
# Read the Docs configuration file for Sphinx projects
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.12"
sphinx:
configuration: docs/conf.py
fail_on_warning: false
python:
install:
- requirements: docs/requirements.txt
# -*- coding: utf-8 -*-
"""Attribute container JSON serializer."""
from acstore.containers import manager as containers_manager
from acstore.helpers import schema as schema_helper
class AttributeContainerJSONSerializer(object):
"""Attribute container JSON serializer."""
_CONTAINERS_MANAGER = containers_manager.AttributeContainersManager
@classmethod
def ConvertAttributeContainerToJSON(cls, attribute_container):
"""Converts an attribute container object into a JSON dictioary.
The resulting dictionary of the JSON serialized objects consists of:
{
'__type__': 'AttributeContainer'
'__container_type__': ...
...
}
Here '__type__' indicates the object base type. In this case
'AttributeContainer'.
'__container_type__' indicates the container type and rest of the elements
of the dictionary that make up the attributes of the container.
Args:
attribute_container (AttributeContainer): attribute container.
Returns:
dict[str, object]: JSON serialized objects.
"""
try:
schema = cls._CONTAINERS_MANAGER.GetSchema(
attribute_container.CONTAINER_TYPE)
except ValueError:
schema = {}
json_dict = {
'__type__': 'AttributeContainer',
'__container_type__': attribute_container.CONTAINER_TYPE}
for attribute_name, attribute_value in attribute_container.GetAttributes():
data_type = schema.get(attribute_name, None)
serializer = schema_helper.SchemaHelper.GetAttributeSerializer(
data_type, 'json')
if serializer:
attribute_value = serializer.SerializeValue(attribute_value)
# JSON will not serialize certain runtime types like set, therefore
# these are cast to list first.
if isinstance(attribute_value, set):
attribute_value = list(attribute_value)
json_dict[attribute_name] = attribute_value
return json_dict
@classmethod
def ConvertJSONToAttributeContainer(cls, json_dict):
"""Converts a JSON dictionary into an attribute container object.
The dictionary of the JSON serialized objects consists of:
{
'__type__': 'AttributeContainer'
'__container_type__': ...
...
}
Here '__type__' indicates the object base type. In this case
'AttributeContainer'.
'__container_type__' indicates the container type and rest of the elements
of the dictionary that make up the attributes of the container.
Args:
json_dict (dict[str, object]): JSON serialized objects.
Returns:
AttributeContainer: attribute container.
"""
# Use __container_type__ to indicate the attribute container type.
container_type = json_dict.get('__container_type__', None)
attribute_container = cls._CONTAINERS_MANAGER.CreateAttributeContainer(
container_type)
supported_attribute_names = attribute_container.GetAttributeNames()
for attribute_name, attribute_value in json_dict.items():
if attribute_name in ('__container_type__', '__type__'):
continue
# Be strict about which attributes to set.
if attribute_name not in supported_attribute_names:
continue
setattr(attribute_container, attribute_name, attribute_value)
return attribute_container
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
[tool.docformatter]
black = false
non-cap = ["dfDateTime", "dfImageTools", "dfVFS", "dfWinReg", "dtFabric"]
non-strict = false
wrap-summaries = 80
wrap-descriptions = 80
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Tests for the attribute container JSON serializer."""
import unittest
from acstore.containers import manager
from acstore.helpers import json_serializer
from tests import test_lib as shared_test_lib
class AttributeContainerJSONSerializerTest(shared_test_lib.BaseTestCase):
"""Tests for the attribute container JSON serializer."""
_TEST_MANAGER = manager.AttributeContainersManager
_TEST_SERIALIZER = json_serializer.AttributeContainerJSONSerializer
def testConvertAttributeContainerToJSON(self):
"""Tests the ConvertAttributeContainerToJSON function."""
attribute_container = shared_test_lib.TestAttributeContainer()
attribute_container.attribute = 'MyAttribute'
expected_json_dict = {
'__container_type__': 'test_container',
'__type__': 'AttributeContainer',
'attribute': 'MyAttribute'}
json_dict = self._TEST_SERIALIZER.ConvertAttributeContainerToJSON(
attribute_container)
self.assertEqual(json_dict, expected_json_dict)
def testConvertJSONToAttributeContainer(self):
"""Tests the ConvertJSONToAttributeContainer function."""
json_dict = {
'__container_type__': 'test_container',
'__type__': 'AttributeContainer',
'attribute': 'MyAttribute'}
self._TEST_MANAGER.RegisterAttributeContainer(
shared_test_lib.TestAttributeContainer)
try:
attribute_container = (
self._TEST_SERIALIZER.ConvertJSONToAttributeContainer(json_dict))
finally:
self._TEST_MANAGER.DeregisterAttributeContainer(
shared_test_lib.TestAttributeContainer)
self.assertIsNotNone(attribute_container)
self.assertEqual(attribute_container.CONTAINER_TYPE, 'test_container')
self.assertEqual(attribute_container.attribute, 'MyAttribute')
if __name__ == '__main__':
unittest.main()
+4
-1

@@ -61,3 +61,3 @@ # Run tests on Fedora and Ubuntu Docker images using GIFT CORP and GIFT PPA on commit

apt-get update -q
apt-get install -y build-essential python3 python3-dev python3-distutils python3-setuptools python3-yaml
apt-get install -y build-essential python3 python3-dev python3-distutils python3-pip python3-setuptools python3-wheel python3-yaml
- name: Run tests

@@ -73,2 +73,5 @@ env:

if test -f tests/end-to-end.py; then PYTHONPATH=. python3 ./tests/end-to-end.py --debug -c config/end-to-end.ini; fi
- name: Update setuptools
run: |
python3 -m pip install -U setuptools
- name: Build source distribution

@@ -75,0 +78,0 @@ run: |

+2
-2

@@ -17,3 +17,3 @@ # Run docs tox tests on Ubuntu Docker images using GIFT PPA

include:
- python-version: '3.8'
- python-version: '3.12'
toxenv: 'docs'

@@ -40,3 +40,3 @@ container:

apt-get update -q
apt-get install -y build-essential git libffi-dev python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-pip python3-setuptools python3-yaml
apt-get install -y build-essential git python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-pip python3-setuptools python3-yaml
- name: Install tox

@@ -43,0 +43,0 @@ run: |

@@ -18,11 +18,13 @@ # Run tox tests on Ubuntu Docker images using GIFT PPA

- python-version: '3.7'
toxenv: 'py37'
toxenv: 'py37,wheel'
- python-version: '3.8'
toxenv: 'py38'
toxenv: 'py38,wheel'
- python-version: '3.9'
toxenv: 'py39'
toxenv: 'py39,wheel'
- python-version: '3.10'
toxenv: 'py310'
toxenv: 'py310,wheel'
- python-version: '3.11'
toxenv: 'py311'
toxenv: 'py311,wheel'
- python-version: '3.12'
toxenv: 'py312,wheel'
container:

@@ -48,3 +50,3 @@ image: ubuntu:22.04

apt-get update -q
apt-get install -y build-essential git libffi-dev python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-pip python3-setuptools python3-yaml
apt-get install -y build-essential git python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-pip python3-setuptools python3-yaml
- name: Install tox

@@ -63,4 +65,4 @@ run: |

include:
- python-version: '3.8'
toxenv: 'py38,coverage'
- python-version: '3.10'
toxenv: 'coverage'
container:

@@ -86,3 +88,3 @@ image: ubuntu:22.04

apt-get update -q
apt-get install -y build-essential git libffi-dev python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-pip python3-setuptools python3-yaml
apt-get install -y build-essential git python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-pip python3-setuptools python3-yaml
- name: Install tox

@@ -103,3 +105,3 @@ run: |

include:
- python-version: '3.11'
- python-version: '3.12'
toxenv: 'lint'

@@ -126,3 +128,3 @@ container:

apt-get update -q
apt-get install -y build-essential git libffi-dev python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-pip python3-setuptools python3-yaml
apt-get install -y build-essential git python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-pip python3-setuptools python3-yaml
- name: Install tox

@@ -129,0 +131,0 @@ run: |

Metadata-Version: 2.1
Name: acstore
Version: 20230519
Version: 20240128
Summary: Attribute Container Storage (ACStore).

@@ -9,9 +9,11 @@ Home-page: https://github.com/log2timeline/acstore

License: Apache License, Version 2.0
Classifier:
Classifier: Environment :: Console
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python
Requires-Python: >=3.7
Description-Content-Type: text/plain
License-File: ACKNOWLEDGEMENTS
License-File: AUTHORS
License-File: LICENSE
License-File: README
ACStore, or Attribute Container Storage, provides a stand-alone implementation to read and write attribute container storage files.

@@ -1,2 +0,1 @@

pip>=7.0.0
PyYAML>=3.10
.pylintrc
.style.yapf
.readthedocs.yaml
.yamllint.yaml

@@ -12,2 +12,3 @@ ACKNOWLEDGEMENTS

dependencies.ini
pyproject.toml
requirements.txt

@@ -38,2 +39,3 @@ run_tests.py

acstore/helpers/__init__.py
acstore/helpers/json_serializer.py
acstore/helpers/schema.py

@@ -71,2 +73,3 @@ acstore/helpers/yaml_definitions_file.py

tests/helpers/__init__.py
tests/helpers/json_serializer.py
tests/helpers/schema.py

@@ -73,0 +76,0 @@ tests/helpers/yaml_definitions_file.py

[project]
name: acstore
name_description: ACStore
status: alpha
maintainer: Log2Timeline maintainers <log2timeline-maintainers@googlegroups.com>

@@ -5,0 +6,0 @@ homepage_url: https://github.com/log2timeline/acstore

@@ -8,2 +8,2 @@ # -*- coding: utf-8 -*-

__version__ = '20230519'
__version__ = '20240128'

@@ -52,8 +52,8 @@ # -*- coding: utf-8 -*-

This is the base class for those object that exists primarily as
a container of attributes with basic accessors and mutators.
This is the base class for those object that exists primarily as a container
of attributes with basic accessors and mutators.
The CONTAINER_TYPE class attribute contains a string that identifies
the container type, for example the container type "event" identifiers
an event object.
The CONTAINER_TYPE class attribute contains a string that identifies the
container type, for example the container type "event" identifiers an event
object.

@@ -60,0 +60,0 @@ Attributes are public class members of a serializable type. Protected and

@@ -78,3 +78,3 @@ # -*- coding: utf-8 -*-

if not container_class:
raise ValueError(f'Unsupported container type: {container_type:s}')
raise ValueError(f'Unsupported container type: {container_type!s}')

@@ -81,0 +81,0 @@ return getattr(container_class, 'SCHEMA', {})

@@ -25,5 +25,5 @@ # -*- coding: utf-8 -*-

Raises:
OSError: if the store cannot be read from.
IOError: if the store cannot be read from.
Raises:
OSError: if the store cannot be read from.
IOError: if the store cannot be read from.
"""

@@ -30,0 +30,0 @@ if not self._is_open:

@@ -26,3 +26,3 @@ # -*- coding: utf-8 -*-

name: 'windows_eventlog_message_file'
name: windows_eventlog_message_file
attributes:

@@ -47,4 +47,4 @@ - name: path

_SUPPORTED_KEYS = frozenset([
'name',
'attributes'])
'attributes',
'name'])

@@ -51,0 +51,0 @@ def _ReadDefinition(self, definition_values):

@@ -85,5 +85,5 @@ # -*- coding: utf-8 -*-

Raises:
OSError: if the store cannot be read from.
IOError: if the store cannot be read from.
Raises:
OSError: if the store cannot be read from.
IOError: if the store cannot be read from.
"""

@@ -95,5 +95,5 @@

Raises:
OSError: if the store cannot be written to.
IOError: if the store cannot be written to.
Raises:
OSError: if the store cannot be written to.
IOError: if the store cannot be written to.
"""

@@ -113,4 +113,4 @@

@abc.abstractmethod
def _WriteNewAttributeContainer(self, container):
"""Writes a new attribute container to the store.
def _WriteExistingAttributeContainer(self, container):
"""Writes an existing attribute container to the store.

@@ -122,4 +122,4 @@ Args:

@abc.abstractmethod
def _WriteExistingAttributeContainer(self, container):
"""Writes an existing attribute container to the store.
def _WriteNewAttributeContainer(self, container):
"""Writes a new attribute container to the store.

@@ -157,8 +157,2 @@ Args:

AttributeContainer: attribute container or None if not available.
Raises:
IOError: when the store is closed or if an unsupported identifier is
provided.
OSError: when the store is closed or if an unsupported identifier is
provided.
"""

@@ -176,6 +170,2 @@

AttributeContainer: attribute container or None if not available.
Raises:
IOError: when the store is closed.
OSError: when the store is closed.
"""

@@ -194,6 +184,2 @@

generator(AttributeContainer): attribute container generator.
Raises:
IOError: when the store is closed.
OSError: when the store is closed.
"""

@@ -248,1 +234,49 @@

self._WriteExistingAttributeContainer(container)
class AttributeContainerStoreWithReadCache(AttributeContainerStore):
"""Interface of an attribute container store with read cache.
Attributes:
format_version (int): storage format version.
"""
# pylint: disable=abstract-method
# The maximum number of cached attribute containers
_MAXIMUM_CACHED_CONTAINERS = 32 * 1024
def __init__(self):
"""Initializes an attribute container store with read cache."""
super(AttributeContainerStoreWithReadCache, self).__init__()
self._attribute_container_cache = collections.OrderedDict()
def _CacheAttributeContainerByIndex(self, attribute_container, index):
"""Caches a specific attribute container.
Args:
attribute_container (AttributeContainer): attribute container.
index (int): attribute container index.
"""
if len(self._attribute_container_cache) >= self._MAXIMUM_CACHED_CONTAINERS:
self._attribute_container_cache.popitem(last=True)
lookup_key = f'{attribute_container.CONTAINER_TYPE:s}.{index:d}'
self._attribute_container_cache[lookup_key] = attribute_container
self._attribute_container_cache.move_to_end(lookup_key, last=False)
def _GetCachedAttributeContainer(self, container_type, index):
"""Retrieves a specific cached attribute container.
Args:
container_type (str): attribute container type.
index (int): attribute container index.
Returns:
AttributeContainer: attribute container or None if not available.
"""
lookup_key = f'{container_type:s}.{index:d}'
attribute_container = self._attribute_container_cache.get(lookup_key, None)
if attribute_container:
self._attribute_container_cache.move_to_end(lookup_key, last=False)
return attribute_container

@@ -5,4 +5,4 @@ # -*- coding: utf-8 -*-

import ast
import collections
import itertools
import json
import os

@@ -126,3 +126,4 @@ import pathlib

data_type, 'json')
value = serializer.DeserializeValue(value)
json_dict = json.loads(value)
value = serializer.DeserializeValue(json_dict)

@@ -165,3 +166,4 @@ return value

return serializer.SerializeValue(value)
json_dict = serializer.SerializeValue(value)
return json.dumps(json_dict)

@@ -171,3 +173,4 @@ return value

class SQLiteAttributeContainerStore(interface.AttributeContainerStore):
class SQLiteAttributeContainerStore(
interface.AttributeContainerStoreWithReadCache):
"""SQLite-based attribute container store.

@@ -212,5 +215,2 @@

# The maximum number of cached attribute containers
_MAXIMUM_CACHED_CONTAINERS = 32 * 1024
_MAXIMUM_WRITE_CACHE_SIZE = 50

@@ -221,3 +221,2 @@

super(SQLiteAttributeContainerStore, self).__init__()
self._attribute_container_cache = collections.OrderedDict()
self._connection = None

@@ -233,16 +232,2 @@ self._cursor = None

def _CacheAttributeContainerByIndex(self, attribute_container, index):
"""Caches a specific attribute container.
Args:
attribute_container (AttributeContainer): attribute container.
index (int): attribute container index.
"""
if len(self._attribute_container_cache) >= self._MAXIMUM_CACHED_CONTAINERS:
self._attribute_container_cache.popitem(last=True)
lookup_key = f'{attribute_container.CONTAINER_TYPE:s}.{index:d}'
self._attribute_container_cache[lookup_key] = attribute_container
self._attribute_container_cache.move_to_end(lookup_key, last=False)
def _CacheAttributeContainerForWrite(

@@ -525,11 +510,10 @@ self, container_type, column_names, values):

def _GetCachedAttributeContainer(self, container_type, index):
"""Retrieves a specific cached attribute container.
def _GetNumberOfAttributeContainerRows(self, container_type):
"""Retrieves the number of attribute container rows.
Args:
container_type (str): attribute container type.
index (int): attribute container index.
Returns:
AttributeContainer: attribute container or None if not available.
int: the number of rows of a specified attribute container type.

@@ -540,8 +524,25 @@ Raises:

"""
lookup_key = f'{container_type:s}.{index:d}'
attribute_container = self._attribute_container_cache.get(lookup_key, None)
if attribute_container:
self._attribute_container_cache.move_to_end(lookup_key, last=False)
return attribute_container
self._CommitWriteCache(container_type)
if not self._HasTable(container_type):
return 0
# Note that this is SQLite specific, and will give inaccurate results if
# there are DELETE commands run on the table. acstore does not run any
# DELETE commands.
query = f'SELECT MAX(_ROWID_) FROM {container_type:s} LIMIT 1'
try:
self._cursor.execute(query)
except (sqlite3.InterfaceError, sqlite3.OperationalError) as exception:
raise IOError((
f'Unable to query attribute container store with error: '
f'{exception!s}'))
row = self._cursor.fetchone()
if not row:
return 0
return row[0] or 0
def _HasTable(self, table_name):

@@ -574,5 +575,5 @@ """Determines if a specific table exists.

Raises:
IOError: when the attribute container store is closed.
OSError: when the attribute container store is closed.
Raises:
IOError: when the attribute container store is closed.
OSError: when the attribute container store is closed.
"""

@@ -848,3 +849,3 @@ if not self._is_open:

if not self._is_open:
raise IOError('Storage file already closed.')
raise IOError('Attribute container store already closed.')

@@ -987,30 +988,5 @@ if self._connection:

int: the number of containers of a specified type.
Raises:
IOError: when there is an error querying the attribute container store.
OSError: when there is an error querying the attribute container store.
"""
self._CommitWriteCache(container_type)
return self._attribute_container_sequence_numbers[container_type]
if not self._HasTable(container_type):
return 0
# Note that this is SQLite specific, and will give inaccurate results if
# there are DELETE commands run on the table. acstore does not run any
# DELETE commands.
query = f'SELECT MAX(_ROWID_) FROM {container_type:s} LIMIT 1'
try:
self._cursor.execute(query)
except (sqlite3.InterfaceError, sqlite3.OperationalError) as exception:
raise IOError((
f'Unable to query attribute container store with error: '
f'{exception!s}'))
row = self._cursor.fetchone()
if not row:
return 0
return row[0] or 0
def HasAttributeContainers(self, container_type):

@@ -1025,9 +1001,4 @@ """Determines if store contains a specific type of attribute containers.

containers.
Raises:
IOError: when there is an error querying the attribute container store.
OSError: when there is an error querying the attribute container store.
"""
count = self.GetNumberOfAttributeContainers(container_type)
return count > 0
return self._attribute_container_sequence_numbers[container_type] > 0

@@ -1050,3 +1021,3 @@ def Open(self, path=None, read_only=True, **unused_kwargs): # pylint: disable=arguments-differ

if self._is_open:
raise IOError('Storage file already opened.')
raise IOError('Attribute container store already opened.')

@@ -1114,4 +1085,5 @@ if not path:

for container_type in self._containers_manager.GetContainerTypes():
next_sequence_number = self.GetNumberOfAttributeContainers(container_type)
next_sequence_number = self._GetNumberOfAttributeContainerRows(
container_type)
self._SetAttributeContainerNextSequenceNumber(
container_type, next_sequence_number)
environment:
matrix:
- DESCRIPTION: "Windows with 32-bit Python 3.11"
- DESCRIPTION: "Run tests on Windows with 32-bit Python 3.12"
MACHINE_TYPE: "x86"
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
PYTHON: "C:\\Python311"
PYTHON_VERSION: "3.11"
PYTHON: "C:\\Python312"
PYTHON_VERSION: "3.12"
L2TBINARIES_TRACK: "dev"
- DESCRIPTION: "Windows with 64-bit Python 3.11"
TARGET: tests
- DESCRIPTION: "Run tests on Windows with 64-bit Python 3.12"
MACHINE_TYPE: "amd64"
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
PYTHON: "C:\\Python311-x64"
PYTHON_VERSION: "3.11"
PYTHON: "C:\\Python312-x64"
PYTHON_VERSION: "3.12"
L2TBINARIES_TRACK: "dev"
- DESCRIPTION: "Mac OS with Python 3.11"
TARGET: tests
- DESCRIPTION: "Build wheel on Windows with 32-bit Python 3.12"
MACHINE_TYPE: "amd64"
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
PYTHON: "C:\\Python312-x64"
PYTHON_VERSION: "3.12"
L2TBINARIES_TRACK: "dev"
TARGET: wheel
- DESCRIPTION: "Build wheel on Windows with 64-bit Python 3.12"
MACHINE_TYPE: "amd64"
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
PYTHON: "C:\\Python312-x64"
PYTHON_VERSION: "3.12"
L2TBINARIES_TRACK: "dev"
TARGET: wheel
- DESCRIPTION: "Run tests on Mac OS with Python 3.12"
APPVEYOR_BUILD_WORKER_IMAGE: macos-monterey
HOMEBREW_NO_INSTALL_CLEANUP: 1
TARGET: tests
install:
- cmd: "%PYTHON%\\python.exe -m pip install -U pip setuptools twine wheel"
- cmd: "%PYTHON%\\python.exe -m pip install pywin32 WMI"
- cmd: "%PYTHON%\\python.exe %PYTHON%\\Scripts\\pywin32_postinstall.py -install"
- cmd: "%PYTHON%\\python.exe -m pip install -U build pip setuptools twine wheel"
- ps: If ($isWindows) { .\config\appveyor\install.ps1 }

@@ -27,9 +42,11 @@ - sh: config/appveyor/install.sh

build_script:
- cmd: "%PYTHON%\\python.exe setup.py bdist_wheel"
- cmd: IF [%TARGET%]==[wheel] (
"%PYTHON%\\python.exe" -m build --wheel )
test_script:
- cmd: "%PYTHON%\\python.exe run_tests.py"
- cmd: IF EXIST "tests\\end-to-end.py" (
set PYTHONPATH=. &&
"%PYTHON%\\python.exe" "tests\\end-to-end.py" --debug -c "config\\end-to-end.ini" )
- cmd: IF [%TARGET%]==[tests] (
"%PYTHON%\\python.exe" run_tests.py &&
IF EXIST "tests\\end-to-end.py" (
set PYTHONPATH=. &&
"%PYTHON%\\python.exe" "tests\\end-to-end.py" --debug -c "config\\end-to-end.ini" ) )
- sh: config/appveyor/runtests.sh

@@ -36,0 +53,0 @@

@@ -24,5 +24,5 @@ # Script to set up tests on AppVeyor Windows.

$Output = Invoke-Expression -Command "& '${env:PYTHON}\python.exe' ..\l2tdevtools\tools\update.py --download-directory dependencies --machine-type ${env:MACHINE_TYPE} --msi-targetdir ${env:PYTHON} --track ${env:L2TBINARIES_TRACK} ${Dependencies} 2>&1" | %{ "$_" }
$Output = Invoke-Expression -Command "& '${env:PYTHON}\python.exe' ..\l2tdevtools\tools\update.py --download-directory dependencies --machine-type ${env:MACHINE_TYPE} --track ${env:L2TBINARIES_TRACK} ${Dependencies} 2>&1" | %{ "$_" }
Write-Host (${Output} | Out-String)
}

@@ -6,3 +6,3 @@ # Script to set up tests on AppVeyor MacOS.

brew update -q
brew install -q gettext gnu-sed python@3.11 tox || true
brew install -q gettext gnu-sed python@3.12 tox || true

@@ -12,5 +12,5 @@ #!/bin/sh

# Set the following environment variables to ensure tox can find Python 3.11.
export PATH="/usr/local/opt/python@3.11/bin:${PATH}";
# Set the following environment variables to ensure tox can find Python 3.12.
export PATH="/usr/local/opt/python@3.12/bin:${PATH}";
tox -e py311
tox -e py312

@@ -55,2 +55,3 @@ # -*- coding: utf-8 -*-

napoleon_numpy_docstring = False
napoleon_include_init_with_doc = True
napoleon_include_private_with_doc = False

@@ -107,3 +108,3 @@ napoleon_include_special_with_doc = True

app (sphinx.application.Sphinx): Sphinx application. Required by the
Sphinx event callback API.
the Sphinx event callback API.
"""

@@ -110,0 +111,0 @@ current_directory = os.path.abspath(os.path.dirname(__file__))

@@ -0,6 +1,7 @@

certifi >= 2023.11.17
docutils
Markdown
recommonmark
sphinx >= 4.1.0, < 5.2.0
sphinx >= 4.1.0
sphinx-markdown-tables
sphinx-rtd-theme >= 0.5.1

@@ -7,2 +7,10 @@ acstore.helpers package

acstore.helpers.json\_serializer module
---------------------------------------
.. automodule:: acstore.helpers.json_serializer
:members:
:undoc-members:
:show-inheritance:
acstore.helpers.schema module

@@ -9,0 +17,0 @@ -----------------------------

Metadata-Version: 2.1
Name: acstore
Version: 20230519
Version: 20240128
Summary: Attribute Container Storage (ACStore).

@@ -9,9 +9,11 @@ Home-page: https://github.com/log2timeline/acstore

License: Apache License, Version 2.0
Classifier:
Classifier: Environment :: Console
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python
Requires-Python: >=3.7
Description-Content-Type: text/plain
License-File: ACKNOWLEDGEMENTS
License-File: AUTHORS
License-File: LICENSE
License-File: README
ACStore, or Attribute Container Storage, provides a stand-alone implementation to read and write attribute container storage files.

@@ -1,2 +0,1 @@

pip >= 7.0.0
PyYAML >= 3.10
[metadata]
license_files = LICENSE
name = acstore
version = 20240128
description = Attribute Container Storage (ACStore).
long_description = ACStore, or Attribute Container Storage, provides a stand-alone implementation to read and write attribute container storage files.
long_description_content_type = text/plain
url = https://github.com/log2timeline/acstore
maintainer = Log2Timeline maintainers
maintainer_email = log2timeline-maintainers@googlegroups.com
license = Apache License, Version 2.0
license_files =
ACKNOWLEDGEMENTS
AUTHORS
LICENSE
README
classifiers =
Development Status :: 3 - Alpha
Programming Language :: Python
[options]
install_requires = file:requirements.txt
package_dir =
acstore = acstore
packages = find:
python_requires = >=3.7
[options.packages.find]
exclude =
docs
tests
tests.*
utils
where = .
[bdist_rpm]
release = 1
packager = Log2Timeline maintainers <log2timeline-maintainers@googlegroups.com>
doc_files = ACKNOWLEDGEMENTS
doc_files =
ACKNOWLEDGEMENTS
AUTHORS

@@ -12,3 +44,4 @@ LICENSE

build_requires = python3-setuptools
requires = python3-pyyaml >= 3.10
requires =
python3-pyyaml >= 3.10

@@ -15,0 +48,0 @@ [bdist_wheel]

+2
-214

@@ -5,217 +5,5 @@ #!/usr/bin/env python

import os
import pkg_resources
import sys
from setuptools import setup
try:
from setuptools import find_packages, setup
except ImportError:
from distutils.core import find_packages, setup
try:
from distutils.command.bdist_msi import bdist_msi
except ImportError:
bdist_msi = None
try:
from distutils.command.bdist_rpm import bdist_rpm
except ImportError:
bdist_rpm = None
version_tuple = (sys.version_info[0], sys.version_info[1])
if version_tuple < (3, 7):
print(f'Unsupported Python version: {sys.version:s}, version 3.7 or higher '
f'required.')
sys.exit(1)
# Change PYTHONPATH to include acstore so that we can get the version.
sys.path.insert(0, '.')
import acstore # pylint: disable=wrong-import-position
if not bdist_msi:
BdistMSICommand = None
else:
class BdistMSICommand(bdist_msi):
"""Custom handler for the bdist_msi command."""
# pylint: disable=invalid-name
def run(self):
"""Builds an MSI."""
# Command bdist_msi does not support the library version, neither a date
# as a version but if we suffix it with .1 everything is fine.
self.distribution.metadata.version += '.1'
bdist_msi.run(self)
if not bdist_rpm:
BdistRPMCommand = None
else:
class BdistRPMCommand(bdist_rpm):
"""Custom handler for the bdist_rpm command."""
# pylint: disable=invalid-name
def _make_spec_file(self):
"""Generates the text of an RPM spec file.
Returns:
list[str]: lines of the RPM spec file.
"""
# Note that bdist_rpm can be an old style class.
if issubclass(BdistRPMCommand, object):
spec_file = super(BdistRPMCommand, self)._make_spec_file()
else:
spec_file = bdist_rpm._make_spec_file(self)
python_package = 'python3'
description = []
requires = ''
summary = ''
in_description = False
python_spec_file = []
for line in iter(spec_file):
if line.startswith('Summary: '):
summary = line[9:]
elif line.startswith('BuildRequires: '):
line = (f'BuildRequires: {python_package:s}-setuptools, '
f'{python_package:s}-devel')
elif line.startswith('Requires: '):
requires = line[10:]
continue
elif line.startswith('%description'):
in_description = True
elif line.startswith('python setup.py build'):
if python_package == 'python3':
line = '%py3_build'
else:
line = '%py2_build'
elif line.startswith('python setup.py install'):
if python_package == 'python3':
line = '%py3_install'
else:
line = '%py2_install'
elif line.startswith('%files'):
lines = [
f'%files -n {python_package:s}-%{{name}}',
'%defattr(644,root,root,755)',
'%license LICENSE',
'%doc ACKNOWLEDGEMENTS AUTHORS README']
lines.extend([
'%{python3_sitelib}/acstore/*.py',
'%{python3_sitelib}/acstore/*/*.py',
'%{python3_sitelib}/acstore*.egg-info/*',
'',
'%exclude %{_prefix}/share/doc/*',
'%exclude %{python3_sitelib}/acstore/__pycache__/*',
'%exclude %{python3_sitelib}/acstore/*/__pycache__/*'])
python_spec_file.extend(lines)
break
elif line.startswith('%prep'):
in_description = False
python_spec_file.append(f'%package -n {python_package:s}-%{{name}}')
python_summary = f'Python 3 module of {summary:s}'
if requires:
python_spec_file.append(f'Requires: {requires:s}')
python_spec_file.extend([
f'Summary: {python_summary:s}',
'',
f'%description -n {python_package:s}-%{{name}}'])
python_spec_file.extend(description)
elif in_description:
# Ignore leading white lines in the description.
if not description and not line:
continue
description.append(line)
python_spec_file.append(line)
return python_spec_file
def parse_requirements_from_file(path):
"""Parses requirements from a requirements file.
Args:
path (str): path to the requirements file.
Returns:
list[str]: name and optional version information of the required packages.
"""
requirements = []
if os.path.isfile(path):
with open(path, 'r') as file_object:
file_contents = file_object.read()
for requirement in pkg_resources.parse_requirements(file_contents):
try:
name = str(requirement.req)
except AttributeError:
name = str(requirement)
if not name.startswith('pip '):
requirements.append(name)
return requirements
acstore_description = (
'Attribute Container Storage (ACStore).')
acstore_long_description = (
'ACStore, or Attribute Container Storage, provides a stand-alone '
'implementation to read and write attribute container storage files.')
command_classes = {}
if BdistMSICommand:
command_classes['bdist_msi'] = BdistMSICommand
if BdistRPMCommand:
command_classes['bdist_rpm'] = BdistRPMCommand
setup(
name='acstore',
version=acstore.__version__,
description=acstore_description,
long_description=acstore_long_description,
long_description_content_type='text/plain',
license='Apache License, Version 2.0',
url='https://github.com/log2timeline/acstore',
maintainer='Log2Timeline maintainers',
maintainer_email='log2timeline-maintainers@googlegroups.com',
cmdclass=command_classes,
classifiers=[
'',
'Environment :: Console',
'Operating System :: OS Independent',
'Programming Language :: Python',
],
packages=find_packages('.', exclude=[
'docs', 'tests', 'tests.*', 'utils']),
package_dir={
'acstore': 'acstore'
},
data_files=[
('share/doc/acstore', [
'ACKNOWLEDGEMENTS', 'AUTHORS', 'LICENSE', 'README']),
],
install_requires=parse_requirements_from_file('requirements.txt'),
tests_require=parse_requirements_from_file('test_requirements.txt'),
)
setup()
# YAML-based attribute container definitions file.
---
name: 'windows_eventlog_message_file'
name: windows_eventlog_message_file
attributes:
- name: 'path'
type: 'str'
- name: 'windows_path'
type: 'str'
- name: path
type: str
- name: windows_path
type: str

@@ -35,8 +35,8 @@ #!/usr/bin/env python3

attribute_container = interface.AttributeContainer()
attribute_container.attribute_name = 'attribute_name'
attribute_container.attribute_value = 'attribute_value'
attribute_container.attribute_name = 'MyName'
attribute_container.attribute_value = 'MyValue'
expected_dict = {
'attribute_name': 'attribute_name',
'attribute_value': 'attribute_value'}
'attribute_name': 'MyName',
'attribute_value': 'MyValue'}

@@ -51,4 +51,4 @@ test_dict = attribute_container.CopyToDict()

attribute_container._protected_attribute = 'protected'
attribute_container.attribute_name = 'attribute_name'
attribute_container.attribute_value = 'attribute_value'
attribute_container.attribute_name = 'MyName'
attribute_container.attribute_value = 'MyValue'

@@ -75,8 +75,8 @@ expected_attribute_names = ['attribute_name', 'attribute_value']

attribute_container._protected_attribute = 'protected'
attribute_container.attribute_name = 'attribute_name'
attribute_container.attribute_value = 'attribute_value'
attribute_container.attribute_name = 'MyName'
attribute_container.attribute_value = 'MyValue'
expected_attributes = [
('attribute_name', 'attribute_name'),
('attribute_value', 'attribute_value')]
('attribute_name', 'MyName'),
('attribute_value', 'MyValue')]

@@ -92,4 +92,4 @@ attributes = sorted(attribute_container.GetAttributes())

('_protected_attribute', 'protected'),
('attribute_name', 'attribute_name'),
('attribute_value', 'attribute_value')]
('attribute_name', 'MyName'),
('attribute_value', 'MyValue')]

@@ -104,4 +104,4 @@ attributes = sorted(attribute_container.GetAttributes())

attribute_container._protected_attribute = 'protected'
attribute_container.attribute_name = 'attribute_name'
attribute_container.attribute_value = 'attribute_value'
attribute_container.attribute_name = 'MyName'
attribute_container.attribute_value = 'MyValue'

@@ -116,3 +116,3 @@ attribute_values_hash1 = attribute_container.GetAttributeValuesHash()

attribute_container.attribute_value = 'attribute_value'
attribute_container.attribute_value = 'MyValue'

@@ -130,4 +130,4 @@ setattr(attribute_container, '_SERIALIZABLE_PROTECTED_ATTRIBUTES', [

attribute_container._protected_attribute = 'protected'
attribute_container.attribute_name = 'attribute_name'
attribute_container.attribute_value = 'attribute_value'
attribute_container.attribute_name = 'MyName'
attribute_container.attribute_value = 'MyValue'

@@ -142,3 +142,3 @@ attribute_values_string1 = attribute_container.GetAttributeValuesString()

attribute_container.attribute_value = 'attribute_value'
attribute_container.attribute_value = 'MyValue'

@@ -145,0 +145,0 @@ setattr(attribute_container, '_SERIALIZABLE_PROTECTED_ATTRIBUTES', [

@@ -17,18 +17,19 @@ #!/usr/bin/env python3

_TEST_MANAGER = manager.AttributeContainersManager
def testCreateAttributeContainer(self):
"""Tests the CreateAttributeContainer function."""
manager.AttributeContainersManager.RegisterAttributeContainer(
self._TEST_MANAGER.RegisterAttributeContainer(
shared_test_lib.TestAttributeContainer)
try:
attribute_container = (
manager.AttributeContainersManager.CreateAttributeContainer(
'test_container'))
attribute_container = self._TEST_MANAGER.CreateAttributeContainer(
'test_container')
self.assertIsNotNone(attribute_container)
with self.assertRaises(ValueError):
manager.AttributeContainersManager.CreateAttributeContainer('bogus')
self._TEST_MANAGER.CreateAttributeContainer('bogus')
finally:
manager.AttributeContainersManager.DeregisterAttributeContainer(
self._TEST_MANAGER.DeregisterAttributeContainer(
shared_test_lib.TestAttributeContainer)

@@ -38,11 +39,11 @@

"""Tests the GetContainerTypes function."""
manager.AttributeContainersManager.RegisterAttributeContainer(
self._TEST_MANAGER.RegisterAttributeContainer(
shared_test_lib.TestAttributeContainer)
try:
container_types = manager.AttributeContainersManager.GetContainerTypes()
container_types = self._TEST_MANAGER.GetContainerTypes()
self.assertIn('test_container', container_types)
finally:
manager.AttributeContainersManager.DeregisterAttributeContainer(
self._TEST_MANAGER.DeregisterAttributeContainer(
shared_test_lib.TestAttributeContainer)

@@ -52,7 +53,7 @@

"""Tests the GetSchema function."""
manager.AttributeContainersManager.RegisterAttributeContainer(
self._TEST_MANAGER.RegisterAttributeContainer(
shared_test_lib.TestAttributeContainer)
try:
schema = manager.AttributeContainersManager.GetSchema('test_container')
schema = self._TEST_MANAGER.GetSchema('test_container')
self.assertIsNotNone(schema)

@@ -62,6 +63,6 @@ self.assertEqual(schema, shared_test_lib.TestAttributeContainer.SCHEMA)

with self.assertRaises(ValueError):
manager.AttributeContainersManager.GetSchema('bogus')
self._TEST_MANAGER.GetSchema('bogus')
finally:
manager.AttributeContainersManager.DeregisterAttributeContainer(
self._TEST_MANAGER.DeregisterAttributeContainer(
shared_test_lib.TestAttributeContainer)

@@ -71,6 +72,5 @@

"""Tests the Register and DeregisterAttributeContainer functions."""
number_of_classes = len(
manager.AttributeContainersManager._attribute_container_classes)
number_of_classes = len(self._TEST_MANAGER._attribute_container_classes)
manager.AttributeContainersManager.RegisterAttributeContainer(
self._TEST_MANAGER.RegisterAttributeContainer(
shared_test_lib.TestAttributeContainer)

@@ -80,15 +80,15 @@

self.assertEqual(
len(manager.AttributeContainersManager._attribute_container_classes),
len(self._TEST_MANAGER._attribute_container_classes),
number_of_classes + 1)
with self.assertRaises(KeyError):
manager.AttributeContainersManager.RegisterAttributeContainer(
self._TEST_MANAGER.RegisterAttributeContainer(
shared_test_lib.TestAttributeContainer)
finally:
manager.AttributeContainersManager.DeregisterAttributeContainer(
self._TEST_MANAGER.DeregisterAttributeContainer(
shared_test_lib.TestAttributeContainer)
self.assertEqual(
len(manager.AttributeContainersManager._attribute_container_classes),
len(self._TEST_MANAGER._attribute_container_classes),
number_of_classes)

@@ -95,0 +95,0 @@

@@ -62,3 +62,38 @@ #!/usr/bin/env python3

class AttributeContainerStoreWithReadCacheTest(test_lib.BaseTestCase):
"""Tests for the attribute container store with read cache."""
# pylint: disable=protected-access
def testCacheAttributeContainerByIndex(self):
"""Tests the _CacheAttributeContainerByIndex function."""
attribute_container = test_lib.TestAttributeContainer()
with test_lib.TempDirectory():
test_store = interface.AttributeContainerStoreWithReadCache()
self.assertEqual(len(test_store._attribute_container_cache), 0)
test_store._CacheAttributeContainerByIndex(attribute_container, 0)
self.assertEqual(len(test_store._attribute_container_cache), 1)
def testGetCachedAttributeContainer(self):
"""Tests the _GetCachedAttributeContainer function."""
attribute_container = test_lib.TestAttributeContainer()
with test_lib.TempDirectory():
test_store = interface.AttributeContainerStoreWithReadCache()
cached_container = test_store._GetCachedAttributeContainer(
attribute_container.CONTAINER_TYPE, 1)
self.assertIsNone(cached_container)
test_store._CacheAttributeContainerByIndex(attribute_container, 1)
cached_container = test_store._GetCachedAttributeContainer(
attribute_container.CONTAINER_TYPE, 1)
self.assertIsNotNone(cached_container)
if __name__ == '__main__':
unittest.main()

@@ -119,14 +119,2 @@ #!/usr/bin/env python3

def testCacheAttributeContainerByIndex(self):
"""Tests the _CacheAttributeContainerByIndex function."""
attribute_container = test_lib.TestAttributeContainer()
with test_lib.TempDirectory():
test_store = sqlite_store.SQLiteAttributeContainerStore()
self.assertEqual(len(test_store._attribute_container_cache), 0)
test_store._CacheAttributeContainerByIndex(attribute_container, 0)
self.assertEqual(len(test_store._attribute_container_cache), 1)
def testCheckStorageMetadata(self):

@@ -223,19 +211,33 @@ """Tests the _CheckStorageMetadata function."""

def testGetCachedAttributeContainer(self):
"""Tests the _GetCachedAttributeContainer function."""
def testGetNumberOfAttributeContainerRows(self):
"""Tests the _GetNumberOfAttributeContainerRows function."""
attribute_container = test_lib.TestAttributeContainer()
with test_lib.TempDirectory():
with test_lib.TempDirectory() as temp_directory:
test_path = os.path.join(temp_directory, 'acstore.sqlite')
test_store = sqlite_store.SQLiteAttributeContainerStore()
test_store.Open(path=test_path, read_only=False)
cached_container = test_store._GetCachedAttributeContainer(
attribute_container.CONTAINER_TYPE, 1)
self.assertIsNone(cached_container)
try:
number_of_containers = test_store._GetNumberOfAttributeContainerRows(
attribute_container.CONTAINER_TYPE)
self.assertEqual(number_of_containers, 0)
test_store._CacheAttributeContainerByIndex(attribute_container, 1)
test_store.AddAttributeContainer(attribute_container)
cached_container = test_store._GetCachedAttributeContainer(
attribute_container.CONTAINER_TYPE, 1)
self.assertIsNotNone(cached_container)
number_of_containers = test_store._GetNumberOfAttributeContainerRows(
attribute_container.CONTAINER_TYPE)
self.assertEqual(number_of_containers, 1)
# Test for a supported container type that does not have a table
# present in the storage file.
query = f'DROP TABLE {attribute_container.CONTAINER_TYPE:s}'
test_store._cursor.execute(query)
number_of_containers = test_store._GetNumberOfAttributeContainerRows(
attribute_container.CONTAINER_TYPE)
self.assertEqual(number_of_containers, 0)
finally:
test_store.Close()
def testHasTable(self):

@@ -288,3 +290,3 @@ """Tests the _HasTable function."""

try:
number_of_containers = test_store.GetNumberOfAttributeContainers(
number_of_containers = test_store._GetNumberOfAttributeContainerRows(
attribute_container.CONTAINER_TYPE)

@@ -295,3 +297,3 @@ self.assertEqual(number_of_containers, 0)

number_of_containers = test_store.GetNumberOfAttributeContainers(
number_of_containers = test_store._GetNumberOfAttributeContainerRows(
attribute_container.CONTAINER_TYPE)

@@ -302,3 +304,3 @@ self.assertEqual(number_of_containers, 1)

number_of_containers = test_store.GetNumberOfAttributeContainers(
number_of_containers = test_store._GetNumberOfAttributeContainerRows(
attribute_container.CONTAINER_TYPE)

@@ -323,3 +325,3 @@ self.assertEqual(number_of_containers, 1)

try:
number_of_containers = test_store.GetNumberOfAttributeContainers(
number_of_containers = test_store._GetNumberOfAttributeContainerRows(
attribute_container.CONTAINER_TYPE)

@@ -330,3 +332,3 @@ self.assertEqual(number_of_containers, 0)

number_of_containers = test_store.GetNumberOfAttributeContainers(
number_of_containers = test_store._GetNumberOfAttributeContainerRows(
attribute_container.CONTAINER_TYPE)

@@ -478,8 +480,4 @@ self.assertEqual(number_of_containers, 1)

# Test for a supported container type that does not have a table
# present in the storage file.
query = f'DROP TABLE {attribute_container.CONTAINER_TYPE:s}'
test_store._cursor.execute(query)
number_of_containers = test_store.GetNumberOfAttributeContainers(
attribute_container.CONTAINER_TYPE)
'bogus')
self.assertEqual(number_of_containers, 0)

@@ -486,0 +484,0 @@

+43
-30
[tox]
envlist = py3{7,8,9,10,11},coverage,docs,lint
envlist = py3{7,8,9,10,11,12},coverage,docformatter,docs,lint,wheel

@@ -8,24 +8,36 @@ [testenv]

passenv =
CFLAGS
CPPFLAGS
LDFLAGS
CFLAGS
CPPFLAGS
LDFLAGS
setenv =
PYTHONPATH = {toxinidir}
PYTHONPATH = {toxinidir}
deps =
-rrequirements.txt
-rtest_requirements.txt
coverage: coverage
-rrequirements.txt
-rtest_requirements.txt
coverage: coverage
wheel:
build
setuptools >= 65
wheel
commands =
py3{7,8,9,10,11}: ./run_tests.py
coverage: coverage erase
coverage: coverage run --source=acstore --omit="*_test*,*__init__*,*test_lib*" run_tests.py
coverage: coverage xml
py3{7,8,9,10,11,12}: ./run_tests.py
coverage: coverage erase
coverage: coverage run --source=acstore --omit="*_test*,*__init__*,*test_lib*" run_tests.py
coverage: coverage xml
wheel: python -m build --no-isolation --wheel
[testenv:docformatter]
usedevelop = True
deps =
docformatter
commands =
docformatter --in-place --recursive acstore tests
[testenv:docs]
usedevelop = True
deps =
-rdocs/requirements.txt
-rdocs/requirements.txt
commands =
sphinx-build -b html -d build/doctrees docs dist/docs
sphinx-build -b linkcheck docs dist/docs
sphinx-build -b html -d build/doctrees docs dist/docs
sphinx-build -b linkcheck docs dist/docs

@@ -36,19 +48,20 @@ [testenv:lint]

passenv =
CFLAGS
CPPFLAGS
LDFLAGS
CFLAGS
CPPFLAGS
LDFLAGS
setenv =
PYTHONPATH = {toxinidir}
PYTHONPATH = {toxinidir}
deps =
-rrequirements.txt
-rtest_requirements.txt
pylint >= 2.17.0, < 2.18.0
yamllint >= 1.26.0
-rrequirements.txt
-rtest_requirements.txt
docformatter
pylint >= 3.0.0, < 3.1.0
setuptools
yamllint >= 1.26.0
commands =
pylint --version
yamllint -v
# Ignore setup.py for now due to:
# setup.py:15:0: E0001: Cannot import 'distutils.command.bdist_msi' due to
# syntax error 'expected an indented block (<unknown>, line 347)' (syntax-error)
pylint --rcfile=.pylintrc acstore tests
yamllint -c .yamllint.yaml test_data
docformatter --version
pylint --version
yamllint -v
docformatter --check --diff --recursive acstore setup.py tests
pylint --rcfile=.pylintrc acstore setup.py tests
yamllint -c .yamllint.yaml test_data

@@ -15,2 +15,5 @@ #!/bin/bash

# Update the version in the setuptools configuration.
sed "s/version = [0-9]*/version = ${VERSION}/" -i setup.cfg
# Update the version in the dpkg configuration files.

@@ -26,5 +29,5 @@ cat > config/dpkg/changelog << EOT

# Regenerate the API documentation.
tox -edocs
tox -edocformatter,docs
exit ${EXIT_SUCCESS};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet