{\n",
" "type": "identity",\n",
- " "id": "identity--87aac643-341b-413a-b702-ea5820416155",\n",
- " "created": "2018-04-05T18:38:10.269Z",\n",
- " "modified": "2018-04-05T18:38:10.269Z",\n",
+ " "id": "identity--e7fd0fe0-25ff-4fcb-abe5-b6254a9d1a22",\n",
+ " "created": "2019-07-25T18:18:18.241Z",\n",
+ " "modified": "2019-07-25T18:18:18.241Z",\n",
" "name": "John Smith",\n",
" "identity_class": "individual",\n",
" "x_foo": "bar"\n",
@@ -194,8 +194,6 @@
}
],
"source": [
- "from stix2 import Identity\n",
- "\n",
"identity = Identity(name=\"John Smith\",\n",
" identity_class=\"individual\",\n",
" custom_properties={\n",
@@ -289,9 +287,9 @@
".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */{\n",
" "type": "identity",\n",
- " "id": "identity--a1ad0a6f-39ab-4642-9a72-aaa198b1eee2",\n",
- " "created": "2018-04-05T18:38:12.270Z",\n",
- " "modified": "2018-04-05T18:38:12.270Z",\n",
+ " "id": "identity--033b5f42-c94f-488f-8efa-2b6a167f0d6f",\n",
+ " "created": "2019-07-25T18:18:21.352Z",\n",
+ " "modified": "2019-07-25T18:18:21.352Z",\n",
" "name": "John Smith",\n",
" "identity_class": "individual",\n",
" "x_foo": "bar"\n",
@@ -426,6 +424,113 @@
"print(identity3.x_foo)"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To remove a custom properties, use `new_version()` and set it to `None`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "{\n",
+ " "type": "identity",\n",
+ " "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",\n",
+ " "created": "2015-12-21T19:59:11.000Z",\n",
+ " "modified": "2019-07-25T18:18:25.927Z",\n",
+ " "name": "John Smith",\n",
+ " "identity_class": "individual"\n",
+ "}\n",
+ "
\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "identity4 = identity3.new_version(x_foo=None)\n",
+ "print(identity4)"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {},
diff --git a/docs/guide/versioning.ipynb b/docs/guide/versioning.ipynb
index 6074d00d..eb0708aa 100644
--- a/docs/guide/versioning.ipynb
+++ b/docs/guide/versioning.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 1,
"metadata": {
"nbsphinx": "hidden"
},
@@ -22,7 +22,7 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 2,
"metadata": {
"nbsphinx": "hidden"
},
@@ -63,12 +63,12 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "To create a new version of an existing object, specify the property(ies) you want to change and their new values:"
+ "To create a new version of an existing object, specify the property(ies) you want to change and their new values. For example, here we change the label from \"anomalous-activity\" to \"malicious-activity\":"
]
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 3,
"metadata": {},
"outputs": [
{
@@ -144,12 +144,13 @@
".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */{\n",
" "type": "indicator",\n",
- " "id": "indicator--dd052ff6-e404-444b-beb9-eae96d1e79ea",\n",
+ " "id": "indicator--8ad18fc7-457c-475d-b292-1ec44febe0fd",\n",
" "created": "2016-01-01T08:00:00.000Z",\n",
- " "modified": "2018-04-05T20:02:51.161Z",\n",
+ " "modified": "2019-07-25T17:59:34.815Z",\n",
" "name": "File hash for Foobar malware",\n",
+ " "description": "A file indicator",\n",
" "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
- " "valid_from": "2018-04-05T20:02:51.138312Z",\n",
+ " "valid_from": "2019-07-25T17:59:34.779826Z",\n",
" "labels": [\n",
" "malicious-activity"\n",
" ]\n",
@@ -160,7 +161,7 @@
""
]
},
- "execution_count": 4,
+ "execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
@@ -170,6 +171,7 @@
"\n",
"indicator = Indicator(created=\"2016-01-01T08:00:00.000Z\",\n",
" name=\"File hash for suspicious file\",\n",
+ " description=\"A file indicator\",\n",
" labels=[\"anomalous-activity\"],\n",
" pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n",
"\n",
@@ -187,7 +189,7 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 4,
"metadata": {
"scrolled": true
},
@@ -205,6 +207,117 @@
"indicator.new_version(id=\"indicator--cc42e358-8b9b-493c-9646-6ecd73b41c21\")"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can remove optional or custom properties by setting them to `None` when you call `new_version()`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "{\n",
+ " "type": "indicator",\n",
+ " "id": "indicator--8ad18fc7-457c-475d-b292-1ec44febe0fd",\n",
+ " "created": "2016-01-01T08:00:00.000Z",\n",
+ " "modified": "2019-07-25T17:59:42.648Z",\n",
+ " "name": "File hash for suspicious file",\n",
+ " "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
+ " "valid_from": "2019-07-25T17:59:34.779826Z",\n",
+ " "labels": [\n",
+ " "anomalous-activity"\n",
+ " ]\n",
+ "}\n",
+ "
\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "indicator3 = indicator.new_version(description=None)\n",
+ "print(indicator3)"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {
@@ -292,15 +405,15 @@
".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */{\n",
" "type": "indicator",\n",
- " "id": "indicator--dd052ff6-e404-444b-beb9-eae96d1e79ea",\n",
+ " "id": "indicator--8ad18fc7-457c-475d-b292-1ec44febe0fd",\n",
" "created": "2016-01-01T08:00:00.000Z",\n",
- " "modified": "2018-04-05T20:02:54.704Z",\n",
- " "name": "File hash for Foobar malware",\n",
+ " "modified": "2019-07-25T17:59:52.198Z",\n",
+ " "name": "File hash for suspicious file",\n",
" "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
- " "valid_from": "2018-04-05T20:02:51.138312Z",\n",
+ " "valid_from": "2019-07-25T17:59:34.779826Z",\n",
" "revoked": true,\n",
" "labels": [\n",
- " "malicious-activity"\n",
+ " "anomalous-activity"\n",
" ]\n",
"}\n",
"
\n"
@@ -315,8 +428,8 @@
}
],
"source": [
- "indicator2 = indicator2.revoke()\n",
- "print(indicator2)"
+ "indicator4 = indicator3.revoke()\n",
+ "print(indicator4)"
]
}
],
diff --git a/setup.cfg b/setup.cfg
index ae45560a..b012bb95 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 1.1.2
+current_version = 1.1.3
commit = True
tag = True
diff --git a/setup.py b/setup.py
index 07de2a4c..497bf01d 100644
--- a/setup.py
+++ b/setup.py
@@ -27,6 +27,7 @@ def get_long_description():
version=get_version(),
description='Produce and consume STIX 2 JSON content',
long_description=get_long_description(),
+ long_description_content_type='text/x-rst',
url='https://oasis-open.github.io/cti-documentation/',
author='OASIS Cyber Threat Intelligence Technical Committee',
author_email='cti-users@lists.oasis-open.org',
@@ -47,7 +48,7 @@ def get_long_description():
'Programming Language :: Python :: 3.7',
],
keywords='stix stix2 json cti cyber threat intelligence',
- packages=find_packages(exclude=['*.test']),
+ packages=find_packages(exclude=['*.test', '*.test.*']),
install_requires=[
'python-dateutil',
'pytz',
diff --git a/stix2/test/v20/test_datastore_filesystem.py b/stix2/test/v20/test_datastore_filesystem.py
index 25de37e2..317f927b 100644
--- a/stix2/test/v20/test_datastore_filesystem.py
+++ b/stix2/test/v20/test_datastore_filesystem.py
@@ -125,15 +125,13 @@ def rel_fs_store():
def test_filesystem_source_nonexistent_folder():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.FileSystemSource('nonexistent-folder')
- assert "for STIX data does not exist" in str(excinfo)
def test_filesystem_sink_nonexistent_folder():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.FileSystemSink('nonexistent-folder')
- assert "for STIX data does not exist" in str(excinfo)
def test_filesystem_source_bad_json_file(fs_source, bad_json_files):
@@ -441,9 +439,8 @@ def test_filesystem_attempt_stix_file_overwrite(fs_store):
)
# Now attempt to overwrite the existing file
- with pytest.raises(DataSourceError) as excinfo:
+ with pytest.raises(DataSourceError):
fs_store.add(camp8)
- assert "Attempted to overwrite file" in str(excinfo)
os.remove(filepath)
diff --git a/stix2/test/v20/test_pattern_expressions.py b/stix2/test/v20/test_pattern_expressions.py
index 3dc7cde9..23a401ba 100644
--- a/stix2/test/v20/test_pattern_expressions.py
+++ b/stix2/test/v20/test_pattern_expressions.py
@@ -257,7 +257,7 @@ def test_and_observable_expression():
def test_invalid_and_observable_expression():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.AndBooleanExpression([
stix2.EqualityComparisonExpression(
"user-account:display_name",
@@ -268,7 +268,6 @@ def test_invalid_and_observable_expression():
stix2.StringConstant("admin"),
),
])
- assert "All operands to an 'AND' expression must have the same object type" in str(excinfo)
def test_hex():
@@ -352,30 +351,26 @@ def test_list2():
def test_invalid_constant_type():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.EqualityComparisonExpression(
"artifact:payload_bin",
{'foo': 'bar'},
)
- assert 'Unable to create a constant' in str(excinfo)
def test_invalid_integer_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.IntegerConstant('foo')
- assert 'must be an integer' in str(excinfo)
def test_invalid_timestamp_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.TimestampConstant('foo')
- assert 'Must be a datetime object or timestamp string' in str(excinfo)
def test_invalid_float_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.FloatConstant('foo')
- assert 'must be a float' in str(excinfo)
@pytest.mark.parametrize(
@@ -400,9 +395,8 @@ def test_boolean_constant(data, result):
def test_invalid_boolean_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.BooleanConstant('foo')
- assert 'must be a boolean' in str(excinfo)
@pytest.mark.parametrize(
@@ -412,21 +406,18 @@ def test_invalid_boolean_constant():
],
)
def test_invalid_hash_constant(hashtype, data):
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.HashConstant(data, hashtype)
- assert 'is not a valid {} hash'.format(hashtype) in str(excinfo)
def test_invalid_hex_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.HexConstant('mm')
- assert "must contain an even number of hexadecimal characters" in str(excinfo)
def test_invalid_binary_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.BinaryConstant('foo')
- assert 'must contain a base64' in str(excinfo)
def test_escape_quotes_and_backslashes():
@@ -459,15 +450,13 @@ def test_repeat_qualifier():
def test_invalid_repeat_qualifier():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.RepeatQualifier('foo')
- assert 'is not a valid argument for a Repeat Qualifier' in str(excinfo)
def test_invalid_within_qualifier():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.WithinQualifier('foo')
- assert 'is not a valid argument for a Within Qualifier' in str(excinfo)
def test_startstop_qualifier():
@@ -485,19 +474,17 @@ def test_startstop_qualifier():
def test_invalid_startstop_qualifier():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.StartStopQualifier(
'foo',
stix2.TimestampConstant('2016-06-01T00:00:00Z'),
)
- assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.StartStopQualifier(
datetime.date(2016, 6, 1),
'foo',
)
- assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
def test_make_constant_already_a_constant():
diff --git a/stix2/test/v21/test_datastore_filesystem.py b/stix2/test/v21/test_datastore_filesystem.py
index 34b10881..9917ccd0 100644
--- a/stix2/test/v21/test_datastore_filesystem.py
+++ b/stix2/test/v21/test_datastore_filesystem.py
@@ -124,15 +124,13 @@ def rel_fs_store():
def test_filesystem_source_nonexistent_folder():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.FileSystemSource('nonexistent-folder')
- assert "for STIX data does not exist" in str(excinfo)
def test_filesystem_sink_nonexistent_folder():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.FileSystemSink('nonexistent-folder')
- assert "for STIX data does not exist" in str(excinfo)
def test_filesystem_source_bad_json_file(fs_source, bad_json_files):
diff --git a/stix2/test/v21/test_pattern_expressions.py b/stix2/test/v21/test_pattern_expressions.py
index 3dc7cde9..23a401ba 100644
--- a/stix2/test/v21/test_pattern_expressions.py
+++ b/stix2/test/v21/test_pattern_expressions.py
@@ -257,7 +257,7 @@ def test_and_observable_expression():
def test_invalid_and_observable_expression():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.AndBooleanExpression([
stix2.EqualityComparisonExpression(
"user-account:display_name",
@@ -268,7 +268,6 @@ def test_invalid_and_observable_expression():
stix2.StringConstant("admin"),
),
])
- assert "All operands to an 'AND' expression must have the same object type" in str(excinfo)
def test_hex():
@@ -352,30 +351,26 @@ def test_list2():
def test_invalid_constant_type():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.EqualityComparisonExpression(
"artifact:payload_bin",
{'foo': 'bar'},
)
- assert 'Unable to create a constant' in str(excinfo)
def test_invalid_integer_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.IntegerConstant('foo')
- assert 'must be an integer' in str(excinfo)
def test_invalid_timestamp_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.TimestampConstant('foo')
- assert 'Must be a datetime object or timestamp string' in str(excinfo)
def test_invalid_float_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.FloatConstant('foo')
- assert 'must be a float' in str(excinfo)
@pytest.mark.parametrize(
@@ -400,9 +395,8 @@ def test_boolean_constant(data, result):
def test_invalid_boolean_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.BooleanConstant('foo')
- assert 'must be a boolean' in str(excinfo)
@pytest.mark.parametrize(
@@ -412,21 +406,18 @@ def test_invalid_boolean_constant():
],
)
def test_invalid_hash_constant(hashtype, data):
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.HashConstant(data, hashtype)
- assert 'is not a valid {} hash'.format(hashtype) in str(excinfo)
def test_invalid_hex_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.HexConstant('mm')
- assert "must contain an even number of hexadecimal characters" in str(excinfo)
def test_invalid_binary_constant():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.BinaryConstant('foo')
- assert 'must contain a base64' in str(excinfo)
def test_escape_quotes_and_backslashes():
@@ -459,15 +450,13 @@ def test_repeat_qualifier():
def test_invalid_repeat_qualifier():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.RepeatQualifier('foo')
- assert 'is not a valid argument for a Repeat Qualifier' in str(excinfo)
def test_invalid_within_qualifier():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.WithinQualifier('foo')
- assert 'is not a valid argument for a Within Qualifier' in str(excinfo)
def test_startstop_qualifier():
@@ -485,19 +474,17 @@ def test_startstop_qualifier():
def test_invalid_startstop_qualifier():
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.StartStopQualifier(
'foo',
stix2.TimestampConstant('2016-06-01T00:00:00Z'),
)
- assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
- with pytest.raises(ValueError) as excinfo:
+ with pytest.raises(ValueError):
stix2.StartStopQualifier(
datetime.date(2016, 6, 1),
'foo',
)
- assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
def test_make_constant_already_a_constant():
diff --git a/stix2/version.py b/stix2/version.py
index 72f26f59..0b2f79db 100644
--- a/stix2/version.py
+++ b/stix2/version.py
@@ -1 +1 @@
-__version__ = "1.1.2"
+__version__ = "1.1.3"
diff --git a/tox.ini b/tox.ini
index f3a10fba..ca7b4bc6 100644
--- a/tox.ini
+++ b/tox.ini
@@ -34,9 +34,10 @@ commands =
[testenv:packaging]
deps =
- readme_renderer
+ twine
commands =
- python setup.py check -r -s
+ python setup.py bdist_wheel --universal
+ twine check dist/*
[travis]
python =